diff options
| author | Liguros - Gitlab CI/CD [master] <gitlab@liguros.net> | 2021-03-01 00:37:58 +0000 |
|---|---|---|
| committer | Liguros - Gitlab CI/CD [master] <gitlab@liguros.net> | 2021-03-01 00:37:58 +0000 |
| commit | 8ddb1a3d1229412a438971f82d37d518a0223726 (patch) | |
| tree | 83438b5ddb9d23a390f1a3fc505303d3d2223bf2 /sys-kernel | |
| parent | 9acab46e1a820daece7b2e631485c157ce2210ad (diff) | |
| download | baldeagleos-repo-21.1.5.tar.gz baldeagleos-repo-21.1.5.tar.xz baldeagleos-repo-21.1.5.zip | |
Adding metadatav21.1.5
Diffstat (limited to 'sys-kernel')
456 files changed, 984 insertions, 129130 deletions
diff --git a/sys-kernel/bliss-initramfs/metadata.xml b/sys-kernel/bliss-initramfs/metadata.xml index 7cb74c4691c2..f06501a4c5a8 100644 --- a/sys-kernel/bliss-initramfs/metadata.xml +++ b/sys-kernel/bliss-initramfs/metadata.xml @@ -1,8 +1,8 @@ -<?xml version='1.0' encoding='UTF-8'?> -<!DOCTYPE pkgmetadata SYSTEM "http://www.gentoo.org/dtd/metadata.dtd"> +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE pkgmetadata SYSTEM "https://liguros.gitlab.io/dtd/metadata.dtd"> <pkgmetadata> - <!--maintainer-needed--> - <upstream> - <remote-id type="github">fearedbliss/bliss-initramfs</remote-id> - </upstream> -</pkgmetadata> + <upstream> + <remote-id type="github">fearedbliss/bliss-initramfs</remote-id> + </upstream> + <origin>gentoo-staging</origin> +</pkgmetadata>
\ No newline at end of file diff --git a/sys-kernel/bliss-kernel-bin/metadata.xml b/sys-kernel/bliss-kernel-bin/metadata.xml index 5c3f9d281df0..14b68cc9360b 100644 --- a/sys-kernel/bliss-kernel-bin/metadata.xml +++ b/sys-kernel/bliss-kernel-bin/metadata.xml @@ -1,8 +1,9 @@ <?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE pkgmetadata SYSTEM "http://www.gentoo.org/dtd/metadata.dtd"> +<!DOCTYPE pkgmetadata SYSTEM "https://liguros.gitlab.io/dtd/metadata.dtd"> <pkgmetadata> - <!--maintainer-needed--> - <use> - <flag name='initramfs'>Build initramfs along with the kernel.</flag> - </use> -</pkgmetadata> + + <use> + <flag name="initramfs">Build initramfs along with the kernel.</flag> + </use> + <origin>gentoo-staging</origin> +</pkgmetadata>
\ No newline at end of file diff --git a/sys-kernel/cairn-sources/Manifest b/sys-kernel/cairn-sources/Manifest deleted file mode 100644 index c38c17082248..000000000000 --- a/sys-kernel/cairn-sources/Manifest +++ /dev/null @@ -1,298 +0,0 @@ -AUX 5.10.13/dtrace-patches/0001-ctf-generate-CTF-information-for-the-kernel.patch 245882 BLAKE2B a62e7987ad2e2102448920bb1d75fa489c2d960d3de458604acc6a1c35158f108dea038bceea63392931446ad5dbc8e0146b37a6973691adf746f693d6bdeb33 SHA512 f0289de6e00cadb2c4c38d5e7ae4ec5e8036f41bd0aa7313589ce3af6c7d9cff6cc916030a0bd61a6e2ddf4ebdc863a8550ed384b96c7847797ce57e2550c8c8 -AUX 5.10.13/dtrace-patches/0002-kallsyms-introduce-new-proc-kallmodsyms-including-bu.patch 32718 BLAKE2B bdf611b26c724c3a55e95a39df8eb2911f2fab4a95ea5a2163979a5ecab478d25b2b39b668b9e3b7d10ea7ca7269e12f58fb0ca2a7a3619db472b4f2f49370ce SHA512 1773efe326b6d70568eb17ee35f677ee1352a003c11faaf0a1e2ca30e23d4c73c644cb785074e0b6869c57d0a348c4ff65c5f179b2eed8597cf0840c19feb088 -AUX 5.10.13/dtrace-patches/0003-waitfd-new-syscall-implementing-waitpid-over-fds.patch 26905 BLAKE2B e40145dd7361ba37b5f9e63a0f70a5fb80df0a12471b61e6b2fbef0aa15fa90122bc248894ed936812b3fa8c7257182a142aa20dd8ce239bc081580a936156bc SHA512 f6af8f29855879373415cac02011074eb141a3c3f2e79732af127cf243d755e9ae0e1188cbcfac6d6bea9e648dbf74d9285b40154278eb9de8edabb49b05ddb3 -AUX 5.10.13/dtrace-patches/0004-dtrace-core-and-x86.patch 275923 BLAKE2B d45d18422ee9e7381fac40fcfb65cb16d799832df640f1297af004148afd7a36d2cce9ead51cf9db844085ab5e15e9767d27bf45a6df22f2eaa0d341f7da69bf SHA512 4438bcae2617d69eb8239d5614d811269d5b1dbaf7077e8ec1df4dd8b7c4e28b4bb9a11b17630243f8715db6229b371c9a1a201b97cc6047d33244332ffa64a0 -AUX 5.10.13/dtrace-patches/0005-dtrace-modular-components-and-x86-support.patch 484600 BLAKE2B 2dabade3a2e1c5b49c946c30768ed0d637a55b60a228ff025809ec7669761e0452168ebdc25717494a5d96deec21c7e2a28a04338ca63345df59724bb49e6776 SHA512 447e674de2a65f9b83ec250510d65d53bbeb5855068b597f4d6fb3e69105f578a1d74272574f945d3f8c86bddc364df66aea619251b367185eaffa2878e219ee -AUX 5.10.13/dtrace-patches/0006-dtrace-systrace-provider-core-components.patch 9861 BLAKE2B b0a5a80467126108bb5b61a8d70bd094dcce965a5e4a117b38c36650de9deb1241986f22ade6016e725b5907f1f7a828b9768529cac43b28daac2bca21844fca SHA512 70dfdbade9819c0fa8b2e2c1db496526835333113d38d8ae257588eef3bd6cbe94e306effdfa747013948784b56258a03a42bd2c8ffda9b3bd32a5bd184a0f0f -AUX 5.10.13/dtrace-patches/0007-dtrace-systrace-provider.patch 11199 BLAKE2B 3787cb9da781e4008a9754858e925a8626f858ae66528fec8a38366a3e4167a6037fb6760e91a3792e3cb49fe2c49c13af9ac8054a1f4ff9f44a32a5e32c45fd SHA512 f668e6c84d3ec901daaff993124e2a3da6ef101fa86eadc30214b02218c2e18742607c2f39a7eca0de674c4eb54c77e73ddd920637d6591e92c0d2c185570570 -AUX 5.10.13/dtrace-patches/0008-dtrace-sdt-provider-core-components.patch 101126 BLAKE2B 938a4c5bb38da112d84bce2e8a835b05dc34f6781e2a09f4c189c8a0b5e4a7ce73dccfb13505f1ce6bb17ae539e33663f041a5fcc1786d8c94e4b831f6abc5a1 SHA512 ba3bd0a073ec80c97c8f7789434191023b00722cc0fb2a57567efa8e101b2dc9829b70f991bf919ee395a6160bd144dfdabb60c2652ceebe0947b0ba73871d0b -AUX 5.10.13/dtrace-patches/0009-dtrace-sdt-provider-for-x86.patch 33276 BLAKE2B ab8e00705288255b68e8b23175d2e9dcb0180a12ac8a8a380372d38ce6a63c4cc1117e7d52a4833691258ff6cf8022160fd7910c5f59bd6cff30ba029172cbc0 SHA512 0aba8eae7e8a8087b9f6fee4f77647c7ad3824d568c0a4e4a69895d4480c79fd3170d603da42d5aee2fdb44c19fc5d3ca4d2a1d948cf75ce7878b2c357f1ad23 -AUX 5.10.13/dtrace-patches/0010-dtrace-profile-provider-and-test-probe-core-componen.patch 1426 BLAKE2B 852b0943e452a83860c5bfeb88db5dc6d52d3e700b81933646f6f4966f11b92907449c4621176f2d6d1c749d272bb208d64ddad381aab0abc03079c92224dfbf SHA512 b059a3645b4d754932ee79aabd2a2c86452fd809e9ac4e1f51b1be874d1beee2870ec276bc5bc6c857e1eb31e2a909abbfe47f77aaeb8c79c86857d5277228bb -AUX 5.10.13/dtrace-patches/0011-dtrace-profile-and-tick-providers-built-on-cyclics.patch 17675 BLAKE2B 6ea9ec19cd71da3016ddf99e0598f04f077b8ec41e189aa0a87d328765b903e6c194b5991d4ae407fa98efc372f693a914c71c817d27a7f75a81487c687f43f8 SHA512 6ad985c1b53f4fd01c1db2e07c4d861b81aedfbe4729e1367b00f56b80166caa28cce037a7be311bebc2bf3e39f540ee091c2a0a9277bf35b3e5ae3e73dd3600 -AUX 5.10.13/dtrace-patches/0012-dtrace-USDT-and-pid-provider-core-and-x86-components.patch 10977 BLAKE2B 5d50e4ff56a86c1be202b4563b77e140db0b2ce56b61d84c1c85ae8955d6ea5bab6aa30e5f1375e5c7258d259ae9436c033cb944c5dae56159f905969c9ef81b SHA512 139ecb4b2fe3f5f51a3af333dd7dded854df3c549ff265f946e2f191f93c23ae48394007dee32958f98ebb2135d3d72cffb01edf5cb2a43b466a7c4329aea290 -AUX 5.10.13/dtrace-patches/0013-dtrace-USDT-and-pid-providers.patch 73642 BLAKE2B 506b98a4c1e9958f8d8cf42b20cae4b6665f5443e0cf09bea542db09012713545203480331dd8fa23a537b568b82532cc0028c32c9633c0b20dc639f63ca6dde SHA512 199a2ddd12c72950cb6646f7ff1b43a91065536a5501cfe76179a786e2dab4b7bff5c4ed0df29e73e51d633949157d5bb12801544298ce13dbaed85d14e632af -AUX 5.10.13/dtrace-patches/0014-dtrace-function-boundary-tracing-FBT-core-and-x86-co.patch 54502 BLAKE2B 683ced4e432b1515a714d342e65bd155a02c79b5001ee627b3302a9b2b9c4654c0772ab08092f2c7f4b2628a6dcb2b1c23ada9aed2f7493a9776c351ad5fa6d7 SHA512 e51601fd80e9f59e987164cdae387b290c34b7a51b1fd98adc02bc9b821fc9f73e1ca9d7b2b5a6bb2127bce52e04455d9951b90823696efc3175abff57d6b57f -AUX 5.10.13/dtrace-patches/0015-dtrace-fbt-provider-modular-components.patch 19711 BLAKE2B ecdb0fd324de883585e4abe564204e8b67ba0934f4a39dfd3d32ccd3069de1875275414d69aa461199115000318fbf631c1585f147c6c07746df3c215e60e397 SHA512 ed1a0bcaa2e2514765fd66df99a7ab19df066d121e215fb0e0f16712823f1aaa47d3b60771160f206329c4bff6acbec568cc3921d142e286d965db6704d4d2b8 -AUX 5.10.13/dtrace-patches/0016-dtrace-arm-arm64-port.patch 75498 BLAKE2B b6cdd7a1e363746492250bf38b9bfb7e3f46c6a295db1b0d298bc6c4e9aedb73b62945a91d070643f9424b1adf447f271a05d3a0594202ead243fa66662402e3 SHA512 cbe9bcb6f1abaed9e7e0aa96bc8f4a7386cf27070868b0a4d75cb92e9c2adef96d7d5282cc8fb2cf5fbce81c7f472f072211ab59c0cf312188c54b0e5442b1bf -AUX 5.10.13/dtrace-patches/0017-dtrace-add-SDT-probes.patch 105896 BLAKE2B 2f18953f34af9d11ce240aec6f86a2a35b2efad0f68bc9940c5980788931099c66c9f00fc5f1901de7cbe31d932f34fd5a9dad73af41e593a44763f443eed832 SHA512 51345a53594beeeb3047685a8d50843610b3c9969660e2fc73b8d8ad8fbcb6aefec4cf50b1d72da2659ae36b2ae1669a8e6a0d96c77d2b625d1c35073c53dfd1 -AUX 5.10.13/dtrace-patches/0018-dtrace-add-sample-script-for-building-DTrace-on-Fedo.patch 8549 BLAKE2B 2b0ed98f3a95c5589b7cc143d6a95a302568da0c63019728071cb448f2e7963ec1797e8d6965b6730023b0171973f3d4ba6b7280b72424297944257542c82eef SHA512 3c04b5f9d1170cfdd13632693564a9c0205e662b2ad2d748f274e1572b32557ca7832e15e292a6cba135412b38aa6f0cb95c239f9149de6470ad5561653850cd -AUX 5.10.13/dtrace-patches/0019-locking-publicize-mutex_owner-and-mutex_owned-again.patch 2431 BLAKE2B 8ffcbf3b70c46fa21e9f1a03c4d2139b980df2bcb9704489d76666b5d2e72722415f04ff759fb2418ae502434050a7cafbdb6a7a36d1adca71a754af783a2ee5 SHA512 70307162146460093f9d9a1d39c0fa1275e38ef76f29f24675c505ac64f84d98f5308a826cd4cb9533fd023b63b0776ff55f6e714d350f4c96e7b0b1701fe4b7 -AUX 5.10.13/gentoo-patches/0000_README 3702 BLAKE2B cf545e5849b9beea0d24c8dac628bb1bcc651ac863a7f514b2c036aa3cdfd28285b2a0362941803fcc1dab00d97196bc64ced1ee15426336597d55e717e363ed SHA512 d9b9b54f6d9063697768c32301197da3fd1efcc7f71f24e2f688402b9539eb276651af157701a608b9f2346a044b12e6bfb3a3e3fe6b6ebea9ba608f5b6a7beb -AUX 5.10.13/gentoo-patches/1500_XATTR_USER_PREFIX.patch 2293 BLAKE2B c2bde13ef40e7066340afefe55454dc933ac3b65dda4dcf81d9958ba84d9531143e58c4d35151d912bfe21a43aaed35fd99571a769ca8e823fc0d99797a96f4b SHA512 3ed100909f9aed72836a3c712e45e0116cd3c4331961a76a27b867a7098d0df9458387b656c9ea01385c3c37585436e48168ac35666b0e46dca7da05e5e38a61 -AUX 5.10.13/gentoo-patches/1510_fs-enable-link-security-restrictions-by-default.patch 810 BLAKE2B bb749b365f37988253206ddff130651e1042af49a6c773ba6f93642d5927af9a9926eab278979e048c13d2ca683e726a5d0cd509de9e6177d59c85197051e230 SHA512 c97a3799a2d5e4da9c9dfe129756da629fba8183479b02ca82f9b6d9993f17a165a96bd35ac50eb25fb293785b9b529a95165b1a2eb79c05134bee8ccf22a5d3 -AUX 5.10.13/gentoo-patches/2000_BT-Check-key-sizes-only-if-Secure-Simple-Pairing-enabled.patch 1290 BLAKE2B 35f8f2a707da3bdb4df74844f72244dc6cb9fb0d41ac2034af61ce61c96e4bd472fb5bc5c687611356d06f3940e9f6669c80f4261165809592173bf5dac54b61 SHA512 dc47b18749d95a456f8bc47fd6a0618c286b646b38466c3d950dfbeb25adf3fc1a794e95552e4da1abb58e49f0bd841f7222e71c4d04cb0264ca23476ca9caef -AUX 5.10.13/gentoo-patches/2900_tmp513-Fix-build-issue-by-selecting-CONFIG_REG.patch 958 BLAKE2B 095d70ef085c6200b3ac69695339b8937e54b49c45acb7a741d0f471f66c1fe1bedf0b7df0951eff6ccd53ade10abcc66d5d2bca994e28a49d3e4296d7332e55 SHA512 4e637935c2f37cc18f347293e3c94b18f90e2caccca726304a95c4891257a5b2bb3093aee7a97571038b29c0c987cc60a9a80aefd0d4c9a063b33d102f03579e -AUX 5.10.13/gentoo-patches/2920_sign-file-patch-for-libressl.patch 565 BLAKE2B ea33143cebfccbc5fdeab46161ab28c8ed6dbe265b35454659ba87f09705ed80219e9a9e47f7fc3df51292a3a7656c7a6d633e24a37911c35e47d039da530ad5 SHA512 79eaf814d76402a445efc961666a7c7c74207e552b0cb32d93d5cb828da580f7dbe93509dc9f53321c7844663205a8dce4e518ba047e4c57fc55f5c3498088ec -AUX 5.10.13/gentoo-patches/4567_distro-Gentoo-Kconfig.patch 4784 BLAKE2B ccbb902ac828a26a69bda7f7eb7c69770bca7685ed5e58459e473b7a8ac0f396ac9f1aa1ee23a9248de22c5aebbfecf76930420b640cf6307a4d1e73bc9add0a SHA512 bf681566831b583537eda1df1db9c9d1b310cf54a974dcdc437c8da11b65cda423ac86a1a8ae56c84cfc947a6ad363adb25983e51933cf7acb494934c1ad3eb5 -AUX 5.10.13/gentoo-patches/5000_shiftfs-ubuntu-20.04.patch 55494 BLAKE2B 5c56cb45b70a340d6eb65140f3772f3c4a26e30811645d471d0db7a389c813edbfe6f46ed2fb5fa8c96596c9486c1040948d3074b4fc5ebdc8080c4b02b0992b SHA512 e832d44d4a450c45eb7a517d6cd849258985aed08349d18ea21cf4d1eb37dcbac9153f50ca8b910955bfe64169298c631a7ec7857e9235bbce0167d97d69e55b -AUX 5.10.13/hardened-patches/0001-make-DEFAULT_MMAP_MIN_ADDR-match-LSM_MMAP_MIN_ADDR.patch 840 BLAKE2B 9740839753747aac0851874597e83390d9415bbb2b2d2eb5e1d03449849817d25126d37bac0ea64ef796457ded20e4913d57f43c4adbeb06a9019a732b899092 SHA512 7d28c8d57da9ee854a139fd6a83603311e2798e11865017d4a2a0950f21f1d3312b7252e7c2c48b5112529fbc80713098d2fbb4bd0a63b2168f67d127f6eeb57 -AUX 5.10.13/hardened-patches/0002-enable-HARDENED_USERCOPY-by-default.patch 790 BLAKE2B 16134839ab373cae29238fd8fe909bdd4c90d1c49054962e9c281de155a4d8e4464926c96c717ecb4bb0dc35c703fff078e307f0a5acb3aab4992bf4bfd76c09 SHA512 028ed1e01bccc632adb08c2e59322ea3d22dca3d911e8601cdf4a5252b88f3b8243ff91df929a37317bfacd26d26225ad9f463585e5d5f576777717ad4d0055a -AUX 5.10.13/hardened-patches/0003-disable-HARDENED_USERCOPY_FALLBACK-by-default.patch 768 BLAKE2B f03d98ce300492e36abd73a4921e0871d455b894f65d62de7f728490d9630d9b3ea7a3d53e386fcbcf373196eaf0a569d9c3dd8592d966b3a39fba38536f152d SHA512 b95aa576e8512cf3e0b9c9196d66e7689f9275b4c3c3e176f37ea1de66da188c29e9196f34fe9e9cfebd97fddb7b49a5804e2df2dad0a65595420461aaf2e658 -AUX 5.10.13/hardened-patches/0004-enable-SECURITY_DMESG_RESTRICT-by-default.patch 763 BLAKE2B d4b42a83da68f06395fafd3740d08bb146245aee34b85a1a9314f49baff61710c75d4e34715981235d2a4e917a4d328d197119c05a1a23ee269e67ed099e3a7a SHA512 b2006a32d4ef359d06568326e6a82c3420bb4d466676ade05a60ae1ece39b3eb128ca953bb61e8e9e95eb76b39a37d9205440f850012068703cfb71d44cf9018 -AUX 5.10.13/hardened-patches/0005-set-kptr_restrict-2-by-default.patch 791 BLAKE2B 8a94466a420466de93a38784520d9e0223223468ff1dc0e1e434d1d42efae8ec6fb38a671cacd399fde6a00079137ed1490dbeb34e1ce1332e2d6c6efffdfe82 SHA512 efe5da03926403eaf35f65a4c9b8b59c6569199a4f3eb95ceac48cfd8c6e701d42d704d53f3993ebb65cfe7cb3bfe37899dfeab81d4dc97ef121c49a47c28dab -AUX 5.10.13/hardened-patches/0006-enable-DEBUG_LIST-by-default.patch 743 BLAKE2B 6f850632b28bed969f046eb6a8d338afcb028413ff54a1a1da7b13ac9363fa060ddd4ddb3fb65587dd62a7d480b261f7c1f2d0f3bf8cdd3e84ef16aeac9b98b3 SHA512 35811cc68afd7402fde62fbdc6597266a90d1c67f3de6d01eb38ed7136357a9aa26e37d64597763836d9942712e90b0f1be2894601175253f7a0225e3c540dea -AUX 5.10.13/hardened-patches/0007-enable-BUG_ON_DATA_CORRUPTION-by-default.patch 792 BLAKE2B 05183b3b00d234b560f7ed4cc577f0fc27c5bc86664beeb1b12c4dbc4631dfab08e866f2c0eb5f137f1ead38568acbb4a07adefc306efb97c8445106df8bf451 SHA512 6e91f5c113ca729e77e57d6f0629073303947905c3a00df6fed6307f3fc51670007f724f038ef427ec998975ea9857159d21e0c053522f3ee7c453b4b1b2f3a3 -AUX 5.10.13/hardened-patches/0008-enable-ARM64_SW_TTBR0_PAN-by-default.patch 732 BLAKE2B 0a91552dc6675c0359b8bfb5d6cb64d6281531ce687361b3c4101c67caf208f042a5be9f35d73f594b516db8de756d2acfeba71dcc1ee50f5602893918fadfcb SHA512 ed077f3f7d06112508de3d8669af45a1266a3c95e2c0a3557d4b9a1f7b623ef3f5b1627d13851ab2ef8c131f0f69321238f01822cff11877c04b97ade8ade17a -AUX 5.10.13/hardened-patches/0009-arm64-enable-RANDOMIZE_BASE-by-default.patch 736 BLAKE2B 0e2a0a4972db7f5285ebd6e44d03cac6c393fe5ffcc05c5047d01ee17982981057e9389b13387ed217422e3be4a693bbb2d42c4005f83747b8fcf762d26260a0 SHA512 09f7e9f38664b68d2273859bd04209634964d190eb3061a7d19664470fa6046ec3516eec33b498bcc494369ad565cbca0ef274b0976576c14ea3b01f74c2c4a6 -AUX 5.10.13/hardened-patches/0010-enable-SLAB_FREELIST_RANDOM-by-default.patch 745 BLAKE2B 11bc8611d78e330ec3a6c90a6e1b4bdd60b8898bebbca2125980d666fddcd2678303485595c1a2459abb692ec1552cc36fe16c06e2bfc3f5a0b0eab39de7b51f SHA512 ccd814cae6a113b166b7651aa7d2f5165127656fb44ac85457fde9064648040b0b67d78f352802e3cc58a939096595ceae14012080f13cbd284d838bb753402d -AUX 5.10.13/hardened-patches/0011-enable-SLAB_FREELIST_HARDENED-by-default.patch 702 BLAKE2B 02844156366aa67c6bcddb01eabc24547bd31d400e3d553e47d8c0006ae19a8a48bd5518194a95a6c5ac7ff5a59da08ac7ef1382c620e8e5d4c8987ba4ee2e38 SHA512 3b1611a3fa6def95fa5670e305027825097ce5a9fd5282e8944b25adf87c6fa5678213c513ca06bbe13d87de65ed7ef3f29ef2c7b6ab0000b583c9bedef2f585 -AUX 5.10.13/hardened-patches/0012-disable-SLAB_MERGE_DEFAULT-by-default.patch 654 BLAKE2B 6d635e574ebcb81c81f4cb26df07c2561fede01136fe9dbf00f1dab6a5c31def57e68c4b3094f75cf45652450b3c4f21cdce201481e27c8dfaeac411f2ccc506 SHA512 4f499329f93b9a8e0955d19f4b37b19024365cd198c09a5de950543630afdd5c68926eca13cd779a60c7b2dc5119434449680d5a75d7ce2a7dbb9418cc733b8d -AUX 5.10.13/hardened-patches/0013-enable-FORTIFY_SOURCE-by-default.patch 807 BLAKE2B ad40e70bb9f0ff40e10d7f49062c9cb29b3baaddd7568b641e4ecfa9169fc13cc83cbb85ae2d89cfec471a96f7337e2dd31138f987293ff749148801363ec094 SHA512 63e79f3702529c296f5622db2186a22333ae30d3810311d16f791df39cb83eb25a158cd1416927e2ae93333d6388697cbf8b16f08bef2f5a70adbd32eeb9e0af -AUX 5.10.13/hardened-patches/0014-enable-PANIC_ON_OOPS-by-default.patch 966 BLAKE2B c59fd4cc939c8a8596f97dc580c0788379981be28b8b9bc2f4879223143c2ac1898df21f033c3fc34840ff1bbbb92beab1716225b0820d56c7a72b883f5995d7 SHA512 35b67fcd2061aa804154b3bfade833209425ae42df75dc4a763c43c8c636b5d52cf3d2be0c2c410391c6214e89426af783d1b2f1bdc127d2b6c26a61a69e9442 -AUX 5.10.13/hardened-patches/0015-stop-hiding-SLUB_DEBUG-behind-EXPERT.patch 761 BLAKE2B e2893f624213216d853d891260971bca90d776871c8bde6ef3da97f48a52a740d217bfe4fc2a2b5d5756238efa1401a18cad063e8d040e892caf7594d95aaa80 SHA512 90778e1d01a4ccb20871d99b4a2c06ddac1e5a20c41a03e92cca4c651025024552c3fa4951994a29f1efee1e4f966245dcc55d63e21934e2dd4c11aca529b4a0 -AUX 5.10.13/hardened-patches/0016-stop-hiding-X86_16BIT-behind-EXPERT.patch 666 BLAKE2B ccd226cbc0262389477a0a74dbd6eda129a10500ca87d12f0d5a6b10ab8f09dffdaafd8c7389ff4033407f3ee101400f9dd12677330619c08c073be475b4bb16 SHA512 17322c22dd373055345c117c5ddcccf8be3de05ac3ff44a8b57c137cb9b0e6c94e81b44efb9fd8889083495da219fdeab2992ca5bffe0fd2957d493abb1aa4c8 -AUX 5.10.13/hardened-patches/0017-disable-X86_16BIT-by-default.patch 678 BLAKE2B 7f955ba8bada00ec5f4733d68a70e66fb363eaa1f416b74bdbcf3bb93bcdf9225c8584a02683d6d6a19f4282b4e6f54473418711b8393f543288f0bfa0bac507 SHA512 cf8c501b8cb576c243b3143f2c9abf24973d684e2f7f99277e1e923d6a01b54ee986d30c1abddc8ec758a7fcfb843436cb092145f506b4c0218775f8fde2ad55 -AUX 5.10.13/hardened-patches/0018-stop-hiding-MODIFY_LDT_SYSCALL-behind-EXPERT.patch 754 BLAKE2B bc720fa0bb3d620870cc387343adc8584a9e4c70b971637d4d79dafeb3c5c79be143ac6eef5c38a022029090e5294467199e7d6bc6bcc98f16e66d0bfa57f12e SHA512 77b2e26a85dfb72aa7fef8029f0dbdc1ddd514016cea0bc2dd1022ad69c7586505273bc8081a3972f8853b3dd8e93363bc516535c6c19e769ff9f9942c1abb8e -AUX 5.10.13/hardened-patches/0019-disable-MODIFY_LDT_SYSCALL-by-default.patch 802 BLAKE2B a2811c4ace54206b4e89cefc1d3c8542b575d4742853718da9003b278ef3a8783cc2a5b6e24abdb6466bfb0b8e2264a35be060ed2f5be424145714949987054a SHA512 54f92e5a6ce513f8a6d3181721f064f06389fc3dad50a07e439c7e97a728bc84a4b5b0f60124ed0b66b5c79251438ce35471f0cfb33ab154d208a66a29bed9e8 -AUX 5.10.13/hardened-patches/0020-set-LEGACY_VSYSCALL_NONE-by-default.patch 765 BLAKE2B 39ea1e7339515ce36dba14e0ec7e1982d74a23cb020521fc5aa2598c64525726095631dbf361128f3493e1d6bf853022d832e01f47a70e41e91ab175e8a74b99 SHA512 389900f39aa2f93a72dc43cafff54039d0f85dd65dba009421d69e31fa85e8d2389c9e233d66964989b4de1d6db8926a7c8e4849c06890073d8b4148cba1a34e -AUX 5.10.13/hardened-patches/0021-stop-hiding-AIO-behind-EXPERT.patch 691 BLAKE2B 86b3c14c8971f30138754f385a8e743ea532aab3ae317ee67b13ee1826058965ae11cfe748ced6ea892dfefad9000e5aac24eb3a4d761cbe890fb928836791aa SHA512 9c02566c735a9efb2d2d0679dbefe580c65c003c685ffb489b19e91ee031152e79a6880fec1afe02c4b7890d0f7fca94ce0175326561e1e2a387a829ce041da0 -AUX 5.10.13/hardened-patches/0022-disable-AIO-by-default.patch 631 BLAKE2B 02f409c9ae1dd53cf82086b7c8789443e59b08503c439ad2c019c55eda2da6926c77d29cd64c95fd58ede64e30d92dbc0f583e0101a579eee8dbaf459fb89f2e SHA512 214bf009dab05cdb4db3f4f2e45e2992d29c363d4f95721d69a87720d894ec5acab19beff0b92950b501f51334daadc61ded0116d84553a147ca0b41664e4252 -AUX 5.10.13/hardened-patches/0023-remove-SYSVIPC-from-arm64-x86_64-defconfigs.patch 962 BLAKE2B e6bb32327a83f9fcefcc1a75485f543d1801b812ac43b9dce3c91a4c4226f254a4feb815bdd3408d3d8a09d52c565e99fb7d14407277de784ec2d5c4f5bf1136 SHA512 b7f7c7e0728f60a1472f1782795b8831f24bb7d3aa8e340d97e09d92f14a2aae524a568fbc46ad84af2c2263ad87e643aa12184621aa064e141aa45ddcbd7852 -AUX 5.10.13/hardened-patches/0024-disable-DEVPORT-by-default.patch 695 BLAKE2B 709dd45f36f1a2032463431de19cefed5aed685aad94da287d156bee75a1ff544946d210aea6de8faee1a24be65c18e51e8b64346a45aab94a44de7e73033a4b SHA512 e494ce4d276d31b97a169624141b4bbb5c30f622e6d864aabc71b16a3c7e1da89438c75ca73750d3788981e4322c667372e8712a04d62e42df9e186f585b289b -AUX 5.10.13/hardened-patches/0025-disable-PROC_VMCORE-by-default.patch 613 BLAKE2B a7c1fa67265f9cbeed1da5c0a8504fb91fff3962c81af2e8c25eeeb1391e9b729d7ac7beb03a30ab9b05c08d0524c392552092e1d73ee51d298bcd7b16f02557 SHA512 1a64ff3dfe94f97fe468cc6103925d4b2999b660af6e1d72f6b569c3dcf67b4c79a2fa7f1961dbad6d4cfa70ad8d8bf1aa6b781afebee7580487a2420cb8cd93 -AUX 5.10.13/hardened-patches/0026-disable-NFS_DEBUG-by-default.patch 598 BLAKE2B d6555576fb217b84608f2e83ab4ecc6eeb8b0f88267d7cc4d84d993f903087eeacf2aa1dd84eca02c7b55755ee2535697f5dadd3a9529108ff8d0834e3f16029 SHA512 a605e3fbcd2eaff7dd9cbfee7de909891638555dc663715b1e4d20ae4180e12010537037b5f06ebf88378cbf2b50bee4fc5e3ebd6419bc13978f06c22b30d781 -AUX 5.10.13/hardened-patches/0027-enable-DEBUG_WX-by-default.patch 653 BLAKE2B d093280754f3490512d4b3884471f409428af26e70f766ad33312bb80f4b6567b24be20249d5655d670929528d909b774c91f21bcce62a8c992c02a1120d678f SHA512 f4b485adb459700c2c7f3013f73e5975d3d74e82f5e7f205b3689d111fffc1dc3439170a4e0049cd58b5722b5c4ca693d9481ea5981dbab6e8b2083709444850 -AUX 5.10.13/hardened-patches/0028-disable-LEGACY_PTYS-by-default.patch 683 BLAKE2B c23ff7faa6dff5af4c8ba1811aec96541f2236e72860c41afad0c4abce5221b4b919878e2026ab05a2a813fc2ef0589fee70acc8b683611807c481518102347b SHA512 4fc9188343ab0a0e99ec5a9a4d25844fc5ec564a273df4011a29bfb16431ab2ebe5120ab86ced1dd6499abdf4090c63c373b54d3edefdb2bdea4293770cbd6aa -AUX 5.10.13/hardened-patches/0029-disable-DEVMEM-by-default.patch 662 BLAKE2B fc36e504f1bfa5cfa763e8e446ba45022af596129607566fed6ed7f4e671614801a468d65f3e1a3015f839b0927ad4de6fa2053e0c6f63ac04b2205df8d42a4c SHA512 d4100d1c11e7d1bf9dcab25e62ea5b17374ae1741da15f7dbc74c3af2b98292ac481ba7d1cfaf301dc77b5513124c9cae9d5da4c74695de467f047bd2619b3a3 -AUX 5.10.13/hardened-patches/0030-enable-IO_STRICT_DEVMEM-by-default.patch 719 BLAKE2B c20a5b170e5fd5148ee776b45ea84c7a742f7b71dd234ae03e86461262e552af3ef4ce32f951a862784317bf36dea3fa421a2db1e2ee7adfa942e2f2cd6f6f25 SHA512 395b5508e343bc6a7a92efed2ee417ea644e5f4d279ba948cb0a95c7a19842989df31f3fb83d1bf1700cf0f5d1155729dfcd997174da16afcb680d0fbc59da5d -AUX 5.10.13/hardened-patches/0031-disable-COMPAT_BRK-by-default.patch 652 BLAKE2B a11063b2f8222b29520dee9bfa4431ba6aef8ff11c81cb9f221a920716bac29125a6dc57032b3490ddc3a34cbe20450f25e11de9ab27b1e4743807b13f638fd3 SHA512 a317448879ec3cafece4c6aa27a6c5631142a8e0d51236e3e9d101cd6bb0961627ef9c9b86c5c6a2acbc7c42277e713ffe6455c171aa4556971cc3d48f4b04a6 -AUX 5.10.13/hardened-patches/0032-use-maximum-supported-mmap-rnd-entropy-by-default.patch 1397 BLAKE2B 0e279151811d14d35230858acaf0fe2be92ca344209b77b1177ad1df6dcdded7d784504216a038c74d9cc035adc2aae1d0594b18a179b96f013c539931dca9dd SHA512 06f2d0a2fd139bb5861304f8125692ac2e81673dc6ce2d15e695c7628dedc2e9a1d29c73864934fdea0cfea61d5ddc3b58762b5bd480c15dfd8d049f2d18b642 -AUX 5.10.13/hardened-patches/0033-enable-protected_-symlinks-hardlinks-by-default.patch 818 BLAKE2B 77018a473bc85f85250f835e416f532191c06591d3d5c6044c5cb0489da831ce40a5f4f7427660b27977058296203189a316f367f943326c498d8432a76f72b4 SHA512 acc95ebd557767d98ec055df29f73097fe3129929133dd8955de9a61f988cc5edd621ef21096adeba7c706ff133b438d6d8e07158a29d656b03550e1a96f79c8 -AUX 5.10.13/hardened-patches/0034-enable-SECURITY-by-default.patch 646 BLAKE2B 2c6feb548818edbecd84b5768f8420b486040bd6197cc52b2d2486ba841b088171195124cdec25583d185eb6e8fb344a5362a350a4ce059ec79623423cfd0f6f SHA512 09100fb65bb6832e1c5f0e3aecca2dd4c34ec44f545d7ccd8a38564138575362e9401a8fe73091e5149b2dc0ba8d34bec0f15a164e6686ad8e6248d96a85ff35 -AUX 5.10.13/hardened-patches/0035-enable-SECURITY_YAMA-by-default.patch 706 BLAKE2B 1639d21f203e71e6726b23f9f4bb7ef41b4cad6a75b1707a8670d4dff8a494ebbc1847a18b62877abed26b5858e2ddffc96369f3ce741129927d4560658f8e97 SHA512 81109e2f2d366f8183ddac40de91060377a50e67d38df83334ddceedd2f389cc75d537ffc7ad26dd9e3bf85543f3bb0d7f931c31a3880dfb0b5ee1201a26ff98 -AUX 5.10.13/hardened-patches/0036-enable-SECURITY_NETWORK-by-default.patch 685 BLAKE2B cbba761799a71262a5e65caa5d791082ed8476ffbb4ae02bb00e8710cb53776fc15ede8c5e3774f020e7264e5764b900c0bc5b9ff2ab6614e52bbc0f310feae0 SHA512 c5e68b6bb0d5d3e78fdbd1d28414d2789568e702a6684c4f8519672e5d50e3175b0a2bed53b2f6e7458c6f40fef8ba95da493715850730131c97ce3f1c128417 -AUX 5.10.13/hardened-patches/0037-enable-AUDIT-by-default.patch 628 BLAKE2B 7bbf1ad22af9b66427c5dc1a86a5109114a5c35fb53e837a37338bd53cca091df2c334b8ec98471ae0d390d4f9bfb2df6111054076bbcd46787f089a00b1e56a SHA512 4133ddaf4d6e6021f3002813619d2a048deb8a41d97a29b1dfec3af7a50e3372a36a8e37b67421c3ab197fb74795bb3af4ccc1dd615180753700380640bf4afd -AUX 5.10.13/hardened-patches/0038-enable-SECURITY_SELINUX-by-default.patch 784 BLAKE2B e4680319c1751da3beff6bd7fda39bd13ccc12fd27fa41566a5a3eb28a1154dc57b2c9070a82c79899a5f31a4d6ec14cf458b595b0c3791e9589044824b9cf2b SHA512 3ae00e48dd399c02c484150a1689dbb3d79112d4d51bf7de79ef5ee77f5727a45510cc29514db705ce6463bda58237e0c470f817956c9e9a9550805cdc1c781a -AUX 5.10.13/hardened-patches/0039-enable-SYN_COOKIES-by-default.patch 666 BLAKE2B 2e43652288dee79e8eaa18abfb8065bbf2123dbc604d43b94e7b24e05c865db41347184fb306f2a06459eb06105c4496f167a939678c46f1bfbbee983f9faa09 SHA512 5919f0055d077b651a6f7bf4324d5b55318dd1399036575ea59d0170d8b62a57e79afb8a97d59a809c8b26f821ab8dbc9e41baf409810768cbbe2b813dd92dd0 -AUX 5.10.13/hardened-patches/0040-enable-INIT_ON_ALLOC_DEFAULT_ON-by-default.patch 785 BLAKE2B e37d5653fba0ceadc4be64cb598d76e91082f612e9d0b2e3bdc2c059aff10f347e98c23aa7d1d0d51a8f888045466e7ee741385542dfff301315f34fb639465f SHA512 14712f6209062aa2211e2903df3e4623d498690b72222eddd8e2901550adee31d707f3c62936a9aef678e866f033f959b5ada29c1b6fc42033413514406f4aa6 -AUX 5.10.13/hardened-patches/0041-enable-INIT_ON_FREE_DEFAULT_ON-by-default.patch 774 BLAKE2B 7ebfed15a2749359241fe846569dfecf25433a5503a0e68cf501a29d2f09f71a6e3c36a3f6636f7dc3b3d540c648c3373de41f1601fbca20ad31c323c769f31a SHA512 e1c7b084ed56e1001fed6723d76d4ac3fe9447a93462f6bbd39e575311fb6ce4aaa94a7ec52663c94b3416f4d42b13ba5c372caf3eed0a96cf00491bf52c07d4 -AUX 5.10.13/hardened-patches/0042-kconfig-select-DEBUG_FS_ALLOW_NONE-by-default-if-DEB.patch 827 BLAKE2B df605131e42444a5b2c54c2402b0f5b8d5355abc2e38567d40005b7eae53fa7b0949c4d8b2bb4e4cefc4f53c265143013b77dba2a2ae7c0c828377158e39734d SHA512 22aab6f0bcb8dcc356ecd6897b61202ef0b40af4dcda150614d54ee25d33bb3d3eefa19a0d5e15217213c824e00922314aa853a42a513da6756282993fae12de -AUX 5.10.13/hardened-patches/0043-stop-hiding-SYSFS_SYSCALL-behind-EXPERT.patch 705 BLAKE2B fe7c98fb16258c0fc34f74a8d653b5c76ccfbb4be546ab501a70736f4cf09a06644676f209573fd64a065c82948aafa0cea5650bd81d4f3dc13ffd9e2aff2320 SHA512 4b3c143165d96c0a19fe221a15b82bc7f04da6bd1186d5367d484110e93c621df57a2b04da0c59ba39939452aec309cefc16d3fefafce7b5fc9d2b0a67eff5fe -AUX 5.10.13/hardened-patches/0044-disable-SYSFS_SYSCALL-by-default.patch 835 BLAKE2B 957133513de18e23a7af92c5703e103831c2ba3234087103080458ec5eabab3f013bf93d95df47b3a9dd2c6cf02dc8959fe921e346352606a66275f440616572 SHA512 61179e8238e3a0586a089130c1e690b300039e80132cdbfa5e61a9c74072aa543f2687ff90f3da6fe5ea99f538b228138deb1f09b42aab6545db1985f97e9f52 -AUX 5.10.13/hardened-patches/0045-stop-hiding-UID16-behind-EXPERT.patch 679 BLAKE2B e220f96afc064e3e184984653a3ca2d1b33394d53219f4fd0a1eb8caedab9de961981128d3afd3de1deb1ba061b07ac7ece8f41c7f034230275fd6bba966b4c5 SHA512 8070f011542ea47b680e53e03390db26849a161c24b479a707ef9188823598d61821f3cd6da28db846fe461f3c147fd86fce36d701b77cc21be2e9476a7802af -AUX 5.10.13/hardened-patches/0046-disable-UID16-by-default.patch 605 BLAKE2B a9d034bbb206fa92eb489a7ad07ce11ff08433f632b25380243abbedebf18c9f22b53e621e19e19f4d00261270022e78585d457faeb1ee3e5af1372273439d55 SHA512 16b51b2c2c8c645cc22f1702d902741893903ed5a5b91ead757f4db9a43aab3cb2799f6f802eff4399125ed25d9593407ed967680e028d94f44da179a223acfd -AUX 5.10.13/hardened-patches/0047-add-__read_only-for-non-init-related-usage.patch 697 BLAKE2B 58daa57dfc54a5c9effc7848c5cc75e14652a8f32969396a9b9046d115a28b65e204bb425b275d56b073c33a567274c4637f1e43c1ed025884c0084ee587e81f SHA512 eaf3f955e398aff305f94e5fcfa55d86e675d9e7f09d6d32f80b19cb406c068fa5b5941ff5c5f1f27233430850a4554ae03fc1901495546d725a477bab8f2e5c -AUX 5.10.13/hardened-patches/0048-make-sysctl-constants-read-only.patch 3971 BLAKE2B 8273e7d2ce05d26e5be0e8cd3e56bc469a2746d9fbdcf5f92a659b6b157e8007b37817db9c01fa91c43ebc6656b6cee89eb72924a8eb67c2044e2d153798a9aa SHA512 80b6f51a5b732e9d2f927e483ea27d9f8a8766925e939c5c39fa5a7fe4eeaf1cf7ff8797d29ffbfeb800d0f468e3753411cb6eff83ec3ebb54d3aef1cb3b0186 -AUX 5.10.13/hardened-patches/0049-mark-kernel_set_to_readonly-as-__ro_after_init.patch 2089 BLAKE2B 49dbb022d028007b769bd1de0536ab1ded05c875c9d4102384cffb06c3eb6661a53efe4328a055c711f804ecd56ef4088664a9b22c1800172d395cd685f7c649 SHA512 4589cf5184de1901b21a89950ad2b810f9d9e361ebca7e7285b4a49eaafde1cf972b292b0196f0dfb5ec2c69b3c5e9e0f5be2d35db5101756f6f9a70fb18633f -AUX 5.10.13/hardened-patches/0050-Revert-mark-kernel_set_to_readonly-as-__ro_after_ini.patch 2171 BLAKE2B 7f0244b2e73496f5a816762dbf643a9a9dcb7aac1ee9c891b0f8a1c9f543dd829ef92cb285abc444bc1ef14fa6b99f2f31847dec5ae9076d552fc2a79c775f7a SHA512 db18a51626138940f867e4e9309e6d0dfb7a6d461f08143e3c199f8174417f2d5bc0723d2ae9693df5df2e8f67693073311f9a29a8c568cf1dee7052e093182e -AUX 5.10.13/hardened-patches/0051-mark-slub-runtime-configuration-as-__ro_after_init.patch 2004 BLAKE2B a260a771772e51aaf7236ffbdeb09637937b824153285a539d2b54a0a603142416263f4836ab4b6f7d8fa18c0fa08942f0907d6260d8728663214b012e61123b SHA512 3feb0c2f0763ee85be2ce6ba5748b8a43c2df616f89e6cdfd590a5bdaa961010f15507704335a6147dac0c391adbb7b2f411d848631b1f9f602995d97ca5c0cf -AUX 5.10.13/hardened-patches/0052-add-__ro_after_init-to-slab_nomerge-and-slab_state.patch 1165 BLAKE2B 33d7b9ab6e52f2d45e6eb3ba106bd87400f5a13f52063dcaa9dcfa7ae0917c7996f3c16592e89cca1cdc9d675ecd8641894f44edd5e17a569b36c0fe7b65de02 SHA512 81316345449f35512b8085b57e4c82b9efd0068a2f8c9ba7a7515e780ea6147a338bbb813f1281714cc607dc7e218e0b1ef8a93d6cba86ba2748c712ddf3e5c4 -AUX 5.10.13/hardened-patches/0053-mark-kmem_cache-as-__ro_after_init.patch 709 BLAKE2B 1957f637fc75bda1a4f495172c5a7fb115438846b0d3425736e751a3a7905e425d069ac6ede8568d435ea7071fa8795b969191549139f8540a987390b0c5027c SHA512 79eb682165482d3e4e4041e4fa3b8883de633f582482bdf039877fb67cb1c982f68bc485afaa47da6d3dfc4c0ea0fc29e98012326ec1db3a98676135bd326a59 -AUX 5.10.13/hardened-patches/0054-mark-__supported_pte_mask-as-__ro_after_init.patch 1954 BLAKE2B 0d727a9002adce44bddff512e74897e782223ec70073897b23319522bca8c1c7d482203cbd27fdac89e4ce7c1787f274a2c250c137441ab4582068a01850455c SHA512 904895c292d2b08b94215dae9551040ab96f44d126773760eb7a6a9cfad75d1c172b9d4b75153e0c5913fa512cc944bd0ee227b966550faec254a713f2b03e38 -AUX 5.10.13/hardened-patches/0055-mark-kobj_ns_type_register-as-only-used-for-init.patch 1663 BLAKE2B 78e0e5017b2b6f2d581ffcfd0a7c34b416ac9d68812c7f63f5f124e66051c48f081f2f6296b9b3a43d006702eec594f68a7910ca5de751da7cdb63af9c987fa9 SHA512 98be1eafa7c371e6eacbd16c2519e6c501ca728eb36c99afc7b3783fe91f1337d320f5b251f50e6fab4515e7d0fb716fe7dea95a36ccdcbcb06b2fcabf4eeec8 -AUX 5.10.13/hardened-patches/0056-mark-open_softirq-as-only-used-for-init.patch 1272 BLAKE2B 7279e9c96877a43341a81611f1bcd7a3a0ec5d09da4656fcbf97018729c0f67f5cc47c357568d38f609b149895bad6794a498f731f1498f4a61d14f7365a4823 SHA512 525cca315ec2aeba731a0cf4e59e8bc35d361c7fc1b8d8e9f670cd4c7699016d5d25fe39356f11cc7a6a989784c155503f89037f000553ed70a8b3bd6198e388 -AUX 5.10.13/hardened-patches/0057-remove-unused-softirq_action-callback-parameter.patch 7357 BLAKE2B 8c14093958ee78b194b049ad811f6ef79146d9355f28e2cd865248e3edcaddca4084711da1a37fb2a52e75b8bd9c9daa302778190c7a0bc82cda10651d5ce985 SHA512 b56bc3db68517329bb05b785908d037fa1b9e47c24680cb446717fd29479f56963338b56bdfa440bf79af38d22df75edb900b0bf32e16d96bd35a1a75bdf14a9 -AUX 5.10.13/hardened-patches/0058-mark-softirq_vec-as-__ro_after_init.patch 871 BLAKE2B ff8c249b2fbf303654b695867bb1585b106aaecd36aa13439b1d689de58515428379b06593e594d523e5c4b7aa03875d3a243921d76ba150e4fed464b8c3a149 SHA512 78fab67f6fd40d679bd49b903cb23f8c8b41b92d9fc95f9a214bd46cecc6c11be225c71733c4c4aaf75fb0062821d58df17d08e39d2b273cebed01eafa6194e1 -AUX 5.10.13/hardened-patches/0059-mm-slab-trigger-BUG-if-requested-object-is-not-a-sla.patch 947 BLAKE2B 785073b1a53cee070cbab2e3de4f88199ca7a19b066592836f982a7135c359f25f02fb18e30bf5a9f4ade95bb47803253449a0fd1742ad869bcf39225d174a03 SHA512 9cc3b9ee7d7c204c26b219ff857c53b9035a68761b49ddfc66c0dad8a2a924516cedbb3606c018145fa9140eb18ea12150d9ff66c493189348aa97a83ff263dd -AUX 5.10.13/hardened-patches/0060-bug-on-kmem_cache_free-with-the-wrong-cache.patch 1180 BLAKE2B 60b981b2221ea72ee33559869c6c902093031d584f714e14f7e2d0df032bdac286c246af66dd746b62e6d744f15cbfc78273bbad122c57329cb9f9774665287e SHA512 0985b57de96b96db9623cd25c1a7a0b93189cfc0b4f3945de30d7daf2be6ff8795d151a6041771c0a659ff49edeb32ff57c3250179d55384482e83670afb4b58 -AUX 5.10.13/hardened-patches/0061-bug-on-PageSlab-PageCompound-in-ksize.patch 788 BLAKE2B 73d61d2006e643a563e0a245e51134e19ab8cb64c987d49ef2550c6f02d2e2f2c34fdea4bbd0f1b3c548c2aa50ec014e3ed9ccbd1c58458345f1ba0a20707d22 SHA512 afe8131acfdf4651557d61c40e6a77331fa5bc9a8495661af498e2956180af8185f477b71996397517607eb7621668de67c8e19e37f0232471801a536866a88e -AUX 5.10.13/hardened-patches/0062-mm-add-support-for-verifying-page-sanitization.patch 2256 BLAKE2B 076757e10877845dc20c1c9f2835696344481b3eb6b7b0d8296b76cb7d84adc913bab72b46ad0a7e698aca2ce26bd3d9805568bd7bce1d9194eac737adfc95ce SHA512 4e6399df0a4c395c110cb3f0b32c6e2531782ee878c18327a6ff7bfb90e9a3aa7a79c131f035337836b19a1b1168a925aa87f662c6cc8ade0ab95932c8d327d9 -AUX 5.10.13/hardened-patches/0063-slub-Extend-init_on_free-to-slab-caches-with-constru.patch 2454 BLAKE2B c575e589c071913a15e14e07f82af6eee6c7fed4adde18ae2597fb60e80a53bce19b62be491da3fbb52adc787c492c605fbb868856e868710e270e97a9510450 SHA512 2300a77b709e34135da4fdee510357b38681b09755e796113f5f208ad317e83d7b019ba3d057fea8447dd9311e0c605d3d38af77d4f04a5e2f85ba1969a3b155 -AUX 5.10.13/hardened-patches/0064-slub-Add-support-for-verifying-slab-sanitization.patch 4020 BLAKE2B 18fb888858012e261900e53b87ecc2d3b946d53f3d26a83b4051624be3a49db23421423ed4c2c9bd6426de40124e52f510c77c02df00d564e014d14c048dead5 SHA512 9ac1585cc4e0a79dd2aac6173766de968662df4025596aa74b968517149bb120fa076aa3d53b19426eb9eaa20321d756c61961cbbf28115695e4d53373adb3b4 -AUX 5.10.13/hardened-patches/0065-slub-add-multi-purpose-random-canaries.patch 8811 BLAKE2B e5b5df14cf1bc43f571795c3526fcf301bb5d416397f2cb9c2c830e269c38b8bb486b9374927c0ec5d8e615ac911cecffd83dac17eea06a5dfb8f6d047fdd8f1 SHA512 7e2bfd646d687c1fcf119189d2c2c059f5730a2877b14f9908cdc33a35d0bfb99e68da38b90363c5685298cd80707ca4fa09cce282f79de1c0aa1fbeff1e81e4 -AUX 5.10.13/hardened-patches/0066-security-perf-Allow-further-restriction-of-perf_even.patch 4744 BLAKE2B 69f7fe4d990d6f159f61ca6ca9ad4eb8a9fc4632274a6825acf831d75e9beb4524a8b8f38e0c44a90104c403b1b45170ad318b0593ef856d13534ac38bf374ab SHA512 3dc336e54fbe812d8e700f25227f1d0ebe89ec20a120659c8773d1982b897837a6b5bfccc951ef88ee25cf59ce5dde01839840a5bd01f65b1add4e30c64b25d6 -AUX 5.10.13/hardened-patches/0067-enable-SECURITY_PERF_EVENTS_RESTRICT-by-default.patch 798 BLAKE2B 5f4bc3b1709dc5302004a6e17f4f78f2a646b839f82adf5facb07ef0219a239cb505f4eedb95ea417a06d75315abf287e12bc8fdb9ef7775f3a679186dbf9c7e SHA512 2969a47a7c7a929fc3a17bdc4456cf40b408aa8e58e73c47dacd4b5b77eb02f141ba03cfbf40624311396014b1226b606ffa977845da800608b4172db3ba280c -AUX 5.10.13/hardened-patches/0068-add-sysctl-to-disallow-unprivileged-CLONE_NEWUSER-by.patch 3791 BLAKE2B c1d0a1949a09647079521b90e58c12da63da14f1954aace9acab05c82037ef89c427abc8b257a5aace35bc5e8c77aa9f89aff495d61f43acad25f0b52411cf20 SHA512 ccf00c57467990d56a62b8a22df409539aee155f95ca28fd5c8c120f031ecbdf32269f0b406ddaeb98868ac284205d8617a05e34f1602469fd8b4f508e0917e9 -AUX 5.10.13/hardened-patches/0069-add-CONFIG-for-unprivileged_userns_clone.patch 2070 BLAKE2B 6ae81d5f14ed7953c961f1d30bf4c87c86b62e9192257636c0ccb3d52966c5dab6946bf4dda52ec9ce02c06dc71bcac5e5a46221c9d53093b4a1f38f21417100 SHA512 7e2520a61eaafb8ff0f50b9c22c50c784f3afe77def13ccdc6ce030af629382afa3a27a045b79276975e125c89684b43afe38148b8c552cfab621c528ba0a0df -AUX 5.10.13/hardened-patches/0070-add-kmalloc-krealloc-alloc_size-attributes.patch 2735 BLAKE2B 9edcf7104d5bd9f11acc91593219f81176fa8ad3c7dfe9492d3e2682bbf575461187955076611a490eb21972eaa49769ed07b6e538515611f1c462701b9db26e SHA512 33d94ece1c681ac0e105a23953871e69543df05243a71852dc472e037932db3d8006faacdcba1a862aa9997f6ccf7a7c7c6c0d929f37c7d7e65ec0327cf79c1b -AUX 5.10.13/hardened-patches/0071-add-vmalloc-alloc_size-attributes.patch 2249 BLAKE2B ea003015c0cdcb89dbfaea6368712bab52906e4ff045bcd5ca1e955baedb41b93d417b4d8fe800678822c6d4a0d72c031926717e2d781311cd567126f2f115b4 SHA512 2eb14030deae8480b13399fcdc07ed9691875f88da4eb57db117ca64498651e9be9586b2e4883d2450c48b339ffb893f08b0f78d85273c0014efaa791aab6559 -AUX 5.10.13/hardened-patches/0072-add-kvmalloc-alloc_size-attribute.patch 860 BLAKE2B ca8ad8c53354206a8c914d241d2ba44b6bf12d700c3d092fbf11119dae49f65b4d1098c198068ae881f1a77c875521f71821a7e761f544fd2c7d2345f3667fb7 SHA512 51361d144aaddc622dae0413d3c474ab9ccfe8e03ec837473b6d8c1e736b2d5b1ad2629587822241129fdacaa202e944c182ee9af4105ff8cf46f18748ec2f23 -AUX 5.10.13/hardened-patches/0073-add-percpu-alloc_size-attributes.patch 1588 BLAKE2B 9d07d9d6ed92e81acc82beea9ce82b907098b4e8bfa8bc44d83f0510d0250de6775d2b48b88cdcec57e0812c9a0421e2702996af48b60228b082ccbb1dedd103 SHA512 687430472329cc4b2b93cab8094354ef95e0cde6608993d1b647459b3bbf902fbd1dfb7dff53621a28d9d93806b52ef94330d3609488b70d9c1c86c96eab83d2 -AUX 5.10.13/hardened-patches/0074-add-alloc_pages_exact-alloc_size-attributes.patch 1259 BLAKE2B 8086efd9c041d169b13177032fa4bbed5501cd6ef3647c0d64c54ef81542237c7f93d90af267f897ae7cd0e705e64e1cb54767ebf72892e02b78cafe8cf3de22 SHA512 84526a71aba59ff9a395fc1be37e434049495ec960c657c89f931d3615363263d92d26e31469ae549760548217721945491021cbbc54cad6a3e6a8f263f3c2fe -AUX 5.10.13/hardened-patches/0075-Add-the-extra_latent_entropy-kernel-parameter.patch 3591 BLAKE2B 223a9d0aa677ebced49bbf8aa0bc4e56b0b9e735d553ba4cf52c04f5acffd94d5e7c55833bba8d36db76ae284ea07d138a957ddbadaed943953d2901e5603e11 SHA512 e666c64e0e81602c7f9df666b5dd237927b3404162acc44258229ee5580ce6b1d291dd1847f5de905d7e7151519072746fa9d4c45e620ca28507138c2ee65497 -AUX 5.10.13/hardened-patches/0076-ata-avoid-null-pointer-dereference-on-bug.patch 1191 BLAKE2B f7315357051ff89bb83f86dc943fe10d7f3132a34021c6fb8ed6ce2c6ae16df4266cc6ae7ea68f3946b8abdd19d84ee00069015194d0f7e323f51c3fa6ec8eff SHA512 74a3cf41ce115840ba2d8a707eae0c706ffc6ab3b83b875e8209180cd01bf3d10cc60013bc65bb40eb1f1efc0298877b75dacc9454e521152fe7c5059e8b4840 -AUX 5.10.13/hardened-patches/0077-sanity-check-for-negative-length-in-nla_memcpy.patch 755 BLAKE2B 43dd93aa7c6f497aa1d098fbc07243f4e00bd7918d886952d29d2c4bf1cb85e3aad1ef5203dadb3b45b1256ed7fff96935d9c8607256921b7f4a60894b814e0b SHA512 984a1c90b6bae2862ada94ed3e1ac48b3badca55ec82e99921e02695e45cbb175124af5e195edd24556af5a0a9f1604a2d4f42c90a993d80fbb587c64f1ca467 -AUX 5.10.13/hardened-patches/0078-add-page-destructor-sanity-check.patch 2205 BLAKE2B d06097eb17d8409167e5c8db231f2dfbb5fc63a835d30f8d373fee4e7dc9367bef10286100a91567fb287cd2cc675e749cd83cf3667e22fee23d3e04bcf5a834 SHA512 88b3558d5b0d10ad4f85461fbc29ec90eec47e3f1be2682b5e7bff09331b981afffef2bf71346de127242420315385dccc59072dc50a73ab034ee4fab9888e9a -AUX 5.10.13/hardened-patches/0079-PaX-shadow-cr4-sanity-check-essentially-a-revert.patch 1793 BLAKE2B 120c718eef8c985a321dd08cdf29f000da2d9fb6a33e7001d7e4f2013938026d07beed900ed510920a3607c254f50e3b27303057fdaec7c9562a5bebdab4297a SHA512 27bf699acf2e5ba1a6c7a1c0dee07d0104e5de7e136212e7a5c0d4aadca006be422c546e2e7c37a0d7b4cf278fa41113c5aec3f60afcb94b9f36f7d5a8d7241b -AUX 5.10.13/hardened-patches/0080-add-writable-function-pointer-detection.patch 2688 BLAKE2B 489df22066fa9f4703ebba205c5b94d6033e63d88f51153c86a5c0941074d5bf0988fe4859186a2616f32ee2e20839ebab22681c936294bf879dc24e4f6e47aa SHA512 d1a60e26b16e224ae2c39a7d7eb0f2f56051e42ff1bc2448bb726f22587288a65a90dc2d20545386258dfd4afe6c0b5c90db61163f1ade59fa3278a087268642 -AUX 5.10.13/hardened-patches/0081-support-overriding-early-audit-kernel-cmdline.patch 760 BLAKE2B 308f3a96ef212baf58e6daa3fc8f86d35802201c91a020f2529f7dc1765fc02bae9461f9e460bc277af56c07d55687f9a7340f755bb76f1c0011cb6a3a5a4483 SHA512 f44b7133895d0c84b767dffb390a002c86711966b09fbb418a55986c144eb91407fa57dda04f5b135808bfe7308bdb62112a4ab2d9be17ac2de9d85534f7fd77 -AUX 5.10.13/hardened-patches/0082-FORTIFY_SOURCE-intra-object-overflow-checking.patch 5669 BLAKE2B 257a4a3b2b239c1e04ac38fdfaf9baf57568f202b061ed64f4193be69159aa837fa105fe10fb1e2be8e57deafe70505ca516f7675a90421a1c665429e50f9399 SHA512 6330eeda635f963b7f7f4c973a607b9e6cf3f0498b16987518f68e242247d71719728787911e02dc0670685aab74a02241f4f99ebc2f2fb851c83180ecccd290 -AUX 5.10.13/hardened-patches/0083-Revert-mm-revert-x86_64-and-arm64-ELF_ET_DYN_BASE-ba.patch 1986 BLAKE2B 08be0d398821871f64c1481fdfc49e02732cb83fd6da1753959d3813ca6625b2cb32cb58f042d671222e0e19d1b60384e496abbf50aef33268d77ca84819b344 SHA512 a60ad839e05532dbeabbd894edf906201932fce7734691d7f16ed4bb04aaab0e7cdd59fff8a7f05ae963a2258b7fa849ee23b50d715fd00bc28d3b1e00c566e3 -AUX 5.10.13/hardened-patches/0084-x86_64-move-vdso-to-mmap-region-from-stack-region.patch 3921 BLAKE2B 906c8fef3136600240ca9fa1896215aa5d14560ef647f770c470e847f3131fc3ad6b763c1925ee9296bb9ca4d486007011291612f4a8a42632004ba1105e0189 SHA512 c1cab75c805fa26f55ff40ddf63159e7833f5a541729b8309e2445b0254f6d82081fe59b93db69d4ee214d77e47b80bf32577780a9c294e468a455cabdf4259e -AUX 5.10.13/hardened-patches/0085-x86-determine-stack-entropy-based-on-mmap-entropy.patch 2502 BLAKE2B a65998852fa28400031904cde9050d950b71edc7ae685c348c2b3d77fbf45355bef26efb6734ae8a5777ca46e4d602b75a98012a72b5410909d85b27bd9bf055 SHA512 097d20c78267478996b4def275d13814edca04544415b67aa177bd2ac5f1d745400eaaf74c12b71224f6566b5b2a5eae05bc4585761028e3cba3b7e56df6bba3 -AUX 5.10.13/hardened-patches/0086-arm64-determine-stack-entropy-based-on-mmap-entropy.patch 2224 BLAKE2B ee89f671fde423cfe5db8744ab5cd84e96acc1134f4280e4615c1abeccdfd303c483f45e51144f634ede0ca4106ca71ab5df4a5df9315b98038001dada5f6e63 SHA512 5978c2bd950f1e3c4f9358e5a4f48a2eadcfa7bb7b2665004e516732c6818fd7785a2fc2422916a777a2bbe53d9b92abe9d2d587c19d9e44246f3ff7dc2424dd -AUX 5.10.13/hardened-patches/0087-randomize-lower-bits-of-the-argument-block.patch 1466 BLAKE2B 249cabd5182b5c5cff56e6103b6c18e31433221e7793ba168f64032c03032ca1c7f8e7f0901d30bb8a6b7927224cd3698634075bb97317281011474b9d8c15e0 SHA512 04350dfca19c33d0bdee1a692d87bb7a0880e2381a1c4f73e95082d1154abaf514fd92d20daf8d76deb25a3193e3e6e8acd1ddb8e120dd397ce2c26a9fef7174 -AUX 5.10.13/hardened-patches/0088-x86_64-match-arm64-brk-randomization-entropy.patch 1019 BLAKE2B 179bf924841c4ba7caa6314daa1dbc5cc4b5cb88b60ed5439b656a022c57f29c568a793afe4cc083d611bc1d05fc38bd3d589c84e48f220cdf5c8023aaeac513 SHA512 d86d047c4af2dcd72d767c55f4ebd15efc563ccb2099586b3245bdddf58e009538ce5c2a0830b5285682a51fd7d99d02e61548751c4b878888bfcdf68c2eeb5a -AUX 5.10.13/hardened-patches/0089-support-randomizing-the-lower-bits-of-brk.patch 1368 BLAKE2B a62e6103ed649262826695df318275f0ee9df487b6ee85171ec64888170f8c2dd5fe9f1e1e6f1d5f2bb87a3e49fad4248160dd6fd730655b317700c5d540919e SHA512 6c6b7e08981d04d7aa900d5e034ecc73171414458dbe7abe97f827577632fed3dfb9db6076f4e359d9377e2e90491e288f1a77a6e370226633082bb87fd7fa91 -AUX 5.10.13/hardened-patches/0090-mm-randomize-lower-bits-of-brk.patch 902 BLAKE2B 0c79f27474e68d3d670fbc97715b6a202f6183e1a2b108981dd3d19a7c542559a921e1c6932922b134efb928959899bfe40d99e5c3da4a7310bd4c87a1e50ccc SHA512 b6fdb4e99a7a81347eaf2134acd5bfba1d157b60f41cbbdab7a00c53d8019d6b9b1741b4c36032ab729a1266d44be54ac04f0e755b871b8f2d748496edf01da2 -AUX 5.10.13/hardened-patches/0091-x86-randomize-lower-bits-of-brk.patch 942 BLAKE2B 9258f1d7a2c90f694af7424184052027556516d0ca4160b0711d70b09c1bad5a959aeecd2d29bf7610b79ef65954f5769b0d7a51873d6edb1c6478b551c707d4 SHA512 95ae981a1b0ed4b687a557599d71a4a309a440cfe570e78f6647eeb85274c1a855884e8507865cd9ac56d9b670c56791bc6a3241edf6633767a89269a6812f8b -AUX 5.10.13/hardened-patches/0092-mm-guarantee-brk-gap-is-at-least-one-page.patch 947 BLAKE2B 4cf37e255e8a349b87214326b153cc3d0e8280f52815a654e37ce6b9d1d0b1e966227d3b3fec6e0b08e4bc597f23e0f643e8aabbbdfb374eeccf2470941024d1 SHA512 e222962feef0cb2a71ec6b57b21545486a765b3cc1dc8f07a34a7510ae1bc2400fff4b0f0d0848d2d13072eb6437df3ce9c571d6e659d6b712a08077a4abe542 -AUX 5.10.13/hardened-patches/0093-x86-guarantee-brk-gap-is-at-least-one-page.patch 987 BLAKE2B 0bfb7789fabd6ed26ae7219522ae1c6edf51faa9218af8ebf90c031d6b568224fd1c3c257e13683cfb393af25f305b15f10a97b7b486447568adb98bc0fe5d00 SHA512 5ca09be711637741be202da3f0825aa950b32f47696aff83db506829f6c9bd076fc541f21bcc4ca5f39ad06002304375a16bc3c7dcf6fb4474fa07c4ee62aed9 -AUX 5.10.13/hardened-patches/0094-x86_64-bound-mmap-between-legacy-modern-bases.patch 1075 BLAKE2B aa035f4978df03d3a632dff3c368e4a12fed232f957fc63628c2970f93f086c78111302366e657238d270d47241a73f209285e26c3f23567caa726a4393670a4 SHA512 e822787332fd792cd87e545d5943d8f14a52c0323c6f3433f7b0e31f506a857d1d2998502eaa1453c9129a36e09de7eacab8abcf26f9de7b93cce94cbc4c2c84 -AUX 5.10.13/hardened-patches/0095-restrict-device-timing-side-channels.patch 5426 BLAKE2B 6a9136a51b4522ce9041cba24d6b19be039026b291109a1d280b2576d7591ad60c9a74efe852659386a4fae8e1ecd60e38f1bb194fede6179f93fa09864a75ef SHA512 20b24aa4da9a48a1fbd64cb08761a626a4e9a47378f2223aa0668540451408c7605a28a0e126694bb63394d7465854c584953bb4a8c307ce6728d8cf4bcf27db -AUX 5.10.13/hardened-patches/0096-sysctl-expose-proc_dointvec_minmax_sysadmin-as-API-f.patch 3572 BLAKE2B cc24cfd9b71e42e51872fc8d45977500619430f44de44a344c0acba80af33eec9f72befb438e25da9ba8660e6b9dc756098e64fcd6a685f701364d548d0da0fc SHA512 c590254c9caeb695139486cf3c8740e1e60cdbec7e20666878ec3c0c2241ab81e5ab56e527f5d4927f69b008276203e2a31dde9a426ee89e6f282bff894dc5ea -AUX 5.10.13/hardened-patches/0097-usb-add-toggle-for-disabling-newly-added-USB-devices.patch 2474 BLAKE2B 4d8b8034e61314d05e8a6410097aabb4fe0f41f4f7d49368d38981079d6ce798b23f9d48cedb0045d0a1fe57374ba043c047de61ee85a6346ec5ded40002f457 SHA512 ea82525c446b72b7719b42d0d02536ca1331c757d7f69efa8e825268a166e311d13232a7aa5a826bd3ca57248138008ea3f1e0049782114add8b5f785c6c82bf -AUX 5.10.13/hardened-patches/0098-usb-implement-dedicated-subsystem-sysctl-tables.patch 5440 BLAKE2B bf4a6ee5ded69fe028d917775f573cd6985e6f2809acbf242a0edf8e88168ff848f45d844524f06e930129063de902e1e3b3b6ab0309c44f0128e7b0c2320dd2 SHA512 bdd4dd6bb55a6869ad37224a3de5593b7643845ad147934ffc78f43b8d27fa1ef85ead77f2207c95a56ed38bbfde0668478c562933ab1a5490eefb0394057b06 -AUX 5.10.13/hardened-patches/0099-hard-wire-legacy-checkreqprot-option-to-0.patch 5154 BLAKE2B 5404c83036fe17922dd03509152b998af85afae806bd4e29c1d048ba72f43c334e94786340d68e06d556f4b34f41f8b69996ec1233e5df97eeb43989373a4b0d SHA512 559edc0555887fccfa3732502c2d1fa99b5e0d17f82cbc203bf4db83580196042faa6ceb99a0d76d129ebf004538382e95a258911acf0838bec4f7dc2b5ee1d6 -AUX 5.10.13/hardened-patches/0100-security-tty-Add-owner-user-namespace-to-tty_struct.patch 2194 BLAKE2B a31776248feeb6094b72b2ba286976bf23ab92a0d9292934694024c6f368305456513b07fd0725321706aa0934653749f5a14018f489d44d723a57f2b02d4142 SHA512 1164e536ac7709d34dc1598858d7aca163a78efc7cec3c71ec918085aa37129d624ff2d20f30d6753d4223d8e72e8a64d1670fc7ef29692b45d7a0b09d091221 -AUX 5.10.13/hardened-patches/0101-security-tty-make-TIOCSTI-ioctl-require-CAP_SYS_ADMI.patch 6822 BLAKE2B 8332ad39f58fc7ea036a7570e56bb0ae0122b8aef898a525a39a52bf81d057b39176f6491640b144248c7fe612a1f86c75e949310a0b33d85afd25956faad97a SHA512 c701018def6ecaa27a80b6b9b071624521fd25238159a9c310ea103ee93f33c540b7cf40a93bda5a1f2cef21a87dde679d407b07cb12277eed97c1748f45cfb5 -AUX 5.10.13/hardened-patches/0102-enable-SECURITY_TIOCSTI_RESTRICT-by-default.patch 824 BLAKE2B bb3d7c00ab15471f50ed39bafceb52cc44e35c3f60c20d5258efac21d8f67bb1a1773d112ce4e135f052984b6490d3f6fc5989a680735773340e9a3ef4746647 SHA512 d81e737e81f89c4f65cf8349a3cbd89e95cd741cbe3970d898045902153c4dccc7db4f117d69d3b4902b22092b5882647753a0620fd3c8b5ff9b89ad5de6c80f -AUX 5.10.13/hardened-patches/0103-disable-unprivileged-eBPF-access-by-default.patch 837 BLAKE2B b3bdcea4d9217ef61fd96d9d200685f67743b35f1ea03d0e525df2ada7a80d33e0ca5468f35f8cb9523c9891309f92b81b1c628a24fa63ee6a385720ac188a08 SHA512 e5081cc114866460994dfd809ed5dd166476687d15de8383954975ad4524cfb703814591e531576ab1501cb2bf804475f636ed59cbb1c66178ea8bc5fed6a089 -AUX 5.10.13/hardened-patches/0104-enable-BPF-JIT-hardening-by-default-if-available.patch 857 BLAKE2B 49c195d3d91420597f7ee857c6e5453a6e4c8ec190277d4ae845dae072c22704e5fcc8749ed7334bc23756a01c28cac28ee7a05e738461842de3fb60305c07df SHA512 63ea362c0b368c942f395157a89e82c16916ff8891a89868e987447e8156150a3d140336e53be63bd34cb1bcd46f754172bb961b498dabf4f0967def7161e95d -AUX 5.10.13/hardened-patches/0105-enable-protected_-fifos-regular-by-default.patch 857 BLAKE2B 29872960607c71cc2db9f34c172fe1487be5e529b4d26238837581e822bc9197d1748ecdd2ccb1297f211ac617dbed4ab120d0af3ae293d145b273de4f14f61c SHA512 93753ee4bffcbf11d52aaae50824cf3093962fd252b6b1bcab2d97324934d5d51558b5086c318f0a9b2aeca4ccab7d4b4053cb85931605e79632c11c6e17fd3b -AUX 5.10.13/hardened-patches/0106-modpost-Add-CONFIG_DEBUG_WRITABLE_FUNCTION_POINTERS_.patch 4376 BLAKE2B c5efe70bd73a7ace8eaeb79a4f9f1347af939cd09d940ade036087a4c58c7b9b01c0f8416489c24057ffad67a5356b9fe98d5a4a977d3d3e581443f83a684410 SHA512 824b0e8cf5cef8824d57b0f61bb631f6b7446cb7714ce15292e24e4098facce153b51f0c7067cc026d3e820d5732d2c921547c1d8f71c1100924c9060fa817a9 -AUX 5.10.13/hardened-patches/0107-mm-Fix-extra_latent_entropy.patch 3878 BLAKE2B b67bac3eb674ff9a9ec0160e7208366859548c8c8f06aa32317b257232beb5e137237633ad3a02edf37c331086acff300284f0aa727662f882017baf763f8929 SHA512 cd2f6f9d44a93f01d8c014fec59b96ccb80658e5f4444e93016ef11a4070d9e800d96e5baebf43a27d79f5cc7da6539498e26d9b1216b66ea36fc8dba78e5dd2 -AUX 5.10.13/hardened-patches/0108-add-CONFIG-for-unprivileged_userfaultfd.patch 2287 BLAKE2B 81a4b8b6347eb7cf4a1f1c3f26aa65eee0b9a0bef613c9dadaf3d83ee860ca064eff4a8d8362e8f286a810871aa09a6ae937afc282b5a757a709e0b5f9ebff6d SHA512 0953686bad27bee326345fff93609dfb3998d6c6031505c6e2a1f7cea0d486e0d75cc6788b5054a3859eba571d7ddf2905ab5e06b30c7b7343ef263d4e2deca2 -AUX 5.10.13/hardened-patches/0109-slub-Extend-init_on_alloc-to-slab-caches-with-constr.patch 2692 BLAKE2B 60ecaf551b537addc225cc0553a0e4e36adbacfdd76bc8b303bda85ca34e2a314468e61f6c0778710790eaf0d4122e8f7d83d0690e0d8268a9f6d4095c31aaca SHA512 74000addd7457353a1dba7a773e7c2eeed348ab5a5fa53e10bc0e384f03552bd0beda427a3dbc1e6dc3380fd701ed808bde525185c38e1a4a78d8e2f4bcf5eb4 -AUX 5.10.13/hardened-patches/0110-net-tcp-add-option-to-disable-TCP-simultaneous-conne.patch 6075 BLAKE2B 56daa5c86020ac6c1b210974bcff6e7cc336b97dfc51e762f8da9c68dfe3409c8d199b1dc466fd26e891aa71244e034cf3e09ee6de300efd481931d36b75cb8a SHA512 d4cafd292cdacc46c022f0484eff5a1b88178fbaffbf1f97e234f1ca5631bf816eefb354b9f2e4f46f1f16dacc8fb232260980cf60b9db5164f07d6982415c3d -AUX 5.10.13/hardened-patches/0111-dccp-ccid-move-timers-to-struct-dccp_sock.patch 8416 BLAKE2B 6a01bda897586ad9f44c76aac543d3a717b409152980ce09af6176fbab985c9948b26f3d65fff401a00d403dc393b9a723d54ecf605369660b83ef71955cba03 SHA512 dc6ff7cd53fd78ed9c1fdfeef19becfd12efba44f4d8dab4c1b0f8bf4c218b384f5b830c5ab5e4072dda4a26e8587c92c3f1daf940f67eb1a76375a24b30164a -AUX 5.10.13/hardened-patches/0112-Revert-dccp-don-t-free-ccid2_hc_tx_sock-struct-in-dc.patch 1427 BLAKE2B 2fd45142b37c5e85bbe1aecee5f7f934d560b1da97bab7cf6a1c94916bd27bd7eaaf76f040a4bbb93d56a26d0c131771de4cbf256d6edccd00ccadde4a6382a5 SHA512 8fc1b9308032598ead61823e852606dc67a5fe52e0f99e165f0e7ef74fe1d59f001fa25b6ee4100b9a822eb40651bcd0fe72f0aad2c99971bebd0cf329dfd0dc -AUX 5.10.14/dtrace-patches/0001-ctf-generate-CTF-information-for-the-kernel.patch 247058 BLAKE2B 4b73eff4320983d16b2148199d2d92a0ae7c2c04cca49c28239e611b82816efab67c9c01a7b1e9ee1733678665185bf2a40f7163b16b5963a2c4a49df6c76e3f SHA512 c53b0386de0bcca7a44f6f37c76ec93ab1e09eb098459d3c5a83ee902840758469117ac30a9f87ec152cd7710136b14b2e0e5875c59a41f301f5100e03866581 -AUX 5.10.14/dtrace-patches/0002-kallsyms-introduce-new-proc-kallmodsyms-including-bu.patch 33222 BLAKE2B 653922fba5b5ae73e2bc1e6c5e8f841bd4ba2d2c2e5b7b823fa9f3eb1ba495d0a781f58662b25620bc2b3b4c8a4df3b92801e93b3cdd39f3c52d8e62a91029ac SHA512 d370462e393bdcfcedde131f4861411200b99f7d8985465f747485def237767fd400cca612578cffc254af004e9edd28357e6b25189fad8be7a80bb25182596a -AUX 5.10.14/dtrace-patches/0003-waitfd-new-syscall-implementing-waitpid-over-fds.patch 28081 BLAKE2B 924d5977765939bea5690270aa2ec5a24de7fef611cb9c20f5cf9aa08d3aee1a495e3ff3546b2a80954f00016f5fba2a06d425e9b6671836459b24cd3fb9a77b SHA512 05e42489feef048b626e6b32e118207f0581f58745daf8c613666f62524a9a9c3403f700e7f531ec992bbf5646cef6c2379efd2f578c6da45a2e847804264aef -AUX 5.10.14/dtrace-patches/0004-dtrace-core-and-x86.patch 280654 BLAKE2B 45ed0c03342e6095a85f8d1ea2a62da84612e09d3b267bd265cce2e373ce3a1887f8550165d4ade57b506939434280718f426cb7e8f36d4910972ba8fcd3e482 SHA512 712f536418a38230f69c4e0a22b7cb97cf8b67348068698974273fc19cbfc999847991b3d780aed759eabb313d17158091cbb78e377b6138ab5682368d6a7493 -AUX 5.10.14/dtrace-patches/0005-dtrace-modular-components-and-x86-support.patch 486448 BLAKE2B 5bd65c56bb739c640acc7ecbf8be1d80b89ed8b66f8137540f6687379f1c8930a279c51e9df2b66a00e4e37b5f1732b65d329235981e40eee5f8fc08290a7b83 SHA512 88ba86436e2e0c16e584c0e443ebf494fc9bc9114aa239e07733175275e11cde6ca5e8b77809c1599c649d8123352f5c92baeb00cfda5cb1ff103cca0bf661f3 -AUX 5.10.14/dtrace-patches/0006-dtrace-systrace-provider-core-components.patch 10421 BLAKE2B 913a09ffec28992a48ee70b9047c2f6f1111c37c1def1bcc34169b9b7dddee58314428087179f9a231f2dd247815089dd526e2739992efd8f78bb0a081cc474e SHA512 bd3b94340931149e92b432b930aca4b4066223313851b8c81067324ca295f3a4c7cbc24ac9517b8c7802ca7c7bc45a418ec0988c1697952c9e9d84f4f87dc750 -AUX 5.10.14/dtrace-patches/0007-dtrace-systrace-provider.patch 11423 BLAKE2B 5caf2b371ae6fa58d372ccb8bbdb49d214b5c63074cec0476852ea32af4dbc625032096b6db4336e0bd8b7286fe5b5d6c2e2457c59eeb9f5c564b89c82924896 SHA512 343b5ac5b2e311696c89fa685371d18127dff5548a56b8e71d18d561a577e5bbf4dc9c8f9b494637be00135d5ec4b33bf7dc84a711df753450589623da5f241f -AUX 5.10.14/dtrace-patches/0008-dtrace-sdt-provider-core-components.patch 102862 BLAKE2B ee9b3b8683c1d24b37e1b7d7ef5138d0545b699df415a75ffc1928d5df5196170f0a60cd5d38166b9e417c5ecdb99517c1cf1cd72e9479a6c2c72194b6151396 SHA512 a735b5fdf8270a11df0aa3858a59c29355739dd6b633a97b528a97a7779ac909091c1be4fe47382ff66a5e4c960bbaa286fd040721f70bd236fe01e0107b3fcb -AUX 5.10.14/dtrace-patches/0009-dtrace-sdt-provider-for-x86.patch 33724 BLAKE2B 49029ce6be2d7fff1afb8833720c6ca9f2d4254e151ccdf5a5d1a4b9e6935e5cb24ac916e81c7ab00b66766b53ff1ad6a62b6f7f33fb0e3b1e3dd4c118780875 SHA512 081230067584ab9904f6a245ea976ba9008a6acf1e2fe926c3fcfc5979c654c3c79b4b361e327e910ac295485c1cd4e6ed7226eaa069d35a26027c01d70bdb59 -AUX 5.10.14/dtrace-patches/0010-dtrace-profile-provider-and-test-probe-core-componen.patch 1482 BLAKE2B ea1ee229b6dc1a226335732fa3f8548b6fbbd46f018ece49b6a5acca562132049647b4fefb926d721122b287a5c666b20c974aee9806e1547d1dc3f2b08680bc SHA512 255ff4396e84d59fc1a757c9257e0e11ae9ea83c89564b9f4cbb93a2ca0a349874e5d61c97dd6ba82c7abd6ea91a8dd305190c3bac033a050bb1956735b300bd -AUX 5.10.14/dtrace-patches/0011-dtrace-profile-and-tick-providers-built-on-cyclics.patch 17899 BLAKE2B d6c25e8a3251c79e06dea96eb9f376476a1a508aff0e4a78562765cad690e4d053862d7b7705989bc807c562d65a4ca41236beed1724aa84d5d12f124caa27c0 SHA512 63568f1ed7bb3ea179cbc2d0a33c69955c0b85bf0b964fc56075ad0ba660c5da1a41c042c63f754c2e9bc991bc8ba59972fbbd2686d314144284491151970b0f -AUX 5.10.14/dtrace-patches/0012-dtrace-USDT-and-pid-provider-core-and-x86-components.patch 11201 BLAKE2B 63a4416d108264d7fb0fbf2fea33f89785258a474d6d18c00e183207a5d8b56fee1c802e3a00c611ae04ad8e76f88ac6d346cf438bc777cc7f9d607e992468b4 SHA512 ebe6f9f15ffba602f1e36039b63a3b502872fc96329ea877d937db103d92b2af48530067936f38229acc43f8df3e0cce56bb62f2ebc5f5fa1738496d54ce0247 -AUX 5.10.14/dtrace-patches/0013-dtrace-USDT-and-pid-providers.patch 74034 BLAKE2B ca9564374935a859e2c1de6509806ab77a50a1dfb3e8fc64638a3f102746b4fc9d792c98209f38d6f81e5c9b2bdc988f74552a48d18d038d15ce70149322e326 SHA512 4859daf54677352dcf41e52f0b1fd4fafa0802aa76c6ffd68896942ca6280f869d9f88091708c915a0bf0e52a64793f6d6332d5b3e4fd58be3d30e8236cb7123 -AUX 5.10.14/dtrace-patches/0014-dtrace-function-boundary-tracing-FBT-core-and-x86-co.patch 56182 BLAKE2B 4d289e910edf48e6631c8aadbeb07bf0886c720d75104f315d8b4c5c4716c646863f817ba207ac1d6e384a5bc4e4fa487ef2867962e28445fc69877e6bece37f SHA512 7531d3a2f548f01106ecd024e8be03ce8b27ae70e178c19686424e9dc982f6fdb73f5fd317e4451c7b8ba8571646b15c4c2a0570e0fdea1c165e83d8880e99bf -AUX 5.10.14/dtrace-patches/0015-dtrace-fbt-provider-modular-components.patch 20103 BLAKE2B ded20e58edd9df815dc4b04b940d3b9a8819e5838a6fab973b84eed90e316e18798555682f43ea05c4203781ed7dd00d336dce25e2890dbd413f1dcbb9016b21 SHA512 77733a952f8250722eb4a92ed71e20cac16120e72ed8a2b2e2717e1dba8df38e1f430ec9b185d1499f5c1cd9dc550a3d5369f438e6e9fc67348ce7f1b4e097f1 -AUX 5.10.14/dtrace-patches/0016-dtrace-arm-arm64-port.patch 77514 BLAKE2B f84c71a74942d5cdcef6103f35888a3a71323f0bcc6816d5e8c192adb9381ad628598e3f78e12a3753a7ed9f5bda937f08496aefda912f41d2d319cacf89124f SHA512 1f57a2f272457e3db47bebb6c64f8a7fd5c7847b1d87014202e20e6f2bcb5f608a80a38d6ac951e0ffb2e001577ee22a1a6b5fbe75de15cc66d75a71e37ba771 -AUX 5.10.14/dtrace-patches/0017-dtrace-add-SDT-probes.patch 107827 BLAKE2B cc92348d1b5a2442cfc21958e0abf4cc53c5fceeb27ed3c0cde00171ab34779faff252b90588f32c5cfd22a268de36a21f992c87b8cd2fe8d4f94772e6fbee4d SHA512 77b8c0e8e82e68278344d3725ef6c07282ad66b1083b858e220953005b4567bd909e151aa5d54aee802dc41b143328b18a178d98940e0ad18f86901bcb22317e -AUX 5.10.14/dtrace-patches/0018-dtrace-add-sample-script-for-building-DTrace-on-Fedo.patch 8605 BLAKE2B c569da23290d9028e8cf161dc4ef11154c7e1b98d7fc935a976f58da968950b755797c43c8f22ebda326625775f2c196fe95548829b3ffc9ea1abd2f6fa1fd25 SHA512 2d17e532f5c871c2d85f33785feca7472ca078efad11f955a3734f31dd99999a937c1f416444a2f330f75faffd95e7313a9ad9c5e0a0998464fcc905850d352e -AUX 5.10.14/dtrace-patches/0019-locking-publicize-mutex_owner-and-mutex_owned-again.patch 2599 BLAKE2B 52e58733dc81f34b844b340ed29ac9a569d7afd784f1d15893a5cb481a92600bae57af992beec46198fdbdd6c17136f0632c58119abe4eb37c38795bc6c1e5f6 SHA512 3c45d39bd727265dea556751830f7848e3f36c33cc3860c4c06d5f6b21df3d09e1248f634e97e4d7581d1d6e60485d0d2d4a0341cd6c4bc161e7ed652debbc58 -AUX 5.10.14/gentoo-patches/0000_README 3960 BLAKE2B 264a1e288facf7c19ec01225f86f3be963b47037fc971acbbe30059f0d30128ff4b50cfd0110414460e2e1d3e6af9c73117787db0bda620907c37cd305a20425 SHA512 08adee7285fb29471ff8c9df17133b5b0f0f1dc66a6daa5c06b444b3654541986da63f82d72373ba4e8cac4b4b2f1b6914c4c90a5b187cceb9ace7fb1d43d1bb -AUX 5.10.14/gentoo-patches/1500_XATTR_USER_PREFIX.patch 2293 BLAKE2B c2bde13ef40e7066340afefe55454dc933ac3b65dda4dcf81d9958ba84d9531143e58c4d35151d912bfe21a43aaed35fd99571a769ca8e823fc0d99797a96f4b SHA512 3ed100909f9aed72836a3c712e45e0116cd3c4331961a76a27b867a7098d0df9458387b656c9ea01385c3c37585436e48168ac35666b0e46dca7da05e5e38a61 -AUX 5.10.14/gentoo-patches/1510_fs-enable-link-security-restrictions-by-default.patch 810 BLAKE2B bb749b365f37988253206ddff130651e1042af49a6c773ba6f93642d5927af9a9926eab278979e048c13d2ca683e726a5d0cd509de9e6177d59c85197051e230 SHA512 c97a3799a2d5e4da9c9dfe129756da629fba8183479b02ca82f9b6d9993f17a165a96bd35ac50eb25fb293785b9b529a95165b1a2eb79c05134bee8ccf22a5d3 -AUX 5.10.14/gentoo-patches/2000_BT-Check-key-sizes-only-if-Secure-Simple-Pairing-enabled.patch 1290 BLAKE2B 35f8f2a707da3bdb4df74844f72244dc6cb9fb0d41ac2034af61ce61c96e4bd472fb5bc5c687611356d06f3940e9f6669c80f4261165809592173bf5dac54b61 SHA512 dc47b18749d95a456f8bc47fd6a0618c286b646b38466c3d950dfbeb25adf3fc1a794e95552e4da1abb58e49f0bd841f7222e71c4d04cb0264ca23476ca9caef -AUX 5.10.14/gentoo-patches/2900_tmp513-Fix-build-issue-by-selecting-CONFIG_REG.patch 958 BLAKE2B 095d70ef085c6200b3ac69695339b8937e54b49c45acb7a741d0f471f66c1fe1bedf0b7df0951eff6ccd53ade10abcc66d5d2bca994e28a49d3e4296d7332e55 SHA512 4e637935c2f37cc18f347293e3c94b18f90e2caccca726304a95c4891257a5b2bb3093aee7a97571038b29c0c987cc60a9a80aefd0d4c9a063b33d102f03579e -AUX 5.10.14/gentoo-patches/2920_sign-file-patch-for-libressl.patch 565 BLAKE2B ea33143cebfccbc5fdeab46161ab28c8ed6dbe265b35454659ba87f09705ed80219e9a9e47f7fc3df51292a3a7656c7a6d633e24a37911c35e47d039da530ad5 SHA512 79eaf814d76402a445efc961666a7c7c74207e552b0cb32d93d5cb828da580f7dbe93509dc9f53321c7844663205a8dce4e518ba047e4c57fc55f5c3498088ec -AUX 5.10.14/gentoo-patches/4567_distro-Gentoo-Kconfig.patch 4784 BLAKE2B ccbb902ac828a26a69bda7f7eb7c69770bca7685ed5e58459e473b7a8ac0f396ac9f1aa1ee23a9248de22c5aebbfecf76930420b640cf6307a4d1e73bc9add0a SHA512 bf681566831b583537eda1df1db9c9d1b310cf54a974dcdc437c8da11b65cda423ac86a1a8ae56c84cfc947a6ad363adb25983e51933cf7acb494934c1ad3eb5 -AUX 5.10.14/gentoo-patches/5000_shiftfs-ubuntu-20.04.patch 55494 BLAKE2B 5c56cb45b70a340d6eb65140f3772f3c4a26e30811645d471d0db7a389c813edbfe6f46ed2fb5fa8c96596c9486c1040948d3074b4fc5ebdc8080c4b02b0992b SHA512 e832d44d4a450c45eb7a517d6cd849258985aed08349d18ea21cf4d1eb37dcbac9153f50ca8b910955bfe64169298c631a7ec7857e9235bbce0167d97d69e55b -AUX 5.10.14/hardened-patches/0001-make-DEFAULT_MMAP_MIN_ADDR-match-LSM_MMAP_MIN_ADDR.patch 840 BLAKE2B f872f632768b933e5a5a07d78f7e1160160f07301d29a44332a64c97831dc7184dd3eb8b5321b9662b896cade8a5a14bd1f0956a248033b36f5b28bc9917256b SHA512 eb0aa32286528531096ae00933da8302804f3560396c26414908e18bcbf32face3eccd9ff0ea7fe59144d51d4ab33a889dba410d5849e4134fc1da77ae574734 -AUX 5.10.14/hardened-patches/0002-enable-HARDENED_USERCOPY-by-default.patch 790 BLAKE2B 36e63c612bf5e2ca41f1c2fd47cf026bb11c34b8fd36a67e959ad4c594913385fa989cb4049806d3fcf6bdb1b0e40bcf48fe9c6813060a9dda9056c0a3ae7901 SHA512 b63d623bef827a6482bcbcedee937c8f331ded20687331b9bbddcd14e42e844df2efa0950eb6749e76982efce73c9aaa3c3086ed31e928773f115b6236caac67 -AUX 5.10.14/hardened-patches/0003-disable-HARDENED_USERCOPY_FALLBACK-by-default.patch 768 BLAKE2B 0b11fbbb769c84644872f6168ded3b5c12a4a2d85ead43a658608020c9c9058a58fb37c2bfe4b0e516e4c498054ca2ec1798b86ec6e365463a56df1a250936e1 SHA512 a7bb768ae526a5fdcd2ed4a83e4530f345e7901db4003d8ab63bb79ec0e4716fa7ea13f7331eba7e85d3610d213e34e77d8c3444004d834c8681702bcd03fa9a -AUX 5.10.14/hardened-patches/0004-enable-SECURITY_DMESG_RESTRICT-by-default.patch 763 BLAKE2B 505c9e38f72c5a4b7ccb52b5784df0406c151cab2d1d4dfd9e936c180d4b21dc54ba9994fc1aca2b56ab657ba401b6c1046596a61a6f8df118a684506a2054b5 SHA512 e3e6a0ea0d624fe9361f1e49d3a5f5526955f3062d76514dfd330c22c89f2fc2ab532f85b7c1149dd01ad4bac75e4502316bd1c709fe3297b8639c6ef8ee9797 -AUX 5.10.14/hardened-patches/0005-set-kptr_restrict-2-by-default.patch 791 BLAKE2B 5930fd8dd7a5a98e211bfd8b43de5de4589e3fb275d3a7b825b052e220f772c6d2248f8a606cbdc6a28a790a35d4db7f42be02f8615c824f7a7cef72a6511855 SHA512 cd5b6fd8ffb21910ccfadfd019f13444ae059d41d02097f2c897336a909ff74fe84bec968e9d10f21404b4730153c2a3d380641d931b7d210212bdd835aecced -AUX 5.10.14/hardened-patches/0006-enable-DEBUG_LIST-by-default.patch 743 BLAKE2B 620f63780d82da598e95d8055cfeaef333da80f50a8b10e08430346342bc28a744e7ab3e0d153fc9196f2fc1891e4b7a0925ef469b3cebc1f9847593f53b6af8 SHA512 29f43da5f488ef7055974b504a874034ebc89f3492da2894edc59bc82a6ba2baa36c6674639b6689f5d9f738fd6ea62d0088bdfaa33ab95b9a7efcef284c03a3 -AUX 5.10.14/hardened-patches/0007-enable-BUG_ON_DATA_CORRUPTION-by-default.patch 792 BLAKE2B 47f328006b7cb7c9f27e90ac67404d8c208a5ff5f79f0ef55b2cf8ea23dfcb7286b1514927eb343c27c0a8321fa55d932c9a0293c799a0236ef1905337bd6714 SHA512 6d1721342859fecf853875d619c58ef92031b4dbb6aeeda0b745b07095d22a34d4de577b5490598766e2545a7f24c82ff945516bc083badd87a7d40dacb4161f -AUX 5.10.14/hardened-patches/0008-enable-ARM64_SW_TTBR0_PAN-by-default.patch 732 BLAKE2B 028b7a8d9cd7fd94a2c14c2c3c4a940742aa0ee912cfc551c8c3255e3f521f686986556a332100d496d01138487784ce63faf421f68be1aebbe901d6005d00bc SHA512 74e6272dba59ea008f85c76e322ae1ddf3999d909f737b96eb63652cdd6980fe1c053751899ff30b17a4aacbf14ccc0ffed9da61f2ed6d54858c4f506cb24a4f -AUX 5.10.14/hardened-patches/0009-arm64-enable-RANDOMIZE_BASE-by-default.patch 736 BLAKE2B eabff1e8717e90fffad491a57743ab8fdb97e6b93679b66d04f4fcf28a5f6c3b7e5073235b65f52c154b55ed2e4bef3cf32aa3d9f3fec0f979886db16ad68d52 SHA512 a633a6c646ef0c4172d7c734cf0c592e11c3fdd981d1a383af9e538a51f43a76986df904d2068352272a31fae633e94090f3c55d81265845e841202570cf8616 -AUX 5.10.14/hardened-patches/0010-enable-SLAB_FREELIST_RANDOM-by-default.patch 745 BLAKE2B 3848e4db317916bd5a83593e7cff4aca04f5afa8b85e7d37e440c49332a37318c47f19627503ac58fb05c6bc5fb56462f7bf14ffbea7eacef66218e712fe51c4 SHA512 82683219d37f70e78f41f62f036f9eef756695c4ce6be26e0ab0c9e4baa4a1b8d852d992cc5d817148663a1e7b81cabb1f4c39a9e788b1f9e0d8a043fef4aeea -AUX 5.10.14/hardened-patches/0011-enable-SLAB_FREELIST_HARDENED-by-default.patch 702 BLAKE2B f2e7111221aa91476539301bb86d26569e9160f86c124f8edf326dcac3260afe612989d053dd0eb39172e1e09d3add1ab78a7323542eeff81d0f0ec97857430d SHA512 5538d83e24a73e972204637a07c20c13890c1893b4ec5b83d48a9952b16a8034dd2100651d41a57d9ada4456fe799ec7e0f932ad567f21a74e44e4aced4e492b -AUX 5.10.14/hardened-patches/0012-disable-SLAB_MERGE_DEFAULT-by-default.patch 654 BLAKE2B a1175eff67c3b02d7f2d7ecffe7ed792b80232088f1fdefe07ec2761cc3f00a62284fae76b234b6474681da191c53871497bd49a6b8f0dcb8b03fb887c2a0e80 SHA512 9467e449b793dc2fe1a9e01df21caabf9ac8b7758c955d4a298fe27db4297e341add564e130fbbedfb96a122da695dda9882707fe0b4acc77e5ce3a7558eb4c2 -AUX 5.10.14/hardened-patches/0013-enable-FORTIFY_SOURCE-by-default.patch 807 BLAKE2B 69d125d64984fb720ea87d3e3901b0c6bcaaff32a0121a74e5cea4df3c93657fc7fbb576c403b986d12d96439e4e4cfa92ac2339a95644306b7376af4a401f16 SHA512 e1212581272c534b6e81b88c231b0ef99acbd5c15d756644a3fdd85a8af6a7f46c45bcf1e73e7c06b487446a09f4b047f8cc2ec78810b2bca3d7fbd956bab343 -AUX 5.10.14/hardened-patches/0014-enable-PANIC_ON_OOPS-by-default.patch 966 BLAKE2B 427d372190d1a22fd7701c4c7d2ceb90bfe56764841c26412f023fe6c034a531ce94a39cda6b013e88ba7274a807cac9df96e542585eafeb864827ac130eba92 SHA512 ff79da00ce2a2bce7ab9c8951fa98bad9bc5bb1b7db7b3d47f6bb5c2fefb72654e60f64f9a61841c408d36924ff562bd7c82347022b09e834150715bc100b439 -AUX 5.10.14/hardened-patches/0015-stop-hiding-SLUB_DEBUG-behind-EXPERT.patch 761 BLAKE2B 7b8e25c6bec06c32077130738c699a2e1b08e4696cfc41b91ca8025c1c1815f6346d0ce9b1d564850e2a8e5d0cc006446190c6c5373595eb270b0eb8e88a0020 SHA512 197ae9a39cb4cef3190fb704771df9ea26390ecddcd6c16d62b2d5574891cb927990119a356c4e4b362132030d62848509be2331477e5ecea772a64dc3ddffde -AUX 5.10.14/hardened-patches/0016-stop-hiding-X86_16BIT-behind-EXPERT.patch 666 BLAKE2B e6f5a0a422472b4176f19bbae665846462352fded3e3eb8351055f8a729ea453d9d20b676ea9de81b6c84c534aaa257afd93bde7d331b15af5a08079a520c9b7 SHA512 86ea847be054ea0079f11622c701aa85b06f6b12b921ce7c09aaca405636fba5886dc1755b3f5abf35516980bfe92cb5bb3e81dad791ca6bf69b96ad0149cac3 -AUX 5.10.14/hardened-patches/0017-disable-X86_16BIT-by-default.patch 678 BLAKE2B 2df66c9ddebaf6b61c4cbea97448d505cd6f989dd1d0c57a861bc1f424e848cea3bb88b49fca45ac82ccaf6862eb9163088922988362bd9332fb5873ad5315ad SHA512 59c7bf70299effb4feba588380162a0dee73e50b094077301b0d631222c1ebab4b4102d6a9172a8c7954f2360f26b67810b8c779524f7a674763c1c238bf5df3 -AUX 5.10.14/hardened-patches/0018-stop-hiding-MODIFY_LDT_SYSCALL-behind-EXPERT.patch 754 BLAKE2B ab32f2541a5b1cb6384b37d8bddea661fc309844616b0142b51c74ae92f8e0ac9111bc6dcc7f5abc85b52de9d5fa01ed2cc00d976dcf7de263731c1cfbf91a9a SHA512 110c7ce806e623a99b2e3769b67b2e07cf2c27fe41229e35652489670b82614ccbbab8a3c6a8f73e7884720f3a67b64489f9479364254fe485054af547ae5ca3 -AUX 5.10.14/hardened-patches/0019-disable-MODIFY_LDT_SYSCALL-by-default.patch 802 BLAKE2B 6bd3fb37c973fe67a3b68cbb690f27917661dedfc90b102f46530991919444b9a1346fca396e5bd3dea3dfd453f037d2e584713e26911185292bef3c7e9d81b1 SHA512 6b830af858a20e05eefa1e6e468f8e7c860bb037e995e029784c5943dfe3d89e9fb74038e5f03c44e9d8ef9f431e824f2faa660161854791f5712394fc3533ec -AUX 5.10.14/hardened-patches/0020-set-LEGACY_VSYSCALL_NONE-by-default.patch 765 BLAKE2B 51df35ebaf0b02fd4f63577e52e6027713e351b0b0e34668f770798b0658da1c68f0898fc671d71f06f4fdd9455216199474a5302ffe1f738d4388eb2c80a9a3 SHA512 f106329f56bc229bcdf674197d380465013aa6ca3144f1c0670917109ab969e59568beb2f33c42bda587dbcdeb3bce46ee2a5f7c10eb2336099ce106febb200e -AUX 5.10.14/hardened-patches/0021-stop-hiding-AIO-behind-EXPERT.patch 691 BLAKE2B d4dd58609d600c1d956609b4704559bd0552ea11a53033c3a5783d2a15f4af02b4fbfe70579bd7798f5de21c9f428dfb520da2305cfea6992d9638a6a38de6b9 SHA512 670fba56b7ad8fe823036a3dd851142565a60ed45221b122c7488b226a84e7fa87d3b5e4c56f697a4462940ff8913e0119f22f4004ecec9496294937bb387e11 -AUX 5.10.14/hardened-patches/0022-disable-AIO-by-default.patch 631 BLAKE2B 2e36f2a2ea7818e029fee1869b8e81e8e8e7a08d3bab1f4edaeaa2e5ea8a1a1b197f2c7706611c8394b0be5227534a46e5b27f127b0f7692ae4443fa53c92527 SHA512 e6612fefd3a89bf0fd7ab8ca8de8583c1cc818f8bc9f3cfb7ccc17f0aef354c8dd872c342c35b632b3e1f3f7bb81561a0e76839788e3dda0df8c4e7878a833f9 -AUX 5.10.14/hardened-patches/0023-remove-SYSVIPC-from-arm64-x86_64-defconfigs.patch 962 BLAKE2B 683bb0a4d330119eeca89c54ae0b76a1cbaa06f28465eb3d5434656763bb14ee67f523b8d99b7e1385cca886d7ffaf949786307125b25ff4a0fa8e21946a34eb SHA512 e9c9afe723898d547c9937628379ae99aaf688d5df9c06dbf5c9a67295b535b7637ebb43760b438ba4e9a0f456b01de879362e8bc648539fa6a8a128e3296bd4 -AUX 5.10.14/hardened-patches/0024-disable-DEVPORT-by-default.patch 695 BLAKE2B 47431c16dcf22efca336a54ea0ac34be6f07e292de44637692a2cfbe61bb4b79fbc963727373b77b528bb10ac028fede079f689d38a2a8035cdd4c6242f68ba2 SHA512 97f0adbee3b589bf51c8d505ae946f8f4574ad9206815f2b4f0d36765ffc5ea4756b4d4e067d586f7f1722ea7cc02837a79fa457c087096466e905143698c5b9 -AUX 5.10.14/hardened-patches/0025-disable-PROC_VMCORE-by-default.patch 613 BLAKE2B 888ee4beacde4804029afe590da92b1fb0bbc1dffb982df8f4515045299da280045eeae898c59df7c5bd52483ecb9018478025f19aa8e97735db874e61a54a9b SHA512 a65bc64cbad98b8edec2cc13c06d1396b33f5c7faf912710d5242ab7f3d06430d02af1ab8b243d0c51871c5a6911f7f37ee18da7f9e1690f9ddef78f00b88718 -AUX 5.10.14/hardened-patches/0026-disable-NFS_DEBUG-by-default.patch 598 BLAKE2B fc29b7ea3c098b4fa91b1e31e8a1a204e6d87fb5b2a0a56079d4be1bb8186a320c838764fe1873fcd7dd7514ee7b034be296a2ccf548c8005aa4841309de2c6d SHA512 67b2d862716a6f55d08c318d4a1b98572d5d3234fdbca535b3307953ea487fe1aab5b341e19f097adab0fa921e1f0359f5433a7ebe5ab5cec395e21d39d63639 -AUX 5.10.14/hardened-patches/0027-enable-DEBUG_WX-by-default.patch 653 BLAKE2B d387310d653a8139d470978901bb510d0e0082ff4ca9274fe40553aa9d70a0a2b97d6d1e517bec895588b8452c445d48b98adceea9091e5739ed93d4efbdb445 SHA512 c8c5ee77afd4fac5c79271cdcb9c7cd6516f6fe8fa90220f264095f5a53f7db490a72a88ef03ac329381fa1709f9c095294a5a10fa97f6b8dc53281465d1d197 -AUX 5.10.14/hardened-patches/0028-disable-LEGACY_PTYS-by-default.patch 683 BLAKE2B 5e05216047d47da9cfac49e029f8a3999d8515a854a7e370b8e0ca8bd0a75c248d7eec33da3c4789fda1b683ac57b61e9d18ab345ddd0eee58a3d98bd2d784ed SHA512 422579b7b810cda09e988c0a4b1a7bf7489e51eaf85a52a59da9e88fd5ab89797f6818f851aac4e92b212834fde6db64a3b2bb79d6209a468775c859e3cc6299 -AUX 5.10.14/hardened-patches/0029-disable-DEVMEM-by-default.patch 662 BLAKE2B 40a17ee691fe2183b835f372fbb03e6bf0a9d3df016f89c84bf8b5e76c602e97739ced38b1eb4152608514d78539b8b040dc262ffcac5327397ad26937169efd SHA512 aed3ad87151ba18511e797f4ed6e0585c53099cb0f8b4609eb0369fc7060e85625172c79272656bff816cdd39a5f88d3a43955270bbeac7208dcfb5012bbc2f4 -AUX 5.10.14/hardened-patches/0030-enable-IO_STRICT_DEVMEM-by-default.patch 719 BLAKE2B a19d38454a3a370830f3451794fe252ce077710fc3c6ee5a336458ed2de17cdebb803ac23b9cc5dfc634e84ee6c5b0fcb056d46b7b60e1bfdfa638889be37883 SHA512 d4f6a52d7f4d979a58a066e2149bf4e27d95cfcb353a364445950023d5b55d4409175bc6af95d241e6fa6e27af48f4448ed9bc59ebfd92f471f52e16369de035 -AUX 5.10.14/hardened-patches/0031-disable-COMPAT_BRK-by-default.patch 652 BLAKE2B f5eb29ed31bed116758faa42a6138cd8695988f83956a58fc416645bf7d656afb75183a23f4966e29685328429bd2600ab2251ac1eab2e63d95328673538504a SHA512 6954b9c1cc54601e1e9aa2fb817d14a4de0557e82272fc761c240a429abe9d0fcedf95fe6da27cecb6505a6447367afddbfbf97e0d92046b4cde75d79b9393d8 -AUX 5.10.14/hardened-patches/0032-use-maximum-supported-mmap-rnd-entropy-by-default.patch 1397 BLAKE2B 8bac4fc388e50eaa8fa3ec6071823300acedb7c64d85922b2aad4c39592a7509041faf0080d9c9b31685701506715979e5e33e23104588eff109a38169f00c77 SHA512 d11337d35366b78130fc332346fc5d0fe477f670be5a2619fe863c8f0847abba37de400d6f8ceaf0588236fe1917f4cd4add656b512583966ee8c2e61d9a77ab -AUX 5.10.14/hardened-patches/0033-enable-protected_-symlinks-hardlinks-by-default.patch 818 BLAKE2B 5231045e59ea1cb5607d5cab3cb24ae1a6ab5c79959ab2f82f699cfe02af453e93d617d0c8e276a86b2126b156bd44f665ca756b4e72ebde308f3944c77bad61 SHA512 3b498659f80266e1aebcaa82f4a9b3b8a89e90f83b313c67a6f213bc56333f4801e7ff6d9bd0ea7163410acf404981ea56a01066e23ab9673c70d4a55b1b1bac -AUX 5.10.14/hardened-patches/0034-enable-SECURITY-by-default.patch 646 BLAKE2B 8c4970fc32ba4d2dd4fb218379c578465a2fd16255572dfbca2889f5cc36acbdb2e7a51638cf7a8f1356f3281d70731f31a0629b1292e3116a74ff377444055a SHA512 963161fc185a9257334d42e1c3f5657c9a9a00e3605f1a7655c5deb1e86c1d0be9ee1efd7ab5eefc65d947b7e67b94b3a461e65a96e7d84fe36fa5d2ca09475c -AUX 5.10.14/hardened-patches/0035-enable-SECURITY_YAMA-by-default.patch 706 BLAKE2B d36ee2acbeac5f0e0c38ce7da682dc939159a8fdb4b6c292362d3c96c3b74b5dfdff71fb9a01b177a48ec836ac7134d25234ba45dbc32e2a1243834fb04a68c1 SHA512 a21c6b4ea4635e5610733aa76ac908a06b954c44b66657c4fe19b021c65036c3f736085871b3bfc9e4fc044da44c0d7cabf3d1c88fcb76ffdbe7b652169a5116 -AUX 5.10.14/hardened-patches/0036-enable-SECURITY_NETWORK-by-default.patch 685 BLAKE2B b05a33b12fea32d7be6b24ae5a17061462441c94f23df3055fcf929d32536e62e9cac388ba6df9f659260cab413b831cc35648cd94ca5bdbe9548e01dad8515c SHA512 6c720a9ef2c0c07cf7022815ddef6bd36e81ffdee7fcbbdd0f72b3a23dade2ea485b2faf1e874f7df81fe02f2d2cd86046fe997ef5b5f85483472645d0c7c4a7 -AUX 5.10.14/hardened-patches/0037-enable-AUDIT-by-default.patch 628 BLAKE2B 058ed7827b6e07e1e74c215551efc2410cc76309a36e0399d788fd712dc98f8edc82f54d24f943b2e936817abadac990b7b8e4fa2119b5b91aa1271f0c0da3d2 SHA512 1f57ab25cc2ea8daeb4234befc457c048781b6089c3fbc3f9edf81655bcac820c974829316a7faae573f47169c3831f2ec9572b97666fa957239d592864a2dbb -AUX 5.10.14/hardened-patches/0038-enable-SECURITY_SELINUX-by-default.patch 784 BLAKE2B 6bd382053af37ccd813cbda898138fa1de212a53e622d67cca6fd2d17b0dbb154ec28f408dd9911ecd001301bfa4505cc7dc139b2230596d18964c4e0f1e7ed3 SHA512 f20c7975cf65bdcb416a172493067d2c93dee772704d5bdf6bf532b51a4f36d5364d0e51baded96a7c77a5462950f422e3bc697b86d02895c7077a94d901e93a -AUX 5.10.14/hardened-patches/0039-enable-SYN_COOKIES-by-default.patch 666 BLAKE2B c706034352e7e67fdfbcbfafd87cf10fa9488d7ba6fab08b8afc4b3c2987035118bf20da16fe61356792d0f773a0e9a6443a6163adadcdb73d2b34648feb3c31 SHA512 c2dc7a87e09bf2298636179bbbf1921b0918ee38c4dd0088c920597261df9de29afdbd278e9fdc11114d25b2cc72d9963f59461b3e791c9759b61b4402b555af -AUX 5.10.14/hardened-patches/0040-enable-INIT_ON_ALLOC_DEFAULT_ON-by-default.patch 785 BLAKE2B 2493d4410761a525a561feb06b7b2eb2bb0fc97de4c31bcdf8e1c26cd0551483a1fade15570feeade28de99d7342e7406792b144038c0dd4d9d8df143fc22c17 SHA512 da78c43e340af7e1d542340253d4985ec9aa2e11e96dea41c5db8b2d47dc07220d5b4aaf229e89d71fc43645497c26da2bce51f3f8f34b4865f5f40aba1ca3a2 -AUX 5.10.14/hardened-patches/0041-enable-INIT_ON_FREE_DEFAULT_ON-by-default.patch 774 BLAKE2B 31675210dafc5cd5ae25bab7506358482317eb8978c9f94edb2f3b052b6a2dbf075edd8b81e29925fe55288639b3b05d9f6ddbb1829b05e9a3b7d9e97015f8e0 SHA512 c776bdd490d47e7690e26f77ed9d13b8c473ccee2a6fb01bdb50a96e1d29640943172f4d0d3b657c1ee09f59176fe6ce291ea8fef519730fc61b7f6b11b20d9b -AUX 5.10.14/hardened-patches/0042-kconfig-select-DEBUG_FS_ALLOW_NONE-by-default-if-DEB.patch 827 BLAKE2B 63e56a61e1dfb18141dcc288e56e78cc1c9957bf793333437f2a9eb6f7f75fc22abb8a6dc34d0a66f97fb582075507aee0c29eb2e1ead8941c0f7fa4a5a5e5ea SHA512 b3e8291567f66195a47ad85c5d2725f9231dea704c16ea6d9c9f74be4780067ad9c5901fd9543f6b350ee74dfb2c7427a507c3073451710cb69ca54b97335b4c -AUX 5.10.14/hardened-patches/0043-stop-hiding-SYSFS_SYSCALL-behind-EXPERT.patch 705 BLAKE2B 4efca3c39d11b967e96710f0e48aae03a464d0c6b3b8a578cd9fa7cf2b00f8065420149c9c6e41f0a97f03243ce95afe7279c6621b55bb34e5b04cf7faa03ed3 SHA512 df051fa07c3c0003747191d312dfd678ed6123d750baf6d3446f91daa5ca53001c127fb0d9ba480ee62753f9c4fa309f132710b1baeef5236a359139dfcc93e7 -AUX 5.10.14/hardened-patches/0044-disable-SYSFS_SYSCALL-by-default.patch 835 BLAKE2B 85ecdbc3f76e9b63c74f9ca75e455be70864d34ae89b63d2d1ac0e522ac4c3270176513f2386ec9f278ba9f1104346b1d1b36870cf09cdcb213416eb6cfd84ef SHA512 d8af6c401e1bdcaa370af47fbfdb8d615b0d58bf9f7b1a026466ab74bec5c5fd7a27b3ae9acdc9e0c939fafd68c34171e83721e505aafa96867eab12c642ec79 -AUX 5.10.14/hardened-patches/0045-stop-hiding-UID16-behind-EXPERT.patch 679 BLAKE2B da984dab4a2c4e33cdb255a69ff792fabd087b874f2e60131ba2c52c74f5ebbed4342eb54cbe561a8a125e59d33ed437d98dc1c2674359c0f8a731494a0a7bcc SHA512 34754705947fdd7615b3bf99ad9a3b60c9f52eb71f6a56f13da2827bd1dc297093fe7a18e0aa88ca5bc2c6c44d5a01dea38ce6dd2a1d431c19cbd0d2783e0e6c -AUX 5.10.14/hardened-patches/0046-disable-UID16-by-default.patch 605 BLAKE2B 51b82834c3bc2677066c337b8378d8520810f3587e12aa04763666d2cebe6accba1e05abc2f17c3e734633a47844e7b2b5e246b5f196523d66b508ea16e72e99 SHA512 5c6d2be0255f6bc7c6b169f5ccc090f90fb678e47fc4baea7e8d75eb4626b427e14625eeae62b35b8308a4d5d0c5b4ef56c821f29ec73ffcbf9fff516638b9b7 -AUX 5.10.14/hardened-patches/0047-add-__read_only-for-non-init-related-usage.patch 697 BLAKE2B c573367d3d7f9f26e1275725c00b0d7a0642155bd08352f5786bd64edcf4ba5235a337bf7f728c289f92fc78f84744e5613f5ebeb0aef6870fd0efd5e92af32b SHA512 9c70f722a78dbf885e8f1186846cee8b1e04a400331a124f7934f6b5513702fc6eab5b111144504e3adb1743417ad46e80874bbe9a4b43e926685195a5117666 -AUX 5.10.14/hardened-patches/0048-make-sysctl-constants-read-only.patch 3971 BLAKE2B 92ae02371c633dc0bdf467199375b0c04d2a592ef180f7991eccb3a677e786e447562fff332e8d92d1cce5ed7191f34bcce8e980c5c429f13ef503f2bef4db06 SHA512 9c883678c0a40bdea0f02f5a9181fdfd7301103e533fd41a378075c32266d52a73de30ff1b317e78aff3eadae434a7b24c4a683c712c238518e137381ca2c906 -AUX 5.10.14/hardened-patches/0049-mark-kernel_set_to_readonly-as-__ro_after_init.patch 2089 BLAKE2B e9866f11472fb2893b2826fbbc8f84ea6be2a30d3a5f982d46e129e9584fb9c83634721fe571a8893a45cda1eb8fabf78eb24afe34f81634d6bc32dbd423fc1b SHA512 e71db6c353181d9d65f235a8e392704f1f0c3969c164f3bc7922c185db103e6f9dc3f34f73a792915d83f76b729612ea7a56724e0143c5f97814de66d822878d -AUX 5.10.14/hardened-patches/0050-Revert-mark-kernel_set_to_readonly-as-__ro_after_ini.patch 2171 BLAKE2B e96a6eca5b3a2228ff16688658a51f0c796576d02c0d79d728a063530a50051f095f8f2a180ee9521d9aacc91c6bf77dffc4e9995fe8a1fd15f143f66217908e SHA512 21d550ad873dd857db68c143454dea74aae1c3ad0c33e2b4879c6aa5cf66f7df27a630682afd6dbd3d1fb11caea4b3e1bc1ee306414eff6fdfa023712576ee91 -AUX 5.10.14/hardened-patches/0051-mark-slub-runtime-configuration-as-__ro_after_init.patch 2004 BLAKE2B 43c884daf8fc0841d11d9851bff39526888b1fd4a734bbc081b44eb0332c33e4e5130586e042403ba0f66385a2cab2d25e7ff5adfe0549ecbfde82728c7cddca SHA512 38c698265c65a60cc2c725d64689d9571b3f15941c0fefac4d9fa528831db153cb8e792172587d91d0fc84ed14dcec7f9e7e6bcb2b242d074627f4e9f4ec0a04 -AUX 5.10.14/hardened-patches/0052-add-__ro_after_init-to-slab_nomerge-and-slab_state.patch 1165 BLAKE2B 6e0f48e49da4fce2279afe75aa7c16bac6f0a9240ab37effb657a769def3beed6a73a49e322476c30233208182cdbecf6e5560412154913424b642c8a254e578 SHA512 2e6eba94301f803e434b0e1d930b34ef2c996fe0aa8d3f19fc76b3ccaa264effb4b3bc8e670d7ffef6a43105a83cb83af7bac4b0c29e94dec0f6a91fd9dfc8ef -AUX 5.10.14/hardened-patches/0053-mark-kmem_cache-as-__ro_after_init.patch 709 BLAKE2B 5fa2a7380601873d3141a7ad632cc566abf66c65ffbdb9c0724c9719d182ab61e8417062fd855db695158c05420e9b26ce9e28d323bb9fc68925ccf088780d04 SHA512 929aa752c00c12b835d8ee566e77ee01e8d74b25f0db4cbbc4954a3e346719ce6cd776aedc868dfa4cb16ed25f72802307aa8e6191d353c42b50fd6dd1a0ffac -AUX 5.10.14/hardened-patches/0054-mark-__supported_pte_mask-as-__ro_after_init.patch 1954 BLAKE2B 169f477851ca8954cfd29fea13419e287eb18e4ab1869ad8b58144ce9685a1af2685e83faff7c438088586e836de718e96fcc718752e9c105d535c6c0137a002 SHA512 39ea7258eab2dbb64f9a09dee64c7fb8fdf5b8eba84ff00e780ffe1836a01efbdb06ec46aeccbb0fe907b21b79010743d34a1f83c67b61e594afdce549e5df27 -AUX 5.10.14/hardened-patches/0055-mark-kobj_ns_type_register-as-only-used-for-init.patch 1663 BLAKE2B 87db11abc0f6b6d7a31e26b224748fc4d87a0fc32772809d5c0de678b34a8d8aca1404d463237530d03ef3aa677ba51c79131bd66ed6d8d0cd2c825b4ff17222 SHA512 8b61236e656921a911762fb854633f808fdfbf7861b6c8d6eebbf606839f8e46040851535437ff449445a8518b1fb92c9c8279fb80fb79691090410b38794932 -AUX 5.10.14/hardened-patches/0056-mark-open_softirq-as-only-used-for-init.patch 1272 BLAKE2B 417281b39b08ca457757c0ac9b9651a661e4d8b28c9fc7799eec7fb4163405ebd98d8e818cb0a8f3d7cc384e3678e650f189b4699a86b0e2d562df7abafe0bec SHA512 1c5a50efd51c3db850c21b8cb974e125249792ab5cd1c5bb757ee1226a9b00e4fe582cac920ad90bb8278d51155fc28dc73ee28ff6a6b9d2d090d962a73a0233 -AUX 5.10.14/hardened-patches/0057-remove-unused-softirq_action-callback-parameter.patch 7357 BLAKE2B 87c0548d6650433af370e1a7337dc0f0c674795a1030b089f48f41c291d804307a8dd3a42a52d6cecaf96a4fcd49df89078e27f0742747b0042cc24dfc06f957 SHA512 e6b26eaad8755ec04558e6659f8ce094dcc46619db24937207dd4864d53f19856baadf17a5880267c837306c53a9251dc874f5619cd9c90da5b087192521ac52 -AUX 5.10.14/hardened-patches/0058-mark-softirq_vec-as-__ro_after_init.patch 871 BLAKE2B 54ba8ea5ece9ac776c3725a64a0922770ebd20cff1683ae5dfbf405617396fb6425bc29f8182c9e30d0a5bb69e2ba9ba4605be389bcb57824544cf44117fa172 SHA512 b6802edd05d1af365a12a91ef7c7b1b90659fdff5ac82ed031b31ffe520c08a3dff6d379a5165b48158743ad68799055af86316ad7c39fb07fb0fb3dfb62c5ae -AUX 5.10.14/hardened-patches/0059-mm-slab-trigger-BUG-if-requested-object-is-not-a-sla.patch 947 BLAKE2B a09cfe40534289a5126b577507f77596f72a029b16af3e6c3af4e6a89126bf7313e8982a5d0bece7c5836dfd52844823dff7b4c7bad79a43d7ae7e6ab152d26a SHA512 12dc9ca1e5544ab8532df0e005fe35f6137eceb5b246d5971cdf148aa5c036dac646a0faf6128948360b225c01eb292ca0fac609cd22f719cbe252f2ffb3eab2 -AUX 5.10.14/hardened-patches/0060-bug-on-kmem_cache_free-with-the-wrong-cache.patch 1180 BLAKE2B 59081fb7f8b23f8824177846427faa20cb3fabe60a896355ab67b69c1807298316bf941f1089e8382864aa25b56692e57cf3c9a3df7a91660b9fe29d94a8dcf0 SHA512 7e64eb05ca141a2a9e06f37c0f4c7364e8ee1a253351a343ed4451f8fe94140b4ecabe552912107f233ddb9250e578dc66d2f5980b499ec6cb84dde6457fb069 -AUX 5.10.14/hardened-patches/0061-bug-on-PageSlab-PageCompound-in-ksize.patch 788 BLAKE2B f1ed4d4ca9321d0a172de8f3b43a51cc6499a9748283492a5cffdeb3b2eff1ef31b065a64510aa70802ffb2d9b6ffe2f0302a4855aed0b09211529c4a30abc25 SHA512 4f77f4de4ac9d18314ce630c23d383064287e6ca8f8d139e8a66354139f6dfd72112754bbc2f234da3f1d97e399e4f42afe2ace6c37d3e05e127328cd1822e3f -AUX 5.10.14/hardened-patches/0062-mm-add-support-for-verifying-page-sanitization.patch 2256 BLAKE2B af3ee1d212bfe6d680b94e48f18982bcdbae0bc41c582d169a3e0551b7ff047e6e4abdd3895248fd0443be878943c68d16ce930832a7843bcc6d0eab2dbddb11 SHA512 72f956cbaf03e9515bd38d41f0f50d24fa791c2a76a18bbda29f8810455743439109f1d6aca35498ffa4f66e3e52746d7b73e6f00b6d1ef0ed91ba7d21eee885 -AUX 5.10.14/hardened-patches/0063-slub-Extend-init_on_free-to-slab-caches-with-constru.patch 2454 BLAKE2B 64a9952217fcbe318ea355263caf8c4c7a65992a23b62ec6ba03587160e020ec18bc50c5afeb948a2d5e639d11c1568869e01183e50873b609c7e8b7f72cbe5e SHA512 33ae0d7c14f97942fd63913ff41d2c3956e272e9a026c45c35a8e7488e48df076dda3aed23193391bcb41d9642ced55d1942809b510bb7aec9bc9ba871cb5c84 -AUX 5.10.14/hardened-patches/0064-slub-Add-support-for-verifying-slab-sanitization.patch 4020 BLAKE2B e10151a5329a5eba85375c2e71a66b86217b51f712adb05137b4d698a0b25cd84693e3d0682f0a169216f2fd8dece55e0ed78fa37735cbe5632ad5cff9c46502 SHA512 e26f64274e347982ef640584fdbf0dc0244749b3d0f8654d38bf613ba0d015aa8be56775788e48909d44f4308b251fd58bb656e9552d2daf6316c563916b4707 -AUX 5.10.14/hardened-patches/0065-slub-add-multi-purpose-random-canaries.patch 8811 BLAKE2B dd33ba1d4fdc1610fc0987ac184bce72385fe7691d6adff8838d057f78c0818c0ff62b696f9ccf780762480248fcfc8a11ff62e9e7644902793621fca1aef2da SHA512 0fbd30cb842c0d3f1e7f65a0d45c1cbaeab4fa9fa01d42764c212cec63b6254c05f50b39b82b6ecb3f11e3144b5663eab0d6b9fe7270c98834b93b26832fac0f -AUX 5.10.14/hardened-patches/0066-security-perf-Allow-further-restriction-of-perf_even.patch 4744 BLAKE2B 0534b43ab38c6c9308ef935b2b9e9345873f6aff3975ea5148d5fa5398a7e4c786de7918bf0b00e56c8facc4c0d6b75736f3695d6c3c4e75a50fc9444229ef9a SHA512 650f35b2886224abff0fa5fd9fbb8e1d355b45b26007ac847f0f0490884219ec38aed5fefc904aa7ee9614390eff658e55bcb8bed8dfbf2cc85412da2ed5e937 -AUX 5.10.14/hardened-patches/0067-enable-SECURITY_PERF_EVENTS_RESTRICT-by-default.patch 798 BLAKE2B 5064c2a36b63533a78a185d3c651bc8be4d7be579a9f33f97e57f6c608227619b40cc746367b36e5a06f0e9a6cd99d7eceecfc59b3804f51f1c79ed4e7728622 SHA512 03bb7a37a24894c10170e33d16e4f81be504c2ce4c806973f3328edcac009b2ae29da829212d434b4014a4b81eaab2600d7a0b962a6b30c1a9c7b2214063c1c6 -AUX 5.10.14/hardened-patches/0068-add-sysctl-to-disallow-unprivileged-CLONE_NEWUSER-by.patch 3791 BLAKE2B 71bd3a8a9627e850a770df799318f52946bf46a7fbbde1991576115b64d5c469cf7a928eb1b4db2a3abe73ac69d56e02c20449ec883151a789b4093d627ea1ae SHA512 9ea2a209c5b003b92b35e0621b7b889dec48c259284070c3a879064b9d4443b92791398a02ff7406d64ae7db367737d91481bc52a655a015e320b61c4d3ed7fc -AUX 5.10.14/hardened-patches/0069-add-CONFIG-for-unprivileged_userns_clone.patch 2070 BLAKE2B 242767131e5d851ae5b62f6bbae60ff2d53cec3ddbb7eafd3144ac12812391449c51808776af0986f81cb609e5dee142b338c74c265e5c193fcd3d6a6fabd0f3 SHA512 2af0b36d0cdea8748935b33160e86b1526563e4163ff0948f483abd4dcf28cd56c6a96d94c7d8e4795646acfa6a3d5b5958b029d4ba60b27403a4aeb74e3630a -AUX 5.10.14/hardened-patches/0070-add-kmalloc-krealloc-alloc_size-attributes.patch 2735 BLAKE2B ae8eefa4178092947f9534e485c7c88e6c3a443a4fac97494fb751b5c73cb1d4de9ec598e999cb792abadc0fdacc9ebd84e5947d60a60311434e232249193afd SHA512 3b3611dadd8b8ff963c58d0d702683c1b5e69788b3b99b519f580de62d92b9bce8b67640072b4bbfa22c86dbb4878889ee0da06b740d86c1a4f5236ae43890aa -AUX 5.10.14/hardened-patches/0071-add-vmalloc-alloc_size-attributes.patch 2249 BLAKE2B eb9ff3856984a1d5bee866290bbea45f4ec1a3c9019a662abae8b749fed5ae4c5fa43d3130ede2d5b6b517ee2f0fa162e947706a2af97ae792d77c3f57d0aba3 SHA512 352ff70e07bc59ea2b4e5f77e7e72460f663730a81c0f3f5a05205f955ff755e1abe9ccf9995de8859ec7714c6239be7f64c2c1564215c12388abc983e1b0616 -AUX 5.10.14/hardened-patches/0072-add-kvmalloc-alloc_size-attribute.patch 860 BLAKE2B d524c0cbdf2aa1691631659ffdcdf8e20464ad4a9d108c9340cd1917e7f17ea9d07e9f803dba384bd460005e44b318864adbc6f9d6b4faf76e816b8015fa141f SHA512 a1bd23efc934e61bafef8795a54c128baa97f3de9f2b8f8a3ad6d1b0d74e0f615750f2bfcd73b872d79c9641444a411a4d535d0148fb7ba6e37dc77833883228 -AUX 5.10.14/hardened-patches/0073-add-percpu-alloc_size-attributes.patch 1588 BLAKE2B e7da3104527c3c818426aae7f35c209b63082907d73ecfb2d1c145b42570ccf15b2031e340701ff37146c2490d97a1147fb20c6826d8cb100a0fc7f1bb4ca13a SHA512 413463e5bd8c7fe04515c93f6c4511241700129338e4b87a001f773ebfe8d194be86ae8885ae479dceea31a10b9a2990d12028a82a65236e2db585e19f53b7bf -AUX 5.10.14/hardened-patches/0074-add-alloc_pages_exact-alloc_size-attributes.patch 1259 BLAKE2B b1477beed1aa7a823668b43479b18ce7f1defea70974125361a86807b720894f4e294767fbbac367047be29d15430f780da867716a17fb7a28705794444adf82 SHA512 d9ae2c2cd111b20a0c90c5cb12ab95cb9aee387003e15110408d19ce8f70494b42ee658d4f4ed58ed1d0f369b9d2d69faf4c43d202d3f67dbbc4fced36242c43 -AUX 5.10.14/hardened-patches/0075-Add-the-extra_latent_entropy-kernel-parameter.patch 3591 BLAKE2B 6e1ae96b5530c4d9bb58f476689417e3b9a134072be6e325041d79ba253c60341ff82673d85dc184bbb27d7422d7490b1ec0d4294eb682756d0f9e6c4628acb8 SHA512 0fe5b024f03066dcd634d639cfbf4578d62de910a9cbce7323ca302e007a89b81c0972c26fee5bdac1446078f4e89efd8e17df8253f9a14c2fdf95875753a5aa -AUX 5.10.14/hardened-patches/0076-ata-avoid-null-pointer-dereference-on-bug.patch 1191 BLAKE2B 73bd6d8ec109ff67ba947179a969587af1ade929cb1ea0bcfccbaf66da2625c4f074d67ffcea2ee0e27bc9a8295e131a5db3c0729ed041f7c6b2ff4e48851b11 SHA512 74991d815a6aa27d976e15ab5eeb9e9fe97db86e7d5cc6e54c4c748420d4e975278206b1c094cad509c4f2bd182daf6f22c8a80a7b93b2f6916fc335ae472c3f -AUX 5.10.14/hardened-patches/0077-sanity-check-for-negative-length-in-nla_memcpy.patch 755 BLAKE2B ba31a34d293a1aba3fffd8a76a6953195deb0c5a0c9e80e003f2a71c7284313b66cc6aba961b18baed21a7c22eb8f7414e3a450fa85d2204f123a69a33c80cfd SHA512 5fdba09d6a5cac9ce104c5d223823665e1764376fb77c51004b00584a9c511699d25c0b109fbe4b11b253303a9103400efcad2af302ecf6a001b09c0c9886c4d -AUX 5.10.14/hardened-patches/0078-add-page-destructor-sanity-check.patch 2205 BLAKE2B 146ea9ec8dd21e17cd37588c4b1ea76ed8a52ccf37253c29a6052df1d6c436b8516a4a9f55fedb5a444c82845787be911117a259b5412ea7d4bb678d71bff0a6 SHA512 a86ca4a64ce6f24964782fd724368adf91e04a999373f0951d5b8b1f54aee2e6bb1aec41f8554a9baf1d259206265433c215fdebbeb9581a63d90607e3a072d7 -AUX 5.10.14/hardened-patches/0079-PaX-shadow-cr4-sanity-check-essentially-a-revert.patch 1793 BLAKE2B 148463bdecf3d22ec0e8a4062181dbd69c7447cd3c62c84650d502f4061f148c06044b501f066852c131c0f6d04da6fc503e3e9c22202f6771266bae4f2bb95d SHA512 c2610af8b12dc872037b0383e56d7dd8e6cb2730678d9f727ef31db7bb74c56a3a64875209e14d13a14d1451572e01af66378870ba765d940abd3a99990bdc7b -AUX 5.10.14/hardened-patches/0080-add-writable-function-pointer-detection.patch 2688 BLAKE2B 99dc1fb03f1a4c6c502aae588b8e16205ec4186d156ddc4d45cc064f4c82613298712c92d48f1cbdf6b651313dae286f2409f83c60573436f8dafb3a23b35e29 SHA512 ebdaec0da553554c44d07375062c648700d56bc2d00e0c5722dc2e707f1b0fdb1d5b0e2ac79919b9f2621a04acfcb8d328420fcd74b99b299f6ade16c791cdd7 -AUX 5.10.14/hardened-patches/0081-support-overriding-early-audit-kernel-cmdline.patch 760 BLAKE2B a2fe0b0f9511111aeafca9373aa6eaf8054c63f7643bd76a98233de47326c01eeca7741f176f59438b513aff828e8890c9e3161d85c2e048d8934ab0dece4044 SHA512 6735d28b89dc6b5114df737e16b73cf4658b661a29ce43e3cc04514b4440ebfb4e3a94a6e2163f6af70c3d9acafba91981ecddbde6c785e222d2742e1b816242 -AUX 5.10.14/hardened-patches/0082-FORTIFY_SOURCE-intra-object-overflow-checking.patch 5669 BLAKE2B ed17ac562215b97f7c48d10b2dfe65137e494eeab2df844c94a916c090739d0ac76ca21f4fca4630794b9f5efa8b43c62dfd98fde89729b7fb8aed9b1318e350 SHA512 8ddd1434a840157610bc7c866ddb8f3f0e251a9d7bdd3b6bdf8336eae27760664322fd163844d07560ed6fb55010c52a2cf8dcbd84181171e56ddc15c0f63933 -AUX 5.10.14/hardened-patches/0083-Revert-mm-revert-x86_64-and-arm64-ELF_ET_DYN_BASE-ba.patch 1986 BLAKE2B 0fb823061842195e42e6cce628f2e75555285cda8b3bd9ecb0714245e22d67dbfd284604d333ba138dbf405519cbd6593fe2c5126a6d31ca2d33277999fac6f4 SHA512 e4c61f9ae28ce58f35543b43629db570f3a342185b9034e3376a2c7afa37f35a8b0bccebbb9e41a959a8d473dddbe7256895020ebce9e12f2789dc72a746814a -AUX 5.10.14/hardened-patches/0084-x86_64-move-vdso-to-mmap-region-from-stack-region.patch 3921 BLAKE2B f35a58e8d5604201193e6be08ea9f89825579f245683947153d1c532ce2c8762e3b8bf3c0325d07b6ae2cca6783eaf387148e01f1e7d91dd35aeda527bcb85b8 SHA512 15325d27d952bed62851f550e1bd7a08f06c8532c269e1f2201fed0d66626720a2df92e1b7cd913e21a5d7729e99b1801be4974b44cddd007570e8828aa76020 -AUX 5.10.14/hardened-patches/0085-x86-determine-stack-entropy-based-on-mmap-entropy.patch 2502 BLAKE2B 0083a76021192fcd8d3ac3547d7e5148b622524e7ccfd25e45640c6f4db4e425eb13db343681e56b51dfcb0d5aaad4c107d91caeb722f64ac2b09b07640841bc SHA512 462879e4ade7e1daf174a32c8929107d86c1a243031a4f006a514d88e62b8a49a0117654ce1b551c2af18e4d4feb9399aa350cae17f0454d4b5553105147f247 -AUX 5.10.14/hardened-patches/0086-arm64-determine-stack-entropy-based-on-mmap-entropy.patch 2224 BLAKE2B 6798e9ab9936ed48182d32ca72993905b95fa74d42c4c44a3859bc6e0f365d26a42355bf58febe2c3bf73d717a7247c83b8317d11237eb10a1ed3ced0b308763 SHA512 9086ea3da59864672159d83025e8836c4a21e5d490424a7d29ef4df9f9bac896e52365e1504e36598d8b1aade12fd3d7b880e3cf81aa5402ed70da3befe7ccc6 -AUX 5.10.14/hardened-patches/0087-randomize-lower-bits-of-the-argument-block.patch 1466 BLAKE2B bb09f0baca64c8bc75c278ca67297a14a19b520b63d07703b0ffe23ae8bf2f378bfae68310ad6d6948523c4b69b2872ee3f9debee0958329c719482beb71d8a7 SHA512 0f6756254115971c7416f009c56a2abb634a131e4dbe8526faac3bdc7d265d6c737673515083cb4b26cb8b53ed6c087838c40501a47724af961bc11448c413b6 -AUX 5.10.14/hardened-patches/0088-x86_64-match-arm64-brk-randomization-entropy.patch 1019 BLAKE2B f0d2cf9c9c2de3f72621424644a47e6e9a62efcf07392cbdeeea6ab60cf7c31a8393e5c4797c48667246ecad4d53c7ba884b295d15eefbfd28a5f4eee21b045e SHA512 34a77b4b3b404f2288885a7df2e3002faf4bf9e692456e92404a2f595e49e9d20434fc6175aec0cad3c1f1a26a179a1c9578796fc7d2149209bda139894113ce -AUX 5.10.14/hardened-patches/0089-support-randomizing-the-lower-bits-of-brk.patch 1368 BLAKE2B aa53fd7795bddcecb3761da181f19a0812f95482e81648a0f7ab669aae6d648a92c228695d050fada9539090fdd5bb43520d643849bc5e05459cec5f848c26b8 SHA512 05f519ec692130b1cc7bb98bf9a24257ac918a0428cc1081aba2ace5f3d83c693ef8f378d198d7340c0055dee06d89d6048768c27bd412474a2e7504538d7c29 -AUX 5.10.14/hardened-patches/0090-mm-randomize-lower-bits-of-brk.patch 902 BLAKE2B 49a0d28970187fd71e2dfa4aa57511492505cbee0cf3cf91aeb199f38b2bfc5e84143d30e4c58f8eada035c98cab68595335013fd02de1383d257f915fd4dc2c SHA512 8e8a75e59c107ec81b4ad117998cf89c76fbb50d5793b1cee433bf4ad101cffa44f1a8b861607c33c8aad606f8a046300446ae584840f6f65c8f3690be0f4c22 -AUX 5.10.14/hardened-patches/0091-x86-randomize-lower-bits-of-brk.patch 942 BLAKE2B 5bdcf728fbd15710500c810b47f23f39f3edfdcb602e44f6dff19b16f1e2da88eb4f18db90bbf5a936ccf1b4a011e2fd03b7a9fc1b97cbcd8d36d0ab297d9d8c SHA512 cfeac1314491d94cd18c18eb425fc611ea8924b0f77ad5a4825269bd29892be1ce01dbfe3ad0c92fb52b36361692fd33beba2b7b0fd567b5b197bd214e0f31b4 -AUX 5.10.14/hardened-patches/0092-mm-guarantee-brk-gap-is-at-least-one-page.patch 947 BLAKE2B 520d9c42f1994f42782a5424325dbd199a63cb6b4e84c981efdb1ddd7c84e34b1e72ca7bea7a1cebc009625594c547a36551848985ad35eeacfbefec6f515e0d SHA512 071899a50a6d38303bf01c7236a371ce69797e364ec526d421875f49001b3b3d4d977d2faa4f833625d8b8862aceb5c3f63dd08375e7540f7d87438d5466ebc7 -AUX 5.10.14/hardened-patches/0093-x86-guarantee-brk-gap-is-at-least-one-page.patch 987 BLAKE2B 0d00afeed6fab54aee2aeeee2afa1625b9adf5baeb4734a959b29bbc3285d11e6df2b8ec47383aaa5d8348ac4e4dda2e34e0dc40fefa65873d2efae084bef82b SHA512 700db640cd25d3d3f2ce378ef2706e549a2762c71692710a518638621fea23b8c47e8c2dee996ff343d371830af4df81e6c5f582f84ff0e45931a48ca3fd8509 -AUX 5.10.14/hardened-patches/0094-x86_64-bound-mmap-between-legacy-modern-bases.patch 1075 BLAKE2B a322809c9405f2101e05ebf4f4526a12477438c8fbdb5b18606dd44b536274db1d0126f0a44fca9cf4ccab8dcb59c09f367cf4e05e5c9e42c5f00b5cf6ade997 SHA512 10e8cb3ef76699428f702059c8ad99a52d540ad739665480119a0e2c17fee8e2838916b788fcd40940f8de7cc6f9647b9a42775c4c0099171bc34a5ef869e88c -AUX 5.10.14/hardened-patches/0095-restrict-device-timing-side-channels.patch 5426 BLAKE2B da23d7c184c1cdc51144a029bab59db721a431d5e7a6fe2243e361d4334a61ef87e6b92a7032862ae5ec36ac08a94a51d8fba54e810c94c9f1a51995ffe1a224 SHA512 cc6a021f75b38bd4046f38e599e189efa55d7d11022bd179a5673dede47c0e26613d1870533550fad7e487b973e06d65bb7ee9c379c8eeb85bbdaf7d509621c3 -AUX 5.10.14/hardened-patches/0096-sysctl-expose-proc_dointvec_minmax_sysadmin-as-API-f.patch 3572 BLAKE2B ce1f17c5e0875bb3568a1d41800c383096dd35ed49115d15d723a00419d909f07b01a5a40dd12a5f06defc2cf28b4c174c081eea4049988a8b3fa8d076f00197 SHA512 1969399884540e01526a524a4dbae4dd0e1b533c7f003a585ceae70bdc97d86fd07b336cc614f3436a4aac03cd6b824aeb20e45ccd9912cda3327c1984300711 -AUX 5.10.14/hardened-patches/0097-usb-add-toggle-for-disabling-newly-added-USB-devices.patch 2474 BLAKE2B 0d80a45becd17ce86c935952719e385efc8a8850644e94d165328d7b5bf3f680cd275914571f785bbbd3de7a25223cfa2c948fca86606c0eb64b7a45c91e1e1b SHA512 733d9460fe331becf6988bdcae27de49541c1dfa7311fdedfc84d8a83c3eb03217e3d211c98a66b255ecffdc86ac80b06527ce254db7e20234210e15d9676e40 -AUX 5.10.14/hardened-patches/0098-usb-implement-dedicated-subsystem-sysctl-tables.patch 5440 BLAKE2B 93a3eef18da347a0da66943701022fa471f75068d6e54aa6b3dd19f4ef9253045e95058cdb6d52fcf0be795470e6ec035e9ff5d2cc55f6f0f445a6828c1edad8 SHA512 6eece0eefee82214552c1e2b94504c4bcd54c5d90e4b838ce0d87d8b579820e605a260db8fca5dfe9bd5654692bd42b731826af889df784df59c5b9785771efb -AUX 5.10.14/hardened-patches/0099-hard-wire-legacy-checkreqprot-option-to-0.patch 5154 BLAKE2B 739ca15ebe38a4fc2959610224a70bee87d2828f1d36c23d446ee67576c6d4bf6a72057c3955fbfc9eceba22b6a3d833f97d129a6bcd9bb338b9f1482845df29 SHA512 54f3429452318b79c29661f9f77f36e4495fc8dc9ee562d616cc7f1d6574b93e7a8b2912817a2cdb362c0ec3421d9b9559b5a13ad74511e074e1be722feb9210 -AUX 5.10.14/hardened-patches/0100-security-tty-Add-owner-user-namespace-to-tty_struct.patch 2194 BLAKE2B 939c53581aeba0521aa3ddbaa55d4766351e6f82efd3f803710edf405b4d7f410c8ee381fab3f8cae11173165e2285c79c1f7623df1950c72f2d623008d1ef4b SHA512 9dd812a4e7e3a7b614ade873079aa779628cb82d5454a93ec7c9df40b6950a1b77fa1c0c97e2630b3c92bef947736421e8377afe33c06f14b30c7435df176614 -AUX 5.10.14/hardened-patches/0101-security-tty-make-TIOCSTI-ioctl-require-CAP_SYS_ADMI.patch 6822 BLAKE2B b7ff538ea957a76cbcb3d679bc0ed2134b4c03f7524d8e7ea30f16b53116ee592372d8c43906ab025f604dc64af640cb23c605cceecc97ceca940c569178b4d1 SHA512 5584284e66d6ac25c95442e15faee51cd5f615d7538e79a431fbbaf462493b480b0976b28360b694d7cc9f659e22237c20b07a81e6b590bc29d08bd2c7c6d647 -AUX 5.10.14/hardened-patches/0102-enable-SECURITY_TIOCSTI_RESTRICT-by-default.patch 824 BLAKE2B f1b9e35dfbe19a6e16b12a8d60e853385b6bdb22d60a7554637abfdd58f0836afe74c51346adae5b07e10bb0b4eb2bcf838e8275654b4001cfa0ae3f1696185a SHA512 27179484d797c841a844e8661d5553fab76bb79c156f59f895dbfaf846421753eaea827c4ffc0d3a9ce700f0490e6f4f1640470fc3b8b43a7027acb7cf75298c -AUX 5.10.14/hardened-patches/0103-disable-unprivileged-eBPF-access-by-default.patch 837 BLAKE2B 2baae02e7f275fe7855f12aab01aa27e67276efa8e7efc8827d7d321981c0fda0b1bb4bd8a79908a5570738e94d79d380777eb874fbeb9e248e5ceb19f6b54a9 SHA512 a4911a63bdde28c6c0feb90417dd146a9e6f222f103a5342d9df7559b703b390e6851ec958075631c48ca17cd799fe633f05a0646e8e6c42dd48bdade54109de -AUX 5.10.14/hardened-patches/0104-enable-BPF-JIT-hardening-by-default-if-available.patch 857 BLAKE2B 28d5e4c408634f28ad7779634f6a0cae4ff0bd7395f0ba315127b582446117a30b3fadcdaf6b21837d699cbcb2b070afbcbb223f80a3864028b2a27e2bb18c73 SHA512 9ec667103b6dec895c225f8026c30495765054431abc36d0b215f88b5bf8828971c158cc3f4160982bdbda38d75829ebc18101c7b199ef6c9d1f7d240478e28e -AUX 5.10.14/hardened-patches/0105-enable-protected_-fifos-regular-by-default.patch 857 BLAKE2B a46a0054e558e5152461d170b1e1b54cbbd24572153bdce5bd86459daa4061deae46ae5d43223e594f585c1ea42064430d78bd1fa4dc0f8105e9265c4ceef84e SHA512 834a3986ce8c7eeb39a1de07c412281a28ab775209bb177b4f82ef11d3a94c7bee4fab0ba812795f7fc6ebbecfb054603457d246d636c3e803d23dc976db9afb -AUX 5.10.14/hardened-patches/0106-modpost-Add-CONFIG_DEBUG_WRITABLE_FUNCTION_POINTERS_.patch 4376 BLAKE2B b7a8aa31449ba71324f2a0fce914a54495490fd3a3222e26fbf34c21f56f919bedda8351b62ddee07044b46fb33658c8919ccef3b6b135354a52df41491a9b37 SHA512 219e208a65bf23b60b423330ff30b8ea5f30df9b50e0196cb8fb5e7d7ee41ea5ded28fe5e2a80f91105d4713d0dddecbaf3d4f7126e771bee610a886e253417d -AUX 5.10.14/hardened-patches/0107-mm-Fix-extra_latent_entropy.patch 3878 BLAKE2B 81a60e1d461dc87df58822808e962890e29ae2d3d3ed2e5200315c5492792717e9ffd94d4d1c011e2fc52862dd27b6ee3deeeef4c6d83eb2617d5a156ed8a4ff SHA512 6d31f2a68ee0426718c99b547ac68bb471a88490b3b3f614a2217c713ac4b1954c728d36ff58297952911b1cf9f26cac476fa7ceb56a1d05e990e20b8ce63ceb -AUX 5.10.14/hardened-patches/0108-add-CONFIG-for-unprivileged_userfaultfd.patch 2287 BLAKE2B 80d6bcfeda7904c7446a2a7e44bad1b76038d7960943e03cbd143dbbd41ed8933a5f920c1cb191055bba9b826775f034ab21485b4508d6fed909b0cb282a0186 SHA512 f0cb27a29172b6b0d08179c2108a28eee830474cf77c59ba45bdd33069156fdbce19e8c939595cfa58a29a67da0fa32ff29489c8707792e40ace05d660f5892c -AUX 5.10.14/hardened-patches/0109-slub-Extend-init_on_alloc-to-slab-caches-with-constr.patch 2692 BLAKE2B 7f63b34062b872667ccd38d67c1d48aac2fa7ee97f92a005daaa874ac368b13f466b835b23f8f0616265cabc218e029e9f97b51e2c8443931eb571e66d5d2dc9 SHA512 4ae4e1bff7be423c854772dbb59bf4adc4677f2e3185c01ed2969b8f5fb19ddd978f4efae08bd291e9ba4e98e6cb5f84716dcd86224c566c2b64d296ca5eacf3 -AUX 5.10.14/hardened-patches/0110-net-tcp-add-option-to-disable-TCP-simultaneous-conne.patch 6075 BLAKE2B be6e150cc235fb13e4c51818d7b49a10bfb1675998390a16ed91230fa8f01e23f8724975de2954fe34b8b161cec51af7928c53453d881df8e995c71c341abfcd SHA512 c46549df950202cdfde765bb4d7d947c9858413265a44ad39b233a39e509a39e2b5c7dd08c1d449a09917364e3c0e7a744af38a441fed8338d51f222e629074e -AUX 5.10.14/hardened-patches/0111-dccp-ccid-move-timers-to-struct-dccp_sock.patch 8416 BLAKE2B ebe7841ce32fd3c1d36d993dc9fb46cc7d9ea57ee3d22904244183e1bf6fa1de93d10e3890a9c49c21a544b8651ae7ec2fe8a4151ec1ef5d4173c813052d5448 SHA512 a2ef4ffa7132f93ef77a71687c9f8f6ca31af10c80449a014332e2c5b3bb618dc6003ae4b4edcb1199a7f7382638acd8b9db160ddd68219ab7348f6de983b730 -AUX 5.10.14/hardened-patches/0112-Revert-dccp-don-t-free-ccid2_hc_tx_sock-struct-in-dc.patch 1427 BLAKE2B 077003157e1328b70ddd1d9c650224194c329db05760776fcbb8c6144a42c66685b6384120e5744d70c34106330fbf810c10d453c66d0b19fa28e55890e7eb20 SHA512 90724e27f99d734c86658b90185bb92fdacc0cd01b978c047bbbd6869afede1bebd3a28e1c8191caf8cc4ab0914db99dc76e0de61cf428efe01eb9776f93164f -DIST debian-kconfig-5.10.13 172354 BLAKE2B 2f1fb579a89863fe28dce8f6ba7b8fac9322251c067912c270476c23e47edd43b07a05c968a5583fdf620282fc0d091b7912a1fa49b269c2b151373e3d920e62 SHA512 1087c56c1d923545e3309b24776f4aa3badc21befd56e3bffd22f718b9d84ad03b286d45ad24e1ce61c9d4a61f02612d97cd7fc962d652da18c8b3187f919a6f -DIST debian-kconfig-5.10.14 172354 BLAKE2B 2f1fb579a89863fe28dce8f6ba7b8fac9322251c067912c270476c23e47edd43b07a05c968a5583fdf620282fc0d091b7912a1fa49b269c2b151373e3d920e62 SHA512 1087c56c1d923545e3309b24776f4aa3badc21befd56e3bffd22f718b9d84ad03b286d45ad24e1ce61c9d4a61f02612d97cd7fc962d652da18c8b3187f919a6f -DIST debian-kconfig-amd64-5.10.13 4367 BLAKE2B dfa1559a2c8c5d2447979eee4bc52b5f7e7b310aee6e326f9b55036c01714d120ebc6ca7c9ffdba6c3241ffd6b3b13e8222f511db30797527145640680a39d26 SHA512 6473dceb7641a9e60eedfaa24be95e4d20401e9508ec907c49da2d73983f54eb293e781245ee84aa41f2728354be9bdb06191867008c111735e6962a1d79e888 -DIST debian-kconfig-amd64-5.10.14 4367 BLAKE2B dfa1559a2c8c5d2447979eee4bc52b5f7e7b310aee6e326f9b55036c01714d120ebc6ca7c9ffdba6c3241ffd6b3b13e8222f511db30797527145640680a39d26 SHA512 6473dceb7641a9e60eedfaa24be95e4d20401e9508ec907c49da2d73983f54eb293e781245ee84aa41f2728354be9bdb06191867008c111735e6962a1d79e888 -DIST debian-kconfig-arm64-5.10.13 25993 BLAKE2B 96c85926edde53779ea02c45a6cddff97c42fd6cd0c9df0b806e0c88f85aa6122826e7588c0646db1ee24ecb09f6e7d1b481b937ed10b5de216db81ae766c217 SHA512 805b5b286a17eb1adb1369ed27f4e3ed750d563edad7598773c447698671a1db72289fb87cb5f14acb51362c1029fea9f0a2e6c58f7e60c8c99d8f3c0f417632 -DIST debian-kconfig-arm64-5.10.14 26025 BLAKE2B 59dcb6f5c2c8c28a936644654dc33f14db235c7fa4ede999bffbc04162f3eb3d5c80fd9df15fe03fbaf085772048d6c0e37a2660090666f4e09d749b0e1e3db8 SHA512 9f1d9e367fb789e7ab998145d1dc2fbf6c129d77fa4c91936031f6505ad00e8365d01ff585dec9f6fce98f899a1bf4f64eefd0e35c3ce7315534c8ed3b3b5eb3 -DIST debian-kconfig-i386-5.10.13 8990 BLAKE2B 72fac181239cbc9eb8fd0dcfc8edac3f68447ca3368ec87a1beffe499c0cd30c4da6a44756dc0de56e2997ac265f238ce07e23f7b1883f9dfcf9a272d07005df SHA512 de116317bccce4476901597bbbf47ec62feba828e4fe74bdecd36f009b6a9d46c168a06eb0448bc688503e3ea8b9d427fb381513763a1d6389cbafdec7f1def5 -DIST debian-kconfig-i386-5.10.14 8990 BLAKE2B 72fac181239cbc9eb8fd0dcfc8edac3f68447ca3368ec87a1beffe499c0cd30c4da6a44756dc0de56e2997ac265f238ce07e23f7b1883f9dfcf9a272d07005df SHA512 de116317bccce4476901597bbbf47ec62feba828e4fe74bdecd36f009b6a9d46c168a06eb0448bc688503e3ea8b9d427fb381513763a1d6389cbafdec7f1def5 -DIST debian-kconfig-i686-5.10.13 1296 BLAKE2B a015d0163d8c484f59b85e18b32d4226bcf42416f94e732f44f9121cda8f99b88e3744bc4ae2fc31f88a48f972b7d6a842a1dab488341fcd4eec125ce649ecd7 SHA512 ab20d397b14d774706c278340d992a57b616b8f8aa084e17f9500d87d83915bdb922679275766ae7aebb42f4cc05d25dfd4e75ac9aae84e8dfa85141d31f0011 -DIST debian-kconfig-i686-5.10.14 1296 BLAKE2B a015d0163d8c484f59b85e18b32d4226bcf42416f94e732f44f9121cda8f99b88e3744bc4ae2fc31f88a48f972b7d6a842a1dab488341fcd4eec125ce649ecd7 SHA512 ab20d397b14d774706c278340d992a57b616b8f8aa084e17f9500d87d83915bdb922679275766ae7aebb42f4cc05d25dfd4e75ac9aae84e8dfa85141d31f0011 -DIST debian-kconfig-i686-pae-5.10.13 856 BLAKE2B 3c5a77d9a0c3dadbe4c1d1beb9b2f08e74d77635b520d27397218b4d63815f270e9d06939e17221a0df46fd6de8f758b9236a6654793eda21a336841e3d19f5d SHA512 920a5807ec1a742c35429b88b7702fed870b89ae365e95c9cd521b54102aa51f9ad1abcb0b1424d315b346af2e8ec57054ada5ddcc0ab1872d400956090fbf4b -DIST debian-kconfig-i686-pae-5.10.14 856 BLAKE2B 3c5a77d9a0c3dadbe4c1d1beb9b2f08e74d77635b520d27397218b4d63815f270e9d06939e17221a0df46fd6de8f758b9236a6654793eda21a336841e3d19f5d SHA512 920a5807ec1a742c35429b88b7702fed870b89ae365e95c9cd521b54102aa51f9ad1abcb0b1424d315b346af2e8ec57054ada5ddcc0ab1872d400956090fbf4b -DIST debian-kconfig-kernelarch-arm-5.10.13 2082 BLAKE2B 330b1d06e663ec20de70daf4d513f612366aa2e096c1a8f1cbdd93a86b32632c45060b1a3534fb29835baf1e908f346ef273606d82e5905fd49c26b8ca59941c SHA512 90f5ed4d96aa7a386ddf32c2cb58b0c36f85d99694d9f46ef2564dfe3deb94898585b6a899755afe4f78358d966730487d64730f3300f1b31cbe54246daa0128 -DIST debian-kconfig-kernelarch-arm-5.10.14 2082 BLAKE2B 330b1d06e663ec20de70daf4d513f612366aa2e096c1a8f1cbdd93a86b32632c45060b1a3534fb29835baf1e908f346ef273606d82e5905fd49c26b8ca59941c SHA512 90f5ed4d96aa7a386ddf32c2cb58b0c36f85d99694d9f46ef2564dfe3deb94898585b6a899755afe4f78358d966730487d64730f3300f1b31cbe54246daa0128 -DIST debian-kconfig-kernelarch-x86-5.10.13 40792 BLAKE2B 156921f8c394ad76e49216e83c7fba299cafa1e58655a3c7173ae8bd196fafe3227af872fc590a036d4b4959b06ab6d02e53d5730ad4ecc951d47fb52cb7dace SHA512 327574ed49d79089a505f1e8e3eb38e515fbe1e807120815aef4c858153a6ef77572a6a26b792a964c132f0ad704235005a95d3171246812e9622c4551aa9030 -DIST debian-kconfig-kernelarch-x86-5.10.14 40792 BLAKE2B 156921f8c394ad76e49216e83c7fba299cafa1e58655a3c7173ae8bd196fafe3227af872fc590a036d4b4959b06ab6d02e53d5730ad4ecc951d47fb52cb7dace SHA512 327574ed49d79089a505f1e8e3eb38e515fbe1e807120815aef4c858153a6ef77572a6a26b792a964c132f0ad704235005a95d3171246812e9622c4551aa9030 -DIST linux-5.10.13.tar.xz 116258488 BLAKE2B f2d6f5512c10ced0990d0d0cbc1aa29e5b54b90bff01f16d16093e9c192de9eb0f31e60c9dd51c686ce88c2a1d89a49bedb503af61c91a6a186794fbe71eedde SHA512 e894b9a98d34b0734ad87336530361b712ce60b57e47ea51e0efd66a4446e740b7e2bebc489e41e59523c0cc5f4066f36036eac2c4cfd7d99a63682c24d887be -DIST linux-5.10.14.tar.xz 116254224 BLAKE2B 34ba86c15532eff73ed3cd5d34bb125a534776425a98c43ceff187a9f950c4a12afbe35c5e63306150cdeff5d4e43c5094182d6533381661fe6e5ce82aeaed16 SHA512 8e5016bfc7f5c090af6247ddac41cb3f811576bd078b2e145d798be6f214f72ee77bbff09d48d54a0154a9b137166650c88a1d178d50d5901dcaa03bb2c5e6f1 -EBUILD cairn-sources-5.10.13.ebuild 28705 BLAKE2B 2eacea3d0d6773cfe9c22c1cd6f34e26c14558f88b227c29fbc139ce50f2871098ee11882777c6459eecf4370aa106e80e26e96e441c7ea1e25789a24c4b741a SHA512 a9c7b2548fb80a0d64ca886e2b0d576b59518f6add35b483bdb2a9cea44cc8e54a8bbd3039cf1c82a53d616483a357f5c9c7c3b8cb39343df031c25ad3a5be35 -EBUILD cairn-sources-5.10.14.ebuild 28803 BLAKE2B 1b3619fe2708a0247822e8f0f27f7c5f2856bbbc367438a21c64be7a94839fc2558640dce01e5bb2b1ef1a42c0e05644cc71b11db9fdf33dd14bbbb82031ff02 SHA512 6b406fab0e0ac34fd2e860cfb6c1a330bbf6110f04f9163da39455f302f67bf05c6e40247c10c9b5a10f51bbfa9f6e0601477490fbc6c8f260687c633f72471f diff --git a/sys-kernel/cairn-sources/cairn-sources-5.10.13.ebuild b/sys-kernel/cairn-sources/cairn-sources-5.10.13.ebuild deleted file mode 100644 index 2bcdb056c783..000000000000 --- a/sys-kernel/cairn-sources/cairn-sources-5.10.13.ebuild +++ /dev/null @@ -1,700 +0,0 @@ -# Distributed under the terms of the GNU General Public License v2 - -EAPI=7 - -inherit check-reqs eutils mount-boot toolchain-funcs - -DESCRIPTION="Linux kernel sources with some optional patches." -HOMEPAGE="https://kernel.org" - -LICENSE="GPL-2" -KEYWORDS="x86 amd64 arm arm64" - -SLOT="${PV}" - -RESTRICT="binchecks strip mirror" - -IUSE="binary btrfs clang custom-cflags debug dmraid dtrace ec2 firmware hardened iscsi luks lvm mcelog mdadm microcode multipath nbd nfs plymouth selinux sign-modules symlink systemd wireguard zfs" - -BDEPEND=" - sys-devel/bc - debug? ( dev-util/dwarves ) - virtual/libelf -" - -DEPEND=" - binary? ( sys-kernel/dracut ) - btrfs? ( sys-fs/btrfs-progs ) - dtrace? ( - dev-util/dtrace-utils - dev-libs/libdtrace-ctf - ) - firmware? ( - sys-kernel/linux-firmware - ) - luks? ( sys-fs/cryptsetup ) - lvm? ( sys-fs/lvm2 ) - mdadm? ( sys-fs/mdadm ) - mcelog? ( app-admin/mcelog ) - plymouth? ( - x11-libs/libdrm[libkms] - sys-boot/plymouth[libkms,udev] - ) - sign-modules? ( - || ( dev-libs/openssl - dev-libs/libressl - ) - sys-apps/kmod - ) - systemd? ( sys-apps/systemd ) - wireguard? ( virtual/wireguard ) - zfs? ( sys-fs/zfs ) -" - -# linux kernel upstream -KERNEL_VERSION="5.10.13" -KERNEL_ARCHIVE="linux-${KERNEL_VERSION}.tar.xz" -KERNEL_UPSTREAM="https://cdn.kernel.org/pub/linux/kernel/v5.x/${KERNEL_ARCHIVE}" -KERNEL_EXTRAVERSION="-cairn" - -KERNEL_CONFIG_UPSTREAM="https://salsa.debian.org/kernel-team/linux/-/raw/debian/5.10.12-1/debian/config" - -SRC_URI=" - ${KERNEL_UPSTREAM} - - ${KERNEL_CONFIG_UPSTREAM}/config -> debian-kconfig-${PV} - x86? ( - ${KERNEL_CONFIG_UPSTREAM}/i386/config -> debian-kconfig-i386-${PV} - ${KERNEL_CONFIG_UPSTREAM}/i386/config.686 -> debian-kconfig-i686-${PV} - ${KERNEL_CONFIG_UPSTREAM}/i386/config.686-pae -> debian-kconfig-i686-pae-${PV} - ${KERNEL_CONFIG_UPSTREAM}/kernelarch-x86/config -> debian-kconfig-kernelarch-x86-${PV} - ) - amd64? ( - ${KERNEL_CONFIG_UPSTREAM}/amd64/config -> debian-kconfig-amd64-${PV} - ${KERNEL_CONFIG_UPSTREAM}/kernelarch-x86/config -> debian-kconfig-kernelarch-x86-${PV} - ) - arm64? ( - ${KERNEL_CONFIG_UPSTREAM}/arm64/config -> debian-kconfig-arm64-${PV} - ${KERNEL_CONFIG_UPSTREAM}/kernelarch-arm/config -> debian-kconfig-kernelarch-arm-${PV} - ) -" - -S="$WORKDIR/linux-${KERNEL_VERSION}" - -# TODO: manage HARDENED_PATCHES and GENTOO_PATCHES -# can be managed in a git repository and packed into tar balls per version. - -HARDENED_PATCHES_DIR="${FILESDIR}/${KERNEL_VERSION}/hardened-patches" - -# 'linux-hardened' minimal patch set to compliment existing Kernel-Self-Protection-Project -# 0033-enable-protected_-symlinks-hardlinks-by-default.patch -# 0066-security-perf-Allow-further-restriction-of-perf_even.patch -# 0068-add-sysctl-to-disallow-unprivileged-CLONE_NEWUSER-by.patch -HARDENED_PATCHES=( - 0001-make-DEFAULT_MMAP_MIN_ADDR-match-LSM_MMAP_MIN_ADDR.patch - 0002-enable-HARDENED_USERCOPY-by-default.patch - 0003-disable-HARDENED_USERCOPY_FALLBACK-by-default.patch - 0004-enable-SECURITY_DMESG_RESTRICT-by-default.patch - 0005-set-kptr_restrict-2-by-default.patch - 0006-enable-DEBUG_LIST-by-default.patch - 0007-enable-BUG_ON_DATA_CORRUPTION-by-default.patch - 0008-enable-ARM64_SW_TTBR0_PAN-by-default.patch - 0009-arm64-enable-RANDOMIZE_BASE-by-default.patch - 0010-enable-SLAB_FREELIST_RANDOM-by-default.patch - 0011-enable-SLAB_FREELIST_HARDENED-by-default.patch - 0012-disable-SLAB_MERGE_DEFAULT-by-default.patch - 0013-enable-FORTIFY_SOURCE-by-default.patch - 0014-enable-PANIC_ON_OOPS-by-default.patch - 0015-stop-hiding-SLUB_DEBUG-behind-EXPERT.patch - 0016-stop-hiding-X86_16BIT-behind-EXPERT.patch - 0017-disable-X86_16BIT-by-default.patch - 0018-stop-hiding-MODIFY_LDT_SYSCALL-behind-EXPERT.patch - 0019-disable-MODIFY_LDT_SYSCALL-by-default.patch - 0020-set-LEGACY_VSYSCALL_NONE-by-default.patch - 0021-stop-hiding-AIO-behind-EXPERT.patch - 0022-disable-AIO-by-default.patch - 0023-remove-SYSVIPC-from-arm64-x86_64-defconfigs.patch - 0024-disable-DEVPORT-by-default.patch - 0025-disable-PROC_VMCORE-by-default.patch - 0026-disable-NFS_DEBUG-by-default.patch - 0027-enable-DEBUG_WX-by-default.patch - 0028-disable-LEGACY_PTYS-by-default.patch - 0029-disable-DEVMEM-by-default.patch - 0030-enable-IO_STRICT_DEVMEM-by-default.patch - 0031-disable-COMPAT_BRK-by-default.patch - 0032-use-maximum-supported-mmap-rnd-entropy-by-default.patch - 0033-enable-protected_-symlinks-hardlinks-by-default.patch - 0034-enable-SECURITY-by-default.patch - 0035-enable-SECURITY_YAMA-by-default.patch - 0036-enable-SECURITY_NETWORK-by-default.patch - 0037-enable-AUDIT-by-default.patch - 0038-enable-SECURITY_SELINUX-by-default.patch - 0039-enable-SYN_COOKIES-by-default.patch - 0040-enable-INIT_ON_ALLOC_DEFAULT_ON-by-default.patch - 0041-enable-INIT_ON_FREE_DEFAULT_ON-by-default.patch - 0042-kconfig-select-DEBUG_FS_ALLOW_NONE-by-default-if-DEB.patch - 0043-stop-hiding-SYSFS_SYSCALL-behind-EXPERT.patch - 0044-disable-SYSFS_SYSCALL-by-default.patch - 0045-stop-hiding-UID16-behind-EXPERT.patch - 0046-disable-UID16-by-default.patch - 0047-add-__read_only-for-non-init-related-usage.patch - 0048-make-sysctl-constants-read-only.patch - 0049-mark-kernel_set_to_readonly-as-__ro_after_init.patch - 0050-Revert-mark-kernel_set_to_readonly-as-__ro_after_ini.patch - 0051-mark-slub-runtime-configuration-as-__ro_after_init.patch - 0052-add-__ro_after_init-to-slab_nomerge-and-slab_state.patch - 0053-mark-kmem_cache-as-__ro_after_init.patch - 0054-mark-__supported_pte_mask-as-__ro_after_init.patch - 0055-mark-kobj_ns_type_register-as-only-used-for-init.patch - 0056-mark-open_softirq-as-only-used-for-init.patch - 0057-remove-unused-softirq_action-callback-parameter.patch - 0058-mark-softirq_vec-as-__ro_after_init.patch - 0059-mm-slab-trigger-BUG-if-requested-object-is-not-a-sla.patch - 0060-bug-on-kmem_cache_free-with-the-wrong-cache.patch - 0061-bug-on-PageSlab-PageCompound-in-ksize.patch - 0062-mm-add-support-for-verifying-page-sanitization.patch - 0063-slub-Extend-init_on_free-to-slab-caches-with-constru.patch - 0064-slub-Add-support-for-verifying-slab-sanitization.patch - 0065-slub-add-multi-purpose-random-canaries.patch - 0066-security-perf-Allow-further-restriction-of-perf_even.patch - 0067-enable-SECURITY_PERF_EVENTS_RESTRICT-by-default.patch - 0068-add-sysctl-to-disallow-unprivileged-CLONE_NEWUSER-by.patch - 0069-add-CONFIG-for-unprivileged_userns_clone.patch - 0070-add-kmalloc-krealloc-alloc_size-attributes.patch - 0071-add-vmalloc-alloc_size-attributes.patch - 0072-add-kvmalloc-alloc_size-attribute.patch - 0073-add-percpu-alloc_size-attributes.patch - 0074-add-alloc_pages_exact-alloc_size-attributes.patch - 0075-Add-the-extra_latent_entropy-kernel-parameter.patch - 0076-ata-avoid-null-pointer-dereference-on-bug.patch - 0077-sanity-check-for-negative-length-in-nla_memcpy.patch - 0078-add-page-destructor-sanity-check.patch - 0079-PaX-shadow-cr4-sanity-check-essentially-a-revert.patch - 0080-add-writable-function-pointer-detection.patch - 0081-support-overriding-early-audit-kernel-cmdline.patch - 0082-FORTIFY_SOURCE-intra-object-overflow-checking.patch - 0083-Revert-mm-revert-x86_64-and-arm64-ELF_ET_DYN_BASE-ba.patch - 0084-x86_64-move-vdso-to-mmap-region-from-stack-region.patch - 0085-x86-determine-stack-entropy-based-on-mmap-entropy.patch - 0086-arm64-determine-stack-entropy-based-on-mmap-entropy.patch - 0087-randomize-lower-bits-of-the-argument-block.patch - 0088-x86_64-match-arm64-brk-randomization-entropy.patch - 0089-support-randomizing-the-lower-bits-of-brk.patch - 0090-mm-randomize-lower-bits-of-brk.patch - 0091-x86-randomize-lower-bits-of-brk.patch - 0092-mm-guarantee-brk-gap-is-at-least-one-page.patch - 0093-x86-guarantee-brk-gap-is-at-least-one-page.patch - 0094-x86_64-bound-mmap-between-legacy-modern-bases.patch - 0095-restrict-device-timing-side-channels.patch - 0096-sysctl-expose-proc_dointvec_minmax_sysadmin-as-API-f.patch - 0097-usb-add-toggle-for-disabling-newly-added-USB-devices.patch - 0098-usb-implement-dedicated-subsystem-sysctl-tables.patch - 0099-hard-wire-legacy-checkreqprot-option-to-0.patch - 0100-security-tty-Add-owner-user-namespace-to-tty_struct.patch - 0101-security-tty-make-TIOCSTI-ioctl-require-CAP_SYS_ADMI.patch - 0102-enable-SECURITY_TIOCSTI_RESTRICT-by-default.patch - 0103-disable-unprivileged-eBPF-access-by-default.patch - 0104-enable-BPF-JIT-hardening-by-default-if-available.patch - 0105-enable-protected_-fifos-regular-by-default.patch - 0106-modpost-Add-CONFIG_DEBUG_WRITABLE_FUNCTION_POINTERS_.patch - 0107-mm-Fix-extra_latent_entropy.patch - 0108-add-CONFIG-for-unprivileged_userfaultfd.patch - 0109-slub-Extend-init_on_alloc-to-slab-caches-with-constr.patch - 0110-net-tcp-add-option-to-disable-TCP-simultaneous-conne.patch - 0111-dccp-ccid-move-timers-to-struct-dccp_sock.patch - 0112-Revert-dccp-don-t-free-ccid2_hc_tx_sock-struct-in-dc.patch -) - -GENTOO_PATCHES_DIR="${FILESDIR}/${KERNEL_VERSION}/gentoo-patches" - -# Gentoo Linux 'genpatches' patch set -# 1510_fs-enable-link-security-restrctions-by-default.patch is already provided in hardened patches -# 4567_distro-Gentoo-Kconfiig TODO? -GENTOO_PATCHES=( - 1500_XATTR_USER_PREFIX.patch -# 1510_fs-enable-link-security-restrictions-by-default.patch - 2000_BT-Check-key-sizes-only-if-Secure-Simple-Pairing-enabled.patch - 2900_tmp513-Fix-build-issue-by-selecting-CONFIG_REG.patch - 2920_sign-file-patch-for-libressl.patch -# 4567_distro-Gentoo-Kconfig.patch - 5000_shiftfs-ubuntu-20.04.patch -) - -DTRACE_PATCHES_DIR="${FILESDIR}/${KERNEL_VERSION}/dtrace-patches" - -DTRACE_PATCHES=( - 0001-ctf-generate-CTF-information-for-the-kernel.patch - 0002-kallsyms-introduce-new-proc-kallmodsyms-including-bu.patch - 0003-waitfd-new-syscall-implementing-waitpid-over-fds.patch - 0004-dtrace-core-and-x86.patch - 0005-dtrace-modular-components-and-x86-support.patch - 0006-dtrace-systrace-provider-core-components.patch - 0007-dtrace-systrace-provider.patch - 0008-dtrace-sdt-provider-core-components.patch - 0009-dtrace-sdt-provider-for-x86.patch - 0010-dtrace-profile-provider-and-test-probe-core-componen.patch - 0011-dtrace-profile-and-tick-providers-built-on-cyclics.patch - 0012-dtrace-USDT-and-pid-provider-core-and-x86-components.patch - 0013-dtrace-USDT-and-pid-providers.patch - 0014-dtrace-function-boundary-tracing-FBT-core-and-x86-co.patch - 0015-dtrace-fbt-provider-modular-components.patch - 0016-dtrace-arm-arm64-port.patch - 0017-dtrace-add-SDT-probes.patch - 0018-dtrace-add-sample-script-for-building-DTrace-on-Fedo.patch - 0019-locking-publicize-mutex_owner-and-mutex_owned-again.patch -) - -get_certs_dir() { - # find a certificate dir in /etc/kernel/certs/ that contains signing cert for modules. - for subdir in $PF $P linux; do - certdir=/etc/kernel/certs/$subdir - if [ -d $certdir ]; then - if [ ! -e $certdir/signing_key.pem ]; then - eerror "$certdir exists but missing signing key; exiting." - exit 1 - fi - echo $certdir - return - fi - done -} - -pkg_pretend() { - # Ensure we have enough disk space to compile - if use binary ; then - CHECKREQS_DISK_BUILD="5G" - check-reqs_pkg_setup - fi -} - -pkg_setup() { - export REAL_ARCH="$ARCH" - unset ARCH; unset LDFLAGS #will interfere with Makefile if set -} - -src_unpack() { - - # unpack the kernel sources to ${WORKDIR} - unpack ${KERNEL_ARCHIVE} || die "failed to unpack kernel sources" - - # unpack the various kconfig files into a single file - cat "${DISTDIR}"/debian-kconfig-* >> "${WORKDIR}"/debian-kconfig-${PV} || die "failed to unpack kconfig" -} - -src_prepare() { - - ### PATCHES ### - - # only apply these if USE=hardened as the patches will break proprietary userspace and some others. - if use hardened; then - # apply hardening patches - einfo "Applying hardening patches ..." - for my_patch in ${HARDENED_PATCHES[*]} ; do - eapply "${HARDENED_PATCHES_DIR}/${my_patch}" || die "failed to apply hardened patches" - done - fi - - # apply gentoo patches - einfo "Applying Gentoo Linux patches ..." - for my_patch in ${GENTOO_PATCHES[*]} ; do - eapply "${GENTOO_PATCHES_DIR}/${my_patch}" || die "failed to apply Gentoo Linux patches" - done - - # apply DTrace patches - einfo "Applying DTrace patches ..." - for my_patch in ${DTRACE_PATCHES[*]} ; do - eapply "${DTRACE_PATCHES_DIR}/${my_patch}" || die "failed to apply DTrace patches" - done - - if ! use hardened; then - eapply "${FILESDIR}"/${KERNEL_VERSION}/gentoo-patches/1510_fs-enable-link-security-restrictions-by-default.patch - fi - - # append EXTRAVERSION to the kernel sources Makefile - sed -i -e "s:^\(EXTRAVERSION =\).*:\1 ${KERNEL_EXTRAVERSION}:" Makefile || die "failed to append EXTRAVERSION to kernel Makefile" - - # todo: look at this, haven't seen it used in many cases. - sed -i -e 's:#export\tINSTALL_PATH:export\tINSTALL_PATH:' Makefile || die "failed to fix-up INSTALL_PATH in kernel Makefile" - - # copy the kconfig file into the kernel sources tree - cp "${WORKDIR}"/debian-kconfig-${PV} "${S}"/.config - - ### TWEAK CONFIG ### - - # Do not configure Debian devs certificates - echo 'CONFIG_SYSTEM_TRUSTED_KEYS=""' >> .config - - # enable IKCONFIG so that /proc/config.gz can be used for various checks - # TODO: Maybe not a good idea for USE=hardened, look into this... - echo "CONFIG_IKCONFIG=y" >> .config - echo "CONFIG_IKCONFIG_PROC=y" >> .config - - if use custom-cflags; then - MARCH="$(python -c "import portage; print(portage.settings[\"CFLAGS\"])" | sed 's/ /\n/g' | grep "march")" - if [ -n "$MARCH" ]; then - sed -i -e 's/-mtune=generic/$MARCH/g' arch/x86/Makefile || die "Canna optimize this kernel anymore, captain!" - fi - fi - - # only enable debugging symbols etc if USE=debug... - if use debug; then - echo "CONFIG_DEBUG_INFO=y" >> .config - else - echo "CONFIG_DEBUG_INFO=n" >> .config - fi - - if use dtrace; then - echo "CONFIG_DTRACE=y" >> .config - echo "CONFIG_DT_CORE=m" >> .config - echo "CONFIG_DT_FASTTRAP=m" >> .config - echo "CONFIG_DT_PROFILE=m" >> .config - echo "CONFIG_DT_SDT=m" >> .config - echo "CONFIG_DT_SDT_PERF=y" >> .config - echo "CONFIG_DT_FBT=m" >> .config - echo "CONFIG_DT_SYSTRACE=m" >> .config - echo "CONFIG_DT_DT_TEST=m" >> .config - echo "CONFIG_DT_DT_PERF=m" >> .config - echo "CONFIG_DT_DEBUG=n" >> .config - echo "CONFIG_WAITFD=y" >> .config - fi - - # these options should already be set, but are a hard dependency for ec2, so we ensure they are set if USE=ec2 - if use ec2; then - echo "CONFIG_BLK_DEV_NVME=y" >> .config - echo "CONFIG_XEN_BLKDEV_FRONTEND=m" >> .config - echo "CONFIG_XEN_BLKDEV_BACKEND=m" >> .config - echo "CONFIG_IXGBEVF=m" >> .config - fi - - # hardening opts - # TODO: document these - if use hardened; then - echo "CONFIG_AUDIT=y" >> .config - echo "CONFIG_EXPERT=y" >> .config - echo "CONFIG_SLUB_DEBUG=y" >> .config - echo "CONFIG_SLAB_MERGE_DEFAULT=n" >> .config - echo "CONFIG_SLAB_FREELIST_RANDOM=y" >> .config - echo "CONFIG_SLAB_FREELIST_HARDENED=y" >> .config - echo "CONFIG_SLAB_CANARY=y" >> .config - echo "CONFIG_SHUFFLE_PAGE_ALLOCATOR=y" >> .config - echo "CONFIG_RANDOMIZE_BASE=y" >> .config - echo "CONFIG_RANDOMIZE_MEMORY=y" >> .config - echo "CONFIG_HIBERNATION=n" >> .config - echo "CONFIG_HARDENED_USERCOPY=y" >> .config - echo "CONFIG_HARDENED_USERCOPY_FALLBACK=n" >> .config - echo "CONFIG_FORTIFY_SOURCE=y" >> .config - echo "CONFIG_STACKPROTECTOR=y" >> .config - echo "CONFIG_STACKPROTECTOR_STRONG=y" >> .config - echo "CONFIG_ARCH_MMAP_RND_BITS=32" >> .config - echo "CONFIG_ARCH_MMAP_RND_COMPAT_BITS=16" >> .config - echo "CONFIG_INIT_ON_FREE_DEFAULT_ON=y" >> .config - echo "CONFIG_INIT_ON_ALLOC_DEFAULT_ON=y" >> .config - echo "CONFIG_SLAB_SANITIZE_VERIFY=y" >> .config - echo "CONFIG_PAGE_SANITIZE_VERIFY=y" >> .config - - # gcc plugins - if ! use clang; then - echo "CONFIG_GCC_PLUGINS=y" >> .config - echo "CONFIG_GCC_PLUGIN_LATENT_ENTROPY=y" >> .config - echo "CONFIG_GCC_PLUGIN_STRUCTLEAK=y" >> .config - echo "CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF_ALL=y" >> .config - echo "CONFIG_GCC_PLUGIN_STACKLEAK=y" >> .config - echo "CONFIG_STACKLEAK_TRACK_MIN_SIZE=100" >> .config - echo "CONFIG_STACKLEAK_METRICS=n" >> .config - echo "CONFIG_STACKLEAK_RUNTIME_DISABLE=n" >> .config - echo "CONFIG_GCC_PLUGIN_RANDSTRUCT=y" >> .config - echo "CONFIG_GCC_PLUGIN_RANDSTRUCT_PERFORMANCE=n" >> .config - fi - - # main hardening options complete... anything after this point is a focus on disabling potential attack vectors - # i.e legacy drivers, new complex code that isn't yet proven, or code that we really don't want in a hardened kernel. - echo 'CONFIG_KEXEC=n' >> .config - echo "CONFIG_KEXEC_FILE=n" >> .config - echo 'CONFIG_KEXEC_SIG=n' >> .config - fi - - # mcelog is deprecated, but there are still some valid use cases and requirements for it... so stick it behind a USE flag for optional kernel support. - if use mcelog; then - echo "CONFIG_X86_MCELOG_LEGACY=y" >> .config - fi - - # sign kernel modules via - if use sign-modules; then - certs_dir=$(get_certs_dir) - echo - if [ -z "$certs_dir" ]; then - eerror "No certs dir found in /etc/kernel/certs; aborting." - die - else - einfo "Using certificate directory of $certs_dir for kernel module signing." - fi - echo - # turn on options for signing modules. - # first, remove existing configs and comments: - echo 'CONFIG_MODULE_SIG=""' >> .config - - # now add our settings: - echo 'CONFIG_MODULE_SIG=y' >> .config - echo 'CONFIG_MODULE_SIG_FORCE=n' >> .config - echo 'CONFIG_MODULE_SIG_ALL=n' >> .config - echo 'CONFIG_MODULE_SIG_HASH="sha512"' >> .config - echo 'CONFIG_MODULE_SIG_KEY="${certs_dir}/signing_key.pem"' >> .config - echo 'CONFIG_SYSTEM_TRUSTED_KEYRING=y' >> .config - echo 'CONFIG_SYSTEM_EXTRA_CERTIFICATE=y' >> .config - echo 'CONFIG_SYSTEM_EXTRA_CERTIFICATE_SIZE="4096"' >> .config - echo "CONFIG_MODULE_SIG_SHA512=y" >> .config - - # print some info to warn user - ewarn "This kernel will ALLOW non-signed modules to be loaded with a WARNING." - ewarn "To enable strict enforcement, YOU MUST add module.sig_enforce=1 as a kernel boot" - ewarn "parameter (to params in /etc/boot.conf, and re-run boot-update.)" - echo - fi - - # enable wireguard support within kernel - if use wireguard; then - echo 'CONFIG_WIREGUARD=m' >> .config - # there are some other options, but I need to verify them first, so I'll start with this - fi - - # get config into good state: - yes "" | make oldconfig >/dev/null 2>&1 || die - cp .config "${T}"/.config || die - make -s mrproper || die "make mrproper failed" - - # Apply any user patches - eapply_user -} - -src_configure() { - - if use binary; then - - tc-export_build_env - MAKEARGS=( - V=1 - - HOSTCC="$(tc-getBUILD_CC)" - HOSTCXX="$(tc-getBUILD_CXX)" - HOSTCFLAGS="${BUILD_CFLAGS}" - HOSTLDFLAGS="${BUILD_LDFLAGS}" - - CROSS_COMPILE=${CHOST}- - AS="$(tc-getAS)" - CC="$(tc-getCC)" - LD="$(tc-getLD)" - AR="$(tc-getAR)" - NM="$(tc-getNM)" - STRIP=":" - OBJCOPY="$(tc-getOBJCOPY)" - OBJDUMP="$(tc-getOBJDUMP)" - - # we need to pass it to override colliding Gentoo envvar - ARCH=$(tc-arch-kernel) - ) - - mkdir -p "${WORKDIR}"/modprep || die - cp "${T}"/.config "${WORKDIR}"/modprep/ || die - emake O="${WORKDIR}"/modprep "${MAKEARGS[@]}" olddefconfig || die "kernel configure failed" - emake O="${WORKDIR}"/modprep "${MAKEARGS[@]}" modules_prepare || die "modules_prepare failed" - cp -pR "${WORKDIR}"/modprep "${WORKDIR}"/build || die - fi -} - -src_compile() { - - if use binary; then - - emake O="${WORKDIR}"/build "${MAKEARGS[@]}" all || "kernel build failed" - fi -} - -src_install() { - - # TODO: Change to SANDBOX_WRITE=".." for installkernel writes - # Disable sandbox - export SANDBOX_ON=0 - - # create sources directory if required - dodir /usr/src - - # copy kernel sources into place - cp -a "${S}" "${D}"/usr/src/linux-${PV}${KERNEL_EXTRAVERSION} || die "failed to install kernel sources" - - # change to installed kernel sources directory - cd "${D}"/usr/src/linux-${PV}${KERNEL_EXTRAVERSION} - - # prepare for real-world use and 3rd-party module building: - make mrproper || die "failed to prepare kernel sources" - - # copy kconfig into place - cp "${T}"/.config .config || die "failed to copy kconfig from ${TEMPDIR}" - - # if we didn't USE=binary - we're done. - # The kernel source tree is left in an unconfigured state - you can't compile 3rd-party modules against it yet. - if use binary; then - make prepare || die - make scripts || die - - local targets=( modules_install ) - - # ARM / ARM64 requires dtb - if (use arm || use arm64); then - targets+=( dtbs_install ) - fi - - emake O="${WORKDIR}"/build "${MAKEARGS[@]}" INSTALL_MOD_PATH="${ED}" INSTALL_PATH="${ED}/boot" "${targets[@]}" - installkernel "${PV}${KERNEL_EXTRAVERSION}" "${WORKDIR}/build/arch/x86_64/boot/bzImage" "${WORKDIR}/build/System.map" "${EROOT}/boot" - - # module symlink fix-up: - rm -rf "${D}"/lib/modules/${PV}${KERNEL_EXTRAVERSION}/source || die "failed to remove old kernel source symlink" - rm -rf "${D}"/lib/modules/${PV}${KERNEL_EXTRAVERSION}/build || die "failed to remove old kernel build symlink" - - # Set-up module symlinks: - ln -s /usr/src/linux-${PV}${KERNEL_EXTRAVERSION} "${ED}"/lib/modules/${PV}${KERNEL_EXTRAVERSION}/source || die "failed to create kernel source symlink" - ln -s /usr/src/linux-${PV}${KERNEL_EXTRAVERSION} "${ED}"/lib/modules/${PV}${KERNEL_EXTRAVERSION}/build || die "failed to create kernel build symlink" - - # Fixes FL-14 - cp "${WORKDIR}/build/System.map" "${D}"/usr/src/linux-${PV}${KERNEL_EXTRAVERSION}/ || die "failed to install System.map" - cp "${WORKDIR}/build/Module.symvers" "${D}"/usr/src/linux-${PV}${KERNEL_EXTRAVERSION}/ || die "failed to install Module.symvers" - - if use sign-modules; then - for x in $(find "${D}"/lib/modules -iname *.ko); do - # $certs_dir defined previously in this function. - ${WORKDIR}/build/scripts/sign-file sha512 $certs_dir/signing_key.pem $certs_dir/signing_key.x509 $x || die - done - # install the sign-file executable for future use. - exeinto /usr/src/linux-${PV}-${KERNEL_EXTRAVERSION}/scripts - doexe ${WORKDIR}/build/scripts/sign-file - fi - fi -} - -pkg_postinst() { - - # TODO: Change to SANDBOX_WRITE=".." for Dracut writes - export SANDBOX_ON=0 - - # if USE=symlink... - if use symlink; then - # delete the existing symlink if one exists - if [[ -h "${EROOT}"/usr/src/linux ]]; then - rm "${EROOT}"/usr/src/linux - fi - # and now symlink the newly installed sources - ewarn "" - ewarn "WARNING... WARNING... WARNING" - ewarn "" - ewarn "/usr/src/linux symlink automatically set to linux-${PV}${KERNEL_EXTRAVERSION}" - ewarn "" - ln -sf "${EROOT}"/usr/src/linux-${PV}${KERNEL_EXTRAVERSION} "${EROOT}"/usr/src/linux - fi - - # if there's a modules folder for these sources, generate modules.dep and map files - if [[ -d ${EROOT}/lib/modules/${PV}${KERNEL_EXTRAVERSION} ]]; then - depmod -a ${PV}${KERNEL_EXTRAVERSION} - fi - - # NOTE: WIP and not well tested yet. - # - # Dracut will build an initramfs when USE=binary. - # - # The initramfs will be configurable via USE, i.e. - # USE=zfs will pass '--zfs' to Dracut - # USE=-systemd will pass '--omit dracut-systemd systemd systemd-networkd systemd-initrd' to exclude these (Dracut) modules from the initramfs. - # - # NOTE 2: this will create a fairly.... minimal, and modular initramfs. It has been tested with things with ZFS and LUKS, and 'works'. - # Things like network support have not been tested (I am currently unsure how well this works with Gentoo Linux based systems), - # and may end up requiring network-manager for decent support (this really needs further research). - if use binary; then - einfo "" - einfo ">>> Dracut: building initramfs" - dracut \ - --stdlog=1 \ - --force \ - --no-hostonly \ - --add "base dm fs-lib i18n kernel-modules rootfs-block shutdown terminfo udev-rules usrmount" \ - --omit "biosdevname bootchart busybox caps convertfs dash debug dmsquash-live dmsquash-live-ntfs fcoe fcoe-uefi fstab-sys gensplash ifcfg img-lib livenet mksh network network-manager qemu qemu-net rpmversion securityfs ssh-client stratis syslog url-lib" \ - $(usex btrfs "-a btrfs" "-o btrfs") \ - $(usex dmraid "-a dmraid" "-o dmraid") \ - $(usex hardened "-o resume" "-a resume") \ - $(usex iscsi "-a iscsi" "-o iscsi") \ - $(usex lvm "-a lvm" "-o lvm") \ - $(usex lvm "--lvmconf" "--nolvmconf") \ - $(usex luks "-a crypt" "-o crypt") \ - $(usex mdadm "--mdadmconf" "--nomdadmconf") \ - $(usex mdadm "-a mdraid" "-o mdraid") \ - $(usex microcode "--early-microcode" "--no-early-microcode") \ - $(usex multipath "-a multipath" "-o multipath") \ - $(usex nbd "-a nbd" "-o nbd") \ - $(usex nfs "-a nfs" "-o nfs") \ - $(usex plymouth "-a plymouth" "-o plymouth") \ - $(usex selinux "-a selinux" "-o selinux") \ - $(usex systemd "-a systemd -a systemd-initrd -a systemd-networkd" "-o systemd -o systemd-initrd -o systemd-networkd") \ - $(usex zfs "-a zfs" "-o zfs") \ - --kver ${PV}${KERNEL_EXTRAVERSION} \ - --kmoddir ${EROOT}/lib/modules/${PV}${KERNEL_EXTRAVERSION} \ - --fwdir ${EROOT}/lib/firmware \ - --kernel-image ${EROOT}/boot/vmlinuz-${PV}${KERNEL_EXTRAVERSION} - einfo "" - einfo ">>> Dracut: Finished building initramfs" - ewarn "" - ewarn "WARNING... WARNING... WARNING..." - ewarn "" - ewarn "Dracut initramfs has been generated!" - ewarn "" - ewarn "Required kernel arguments:" - ewarn "" - ewarn " root=/dev/ROOT" - ewarn "" - ewarn " Where ROOT is the device node for your root partition as the" - ewarn " one specified in /etc/fstab" - ewarn "" - ewarn "Additional kernel cmdline arguments that *may* be required to boot properly..." - ewarn "" - ewarn "If you use hibernation:" - ewarn "" - ewarn " resume=/dev/SWAP" - ewarn "" - ewarn " Where $SWAP is the swap device used by hibernate software of your choice." - ewarn"" - ewarn " Please consult "man 7 dracut.kernel" for additional kernel arguments." - fi - - # warn about the issues with running a hardened kernel - if use hardened; then - ewarn "" - ewarn "WARNING... WARNING... WARNING..." - ewarn "" - ewarn "Hardened patches have been applied to the kernel and KCONFIG options have been set." - ewarn "These KCONFIG options and patches change kernel behavior." - ewarn "Changes include:" - ewarn "Increased entropy for Address Space Layout Randomization" - ewarn "GCC plugins (if using GCC)" - ewarn "Memory allocation" - ewarn "... and more" - ewarn "" - ewarn "These changes will stop certain programs from functioning" - ewarn "e.g. VirtualBox, Skype" - ewarn "Full information available in $DOCUMENTATION" - ewarn "" - fi - - # if there are out-of-tree kernel modules detected, warn warn warn - # TODO: tidy up below - if use binary && [[ -e "${EROOT}"/var/lib/module-rebuild/moduledb ]]; then - ewarn "" - ewarn "WARNING... WARNING... WARNING..." - ewarn "" - ewarn "External kernel modules are not yet automatically built" - ewarn "by USE=binary - emerge @modules-rebuild to do this" - ewarn "and regenerate your initramfs if you are using ZFS root filesystem" - ewarn "" - fi - - if use binary; then - if [[ -e /etc/boot.conf ]]; then - ego boot update - fi - fi -} diff --git a/sys-kernel/cairn-sources/cairn-sources-5.10.14.ebuild b/sys-kernel/cairn-sources/cairn-sources-5.10.14.ebuild deleted file mode 100644 index 38da68c76efe..000000000000 --- a/sys-kernel/cairn-sources/cairn-sources-5.10.14.ebuild +++ /dev/null @@ -1,703 +0,0 @@ -# Distributed under the terms of the GNU General Public License v2 - -EAPI=7 - -inherit check-reqs eutils mount-boot toolchain-funcs - -DESCRIPTION="Linux kernel sources with some optional patches." -HOMEPAGE="https://kernel.org" - -LICENSE="GPL-2" -KEYWORDS="x86 amd64 arm arm64" - -SLOT="${PV}" - -RESTRICT="binchecks strip mirror" - -IUSE="binary btrfs clang custom-cflags debug dmraid dtrace ec2 firmware hardened iscsi luks lvm mcelog mdadm microcode multipath nbd nfs plymouth selinux sign-modules symlink systemd wireguard zfs" - -BDEPEND=" - sys-devel/bc - debug? ( dev-util/dwarves ) - virtual/libelf -" - -DEPEND=" - binary? ( sys-kernel/dracut ) - btrfs? ( sys-fs/btrfs-progs ) - dtrace? ( - dev-util/dtrace-utils - dev-libs/libdtrace-ctf - ) - firmware? ( - sys-kernel/linux-firmware - ) - luks? ( sys-fs/cryptsetup ) - lvm? ( sys-fs/lvm2 ) - mdadm? ( sys-fs/mdadm ) - mcelog? ( app-admin/mcelog ) - plymouth? ( - x11-libs/libdrm[libkms] - sys-boot/plymouth[libkms,udev] - ) - sign-modules? ( - || ( dev-libs/openssl - dev-libs/libressl - ) - sys-apps/kmod - ) - systemd? ( sys-apps/systemd ) - wireguard? ( virtual/wireguard ) - zfs? ( sys-fs/zfs ) -" - -# linux kernel upstream -KERNEL_VERSION="5.10.14" -KERNEL_ARCHIVE="linux-${KERNEL_VERSION}.tar.xz" -KERNEL_UPSTREAM="https://cdn.kernel.org/pub/linux/kernel/v5.x/${KERNEL_ARCHIVE}" -KERNEL_EXTRAVERSION="-cairn" - -KERNEL_CONFIG_UPSTREAM="https://salsa.debian.org/kernel-team/linux/-/raw/debian/5.10.13-1/debian/config" - -SRC_URI=" - ${KERNEL_UPSTREAM} - - ${KERNEL_CONFIG_UPSTREAM}/config -> debian-kconfig-${PV} - x86? ( - ${KERNEL_CONFIG_UPSTREAM}/i386/config -> debian-kconfig-i386-${PV} - ${KERNEL_CONFIG_UPSTREAM}/i386/config.686 -> debian-kconfig-i686-${PV} - ${KERNEL_CONFIG_UPSTREAM}/i386/config.686-pae -> debian-kconfig-i686-pae-${PV} - ${KERNEL_CONFIG_UPSTREAM}/kernelarch-x86/config -> debian-kconfig-kernelarch-x86-${PV} - ) - amd64? ( - ${KERNEL_CONFIG_UPSTREAM}/amd64/config -> debian-kconfig-amd64-${PV} - ${KERNEL_CONFIG_UPSTREAM}/kernelarch-x86/config -> debian-kconfig-kernelarch-x86-${PV} - ) - arm64? ( - ${KERNEL_CONFIG_UPSTREAM}/arm64/config -> debian-kconfig-arm64-${PV} - ${KERNEL_CONFIG_UPSTREAM}/kernelarch-arm/config -> debian-kconfig-kernelarch-arm-${PV} - ) -" - -S="$WORKDIR/linux-${KERNEL_VERSION}" - -# TODO: manage HARDENED_PATCHES and GENTOO_PATCHES -# can be managed in a git repository and packed into tar balls per version. - -HARDENED_PATCHES_DIR="${FILESDIR}/${KERNEL_VERSION}/hardened-patches" - -# 'linux-hardened' minimal patch set to compliment existing Kernel-Self-Protection-Project -# 0033-enable-protected_-symlinks-hardlinks-by-default.patch -# 0066-security-perf-Allow-further-restriction-of-perf_even.patch -# 0068-add-sysctl-to-disallow-unprivileged-CLONE_NEWUSER-by.patch -HARDENED_PATCHES=( - 0001-make-DEFAULT_MMAP_MIN_ADDR-match-LSM_MMAP_MIN_ADDR.patch - 0002-enable-HARDENED_USERCOPY-by-default.patch - 0003-disable-HARDENED_USERCOPY_FALLBACK-by-default.patch - 0004-enable-SECURITY_DMESG_RESTRICT-by-default.patch - 0005-set-kptr_restrict-2-by-default.patch - 0006-enable-DEBUG_LIST-by-default.patch - 0007-enable-BUG_ON_DATA_CORRUPTION-by-default.patch - 0008-enable-ARM64_SW_TTBR0_PAN-by-default.patch - 0009-arm64-enable-RANDOMIZE_BASE-by-default.patch - 0010-enable-SLAB_FREELIST_RANDOM-by-default.patch - 0011-enable-SLAB_FREELIST_HARDENED-by-default.patch - 0012-disable-SLAB_MERGE_DEFAULT-by-default.patch - 0013-enable-FORTIFY_SOURCE-by-default.patch - 0014-enable-PANIC_ON_OOPS-by-default.patch - 0015-stop-hiding-SLUB_DEBUG-behind-EXPERT.patch - 0016-stop-hiding-X86_16BIT-behind-EXPERT.patch - 0017-disable-X86_16BIT-by-default.patch - 0018-stop-hiding-MODIFY_LDT_SYSCALL-behind-EXPERT.patch - 0019-disable-MODIFY_LDT_SYSCALL-by-default.patch - 0020-set-LEGACY_VSYSCALL_NONE-by-default.patch - 0021-stop-hiding-AIO-behind-EXPERT.patch - 0022-disable-AIO-by-default.patch - 0023-remove-SYSVIPC-from-arm64-x86_64-defconfigs.patch - 0024-disable-DEVPORT-by-default.patch - 0025-disable-PROC_VMCORE-by-default.patch - 0026-disable-NFS_DEBUG-by-default.patch - 0027-enable-DEBUG_WX-by-default.patch - 0028-disable-LEGACY_PTYS-by-default.patch - 0029-disable-DEVMEM-by-default.patch - 0030-enable-IO_STRICT_DEVMEM-by-default.patch - 0031-disable-COMPAT_BRK-by-default.patch - 0032-use-maximum-supported-mmap-rnd-entropy-by-default.patch - 0033-enable-protected_-symlinks-hardlinks-by-default.patch - 0034-enable-SECURITY-by-default.patch - 0035-enable-SECURITY_YAMA-by-default.patch - 0036-enable-SECURITY_NETWORK-by-default.patch - 0037-enable-AUDIT-by-default.patch - 0038-enable-SECURITY_SELINUX-by-default.patch - 0039-enable-SYN_COOKIES-by-default.patch - 0040-enable-INIT_ON_ALLOC_DEFAULT_ON-by-default.patch - 0041-enable-INIT_ON_FREE_DEFAULT_ON-by-default.patch - 0042-kconfig-select-DEBUG_FS_ALLOW_NONE-by-default-if-DEB.patch - 0043-stop-hiding-SYSFS_SYSCALL-behind-EXPERT.patch - 0044-disable-SYSFS_SYSCALL-by-default.patch - 0045-stop-hiding-UID16-behind-EXPERT.patch - 0046-disable-UID16-by-default.patch - 0047-add-__read_only-for-non-init-related-usage.patch - 0048-make-sysctl-constants-read-only.patch - 0049-mark-kernel_set_to_readonly-as-__ro_after_init.patch - 0050-Revert-mark-kernel_set_to_readonly-as-__ro_after_ini.patch - 0051-mark-slub-runtime-configuration-as-__ro_after_init.patch - 0052-add-__ro_after_init-to-slab_nomerge-and-slab_state.patch - 0053-mark-kmem_cache-as-__ro_after_init.patch - 0054-mark-__supported_pte_mask-as-__ro_after_init.patch - 0055-mark-kobj_ns_type_register-as-only-used-for-init.patch - 0056-mark-open_softirq-as-only-used-for-init.patch - 0057-remove-unused-softirq_action-callback-parameter.patch - 0058-mark-softirq_vec-as-__ro_after_init.patch - 0059-mm-slab-trigger-BUG-if-requested-object-is-not-a-sla.patch - 0060-bug-on-kmem_cache_free-with-the-wrong-cache.patch - 0061-bug-on-PageSlab-PageCompound-in-ksize.patch - 0062-mm-add-support-for-verifying-page-sanitization.patch - 0063-slub-Extend-init_on_free-to-slab-caches-with-constru.patch - 0064-slub-Add-support-for-verifying-slab-sanitization.patch - 0065-slub-add-multi-purpose-random-canaries.patch - 0066-security-perf-Allow-further-restriction-of-perf_even.patch - 0067-enable-SECURITY_PERF_EVENTS_RESTRICT-by-default.patch - 0068-add-sysctl-to-disallow-unprivileged-CLONE_NEWUSER-by.patch - 0069-add-CONFIG-for-unprivileged_userns_clone.patch - 0070-add-kmalloc-krealloc-alloc_size-attributes.patch - 0071-add-vmalloc-alloc_size-attributes.patch - 0072-add-kvmalloc-alloc_size-attribute.patch - 0073-add-percpu-alloc_size-attributes.patch - 0074-add-alloc_pages_exact-alloc_size-attributes.patch - 0075-Add-the-extra_latent_entropy-kernel-parameter.patch - 0076-ata-avoid-null-pointer-dereference-on-bug.patch - 0077-sanity-check-for-negative-length-in-nla_memcpy.patch - 0078-add-page-destructor-sanity-check.patch - 0079-PaX-shadow-cr4-sanity-check-essentially-a-revert.patch - 0080-add-writable-function-pointer-detection.patch - 0081-support-overriding-early-audit-kernel-cmdline.patch - 0082-FORTIFY_SOURCE-intra-object-overflow-checking.patch - 0083-Revert-mm-revert-x86_64-and-arm64-ELF_ET_DYN_BASE-ba.patch - 0084-x86_64-move-vdso-to-mmap-region-from-stack-region.patch - 0085-x86-determine-stack-entropy-based-on-mmap-entropy.patch - 0086-arm64-determine-stack-entropy-based-on-mmap-entropy.patch - 0087-randomize-lower-bits-of-the-argument-block.patch - 0088-x86_64-match-arm64-brk-randomization-entropy.patch - 0089-support-randomizing-the-lower-bits-of-brk.patch - 0090-mm-randomize-lower-bits-of-brk.patch - 0091-x86-randomize-lower-bits-of-brk.patch - 0092-mm-guarantee-brk-gap-is-at-least-one-page.patch - 0093-x86-guarantee-brk-gap-is-at-least-one-page.patch - 0094-x86_64-bound-mmap-between-legacy-modern-bases.patch - 0095-restrict-device-timing-side-channels.patch - 0096-sysctl-expose-proc_dointvec_minmax_sysadmin-as-API-f.patch - 0097-usb-add-toggle-for-disabling-newly-added-USB-devices.patch - 0098-usb-implement-dedicated-subsystem-sysctl-tables.patch - 0099-hard-wire-legacy-checkreqprot-option-to-0.patch - 0100-security-tty-Add-owner-user-namespace-to-tty_struct.patch - 0101-security-tty-make-TIOCSTI-ioctl-require-CAP_SYS_ADMI.patch - 0102-enable-SECURITY_TIOCSTI_RESTRICT-by-default.patch - 0103-disable-unprivileged-eBPF-access-by-default.patch - 0104-enable-BPF-JIT-hardening-by-default-if-available.patch - 0105-enable-protected_-fifos-regular-by-default.patch - 0106-modpost-Add-CONFIG_DEBUG_WRITABLE_FUNCTION_POINTERS_.patch - 0107-mm-Fix-extra_latent_entropy.patch - 0108-add-CONFIG-for-unprivileged_userfaultfd.patch - 0109-slub-Extend-init_on_alloc-to-slab-caches-with-constr.patch - 0110-net-tcp-add-option-to-disable-TCP-simultaneous-conne.patch - 0111-dccp-ccid-move-timers-to-struct-dccp_sock.patch - 0112-Revert-dccp-don-t-free-ccid2_hc_tx_sock-struct-in-dc.patch -) - -GENTOO_PATCHES_DIR="${FILESDIR}/${KERNEL_VERSION}/gentoo-patches" - -# Gentoo Linux 'genpatches' patch set -# 1510_fs-enable-link-security-restrctions-by-default.patch is already provided in hardened patches -# 4567_distro-Gentoo-Kconfiig TODO? -GENTOO_PATCHES=( - 1500_XATTR_USER_PREFIX.patch -# 1510_fs-enable-link-security-restrictions-by-default.patch - 2000_BT-Check-key-sizes-only-if-Secure-Simple-Pairing-enabled.patch - 2900_tmp513-Fix-build-issue-by-selecting-CONFIG_REG.patch - 2920_sign-file-patch-for-libressl.patch -# 4567_distro-Gentoo-Kconfig.patch - 5000_shiftfs-ubuntu-20.04.patch -) - -DTRACE_PATCHES_DIR="${FILESDIR}/${KERNEL_VERSION}/dtrace-patches" - -DTRACE_PATCHES=( - 0001-ctf-generate-CTF-information-for-the-kernel.patch - 0002-kallsyms-introduce-new-proc-kallmodsyms-including-bu.patch - 0003-waitfd-new-syscall-implementing-waitpid-over-fds.patch - 0004-dtrace-core-and-x86.patch - 0005-dtrace-modular-components-and-x86-support.patch - 0006-dtrace-systrace-provider-core-components.patch - 0007-dtrace-systrace-provider.patch - 0008-dtrace-sdt-provider-core-components.patch - 0009-dtrace-sdt-provider-for-x86.patch - 0010-dtrace-profile-provider-and-test-probe-core-componen.patch - 0011-dtrace-profile-and-tick-providers-built-on-cyclics.patch - 0012-dtrace-USDT-and-pid-provider-core-and-x86-components.patch - 0013-dtrace-USDT-and-pid-providers.patch - 0014-dtrace-function-boundary-tracing-FBT-core-and-x86-co.patch - 0015-dtrace-fbt-provider-modular-components.patch - 0016-dtrace-arm-arm64-port.patch - 0017-dtrace-add-SDT-probes.patch - 0018-dtrace-add-sample-script-for-building-DTrace-on-Fedo.patch - 0019-locking-publicize-mutex_owner-and-mutex_owned-again.patch -) - -get_certs_dir() { - # find a certificate dir in /etc/kernel/certs/ that contains signing cert for modules. - for subdir in $PF $P linux; do - certdir=/etc/kernel/certs/$subdir - if [ -d $certdir ]; then - if [ ! -e $certdir/signing_key.pem ]; then - eerror "$certdir exists but missing signing key; exiting." - exit 1 - fi - echo $certdir - return - fi - done -} - -pkg_pretend() { - # Ensure we have enough disk space to compile - if use binary ; then - CHECKREQS_DISK_BUILD="5G" - check-reqs_pkg_setup - fi -} - -pkg_setup() { - export REAL_ARCH="$ARCH" - unset ARCH; unset LDFLAGS #will interfere with Makefile if set -} - -src_unpack() { - - # unpack the kernel sources to ${WORKDIR} - unpack ${KERNEL_ARCHIVE} || die "failed to unpack kernel sources" - - # unpack the various kconfig files into a single file - cat "${DISTDIR}"/debian-kconfig-* >> "${WORKDIR}"/debian-kconfig-${PV} || die "failed to unpack kconfig" -} - -src_prepare() { - - ### PATCHES ### - - # only apply these if USE=hardened as the patches will break proprietary userspace and some others. - if use hardened; then - # apply hardening patches - einfo "Applying hardening patches ..." - for my_patch in ${HARDENED_PATCHES[*]} ; do - eapply "${HARDENED_PATCHES_DIR}/${my_patch}" || die "failed to apply hardened patches" - done - fi - - # apply gentoo patches - einfo "Applying Gentoo Linux patches ..." - for my_patch in ${GENTOO_PATCHES[*]} ; do - eapply "${GENTOO_PATCHES_DIR}/${my_patch}" || die "failed to apply Gentoo Linux patches" - done - - if use dtrace ; then - # apply DTrace patches - einfo "Applying DTrace patches ..." - for my_patch in ${DTRACE_PATCHES[*]} ; do - eapply "${DTRACE_PATCHES_DIR}/${my_patch}" || die "failed to apply DTrace patches" - done - fi - - if ! use hardened; then - eapply "${FILESDIR}"/${KERNEL_VERSION}/gentoo-patches/1510_fs-enable-link-security-restrictions-by-default.patch - fi - - # append EXTRAVERSION to the kernel sources Makefile - sed -i -e "s:^\(EXTRAVERSION =\).*:\1 ${KERNEL_EXTRAVERSION}:" Makefile || die "failed to append EXTRAVERSION to kernel Makefile" - - # todo: look at this, haven't seen it used in many cases. - sed -i -e 's:#export\tINSTALL_PATH:export\tINSTALL_PATH:' Makefile || die "failed to fix-up INSTALL_PATH in kernel Makefile" - - # copy the kconfig file into the kernel sources tree - cp "${WORKDIR}"/debian-kconfig-${PV} "${S}"/.config - - ### TWEAK CONFIG ### - - # Do not configure Debian devs certificates - echo 'CONFIG_SYSTEM_TRUSTED_KEYS=""' >> .config - - # enable IKCONFIG so that /proc/config.gz can be used for various checks - # TODO: Maybe not a good idea for USE=hardened, look into this... - echo "CONFIG_IKCONFIG=y" >> .config - echo "CONFIG_IKCONFIG_PROC=y" >> .config - - if use custom-cflags; then - MARCH="$(python -c "import portage; print(portage.settings[\"CFLAGS\"])" | sed 's/ /\n/g' | grep "march")" - if [ -n "$MARCH" ]; then - sed -i -e 's/-mtune=generic/$MARCH/g' arch/x86/Makefile || die "Canna optimize this kernel anymore, captain!" - fi - fi - - # only enable debugging symbols etc if USE=debug... - if use debug; then - echo "CONFIG_DEBUG_INFO=y" >> .config - else - echo "CONFIG_DEBUG_INFO=n" >> .config - fi - - if use dtrace; then - echo "CONFIG_DTRACE=y" >> .config - echo "CONFIG_DT_CORE=m" >> .config - echo "CONFIG_DT_FASTTRAP=m" >> .config - echo "CONFIG_DT_PROFILE=m" >> .config - echo "CONFIG_DT_SDT=m" >> .config - echo "CONFIG_DT_SDT_PERF=y" >> .config - echo "CONFIG_DT_FBT=m" >> .config - echo "CONFIG_DT_SYSTRACE=m" >> .config - echo "CONFIG_DT_DT_TEST=m" >> .config - echo "CONFIG_DT_DT_PERF=m" >> .config - echo "CONFIG_DT_DEBUG=n" >> .config - echo "CONFIG_WAITFD=y" >> .config - echo "CONFIG_DEBUG_INFO=y" >> .config - fi - - # these options should already be set, but are a hard dependency for ec2, so we ensure they are set if USE=ec2 - if use ec2; then - echo "CONFIG_BLK_DEV_NVME=y" >> .config - echo "CONFIG_XEN_BLKDEV_FRONTEND=m" >> .config - echo "CONFIG_XEN_BLKDEV_BACKEND=m" >> .config - echo "CONFIG_IXGBEVF=m" >> .config - fi - - # hardening opts - # TODO: document these - if use hardened; then - echo "CONFIG_AUDIT=y" >> .config - echo "CONFIG_EXPERT=y" >> .config - echo "CONFIG_SLUB_DEBUG=y" >> .config - echo "CONFIG_SLAB_MERGE_DEFAULT=n" >> .config - echo "CONFIG_SLAB_FREELIST_RANDOM=y" >> .config - echo "CONFIG_SLAB_FREELIST_HARDENED=y" >> .config - echo "CONFIG_SLAB_CANARY=y" >> .config - echo "CONFIG_SHUFFLE_PAGE_ALLOCATOR=y" >> .config - echo "CONFIG_RANDOMIZE_BASE=y" >> .config - echo "CONFIG_RANDOMIZE_MEMORY=y" >> .config - echo "CONFIG_HIBERNATION=n" >> .config - echo "CONFIG_HARDENED_USERCOPY=y" >> .config - echo "CONFIG_HARDENED_USERCOPY_FALLBACK=n" >> .config - echo "CONFIG_FORTIFY_SOURCE=y" >> .config - echo "CONFIG_STACKPROTECTOR=y" >> .config - echo "CONFIG_STACKPROTECTOR_STRONG=y" >> .config - echo "CONFIG_ARCH_MMAP_RND_BITS=32" >> .config - echo "CONFIG_ARCH_MMAP_RND_COMPAT_BITS=16" >> .config - echo "CONFIG_INIT_ON_FREE_DEFAULT_ON=y" >> .config - echo "CONFIG_INIT_ON_ALLOC_DEFAULT_ON=y" >> .config - echo "CONFIG_SLAB_SANITIZE_VERIFY=y" >> .config - echo "CONFIG_PAGE_SANITIZE_VERIFY=y" >> .config - - # gcc plugins - if ! use clang; then - echo "CONFIG_GCC_PLUGINS=y" >> .config - echo "CONFIG_GCC_PLUGIN_LATENT_ENTROPY=y" >> .config - echo "CONFIG_GCC_PLUGIN_STRUCTLEAK=y" >> .config - echo "CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF_ALL=y" >> .config - echo "CONFIG_GCC_PLUGIN_STACKLEAK=y" >> .config - echo "CONFIG_STACKLEAK_TRACK_MIN_SIZE=100" >> .config - echo "CONFIG_STACKLEAK_METRICS=n" >> .config - echo "CONFIG_STACKLEAK_RUNTIME_DISABLE=n" >> .config - echo "CONFIG_GCC_PLUGIN_RANDSTRUCT=y" >> .config - echo "CONFIG_GCC_PLUGIN_RANDSTRUCT_PERFORMANCE=n" >> .config - fi - - # main hardening options complete... anything after this point is a focus on disabling potential attack vectors - # i.e legacy drivers, new complex code that isn't yet proven, or code that we really don't want in a hardened kernel. - echo 'CONFIG_KEXEC=n' >> .config - echo "CONFIG_KEXEC_FILE=n" >> .config - echo 'CONFIG_KEXEC_SIG=n' >> .config - fi - - # mcelog is deprecated, but there are still some valid use cases and requirements for it... so stick it behind a USE flag for optional kernel support. - if use mcelog; then - echo "CONFIG_X86_MCELOG_LEGACY=y" >> .config - fi - - # sign kernel modules via - if use sign-modules; then - certs_dir=$(get_certs_dir) - echo - if [ -z "$certs_dir" ]; then - eerror "No certs dir found in /etc/kernel/certs; aborting." - die - else - einfo "Using certificate directory of $certs_dir for kernel module signing." - fi - echo - # turn on options for signing modules. - # first, remove existing configs and comments: - echo 'CONFIG_MODULE_SIG=""' >> .config - - # now add our settings: - echo 'CONFIG_MODULE_SIG=y' >> .config - echo 'CONFIG_MODULE_SIG_FORCE=n' >> .config - echo 'CONFIG_MODULE_SIG_ALL=n' >> .config - echo 'CONFIG_MODULE_SIG_HASH="sha512"' >> .config - echo 'CONFIG_MODULE_SIG_KEY="${certs_dir}/signing_key.pem"' >> .config - echo 'CONFIG_SYSTEM_TRUSTED_KEYRING=y' >> .config - echo 'CONFIG_SYSTEM_EXTRA_CERTIFICATE=y' >> .config - echo 'CONFIG_SYSTEM_EXTRA_CERTIFICATE_SIZE="4096"' >> .config - echo "CONFIG_MODULE_SIG_SHA512=y" >> .config - - # print some info to warn user - ewarn "This kernel will ALLOW non-signed modules to be loaded with a WARNING." - ewarn "To enable strict enforcement, YOU MUST add module.sig_enforce=1 as a kernel boot" - ewarn "parameter (to params in /etc/boot.conf, and re-run boot-update.)" - echo - fi - - # enable wireguard support within kernel - if use wireguard; then - echo 'CONFIG_WIREGUARD=m' >> .config - # there are some other options, but I need to verify them first, so I'll start with this - fi - - # get config into good state: - yes "" | make oldconfig >/dev/null 2>&1 || die - cp .config "${T}"/.config || die - make -s mrproper || die "make mrproper failed" - - # Apply any user patches - eapply_user -} - -src_configure() { - - if use binary; then - - tc-export_build_env - MAKEARGS=( - V=1 - - HOSTCC="$(tc-getBUILD_CC)" - HOSTCXX="$(tc-getBUILD_CXX)" - HOSTCFLAGS="${BUILD_CFLAGS}" - HOSTLDFLAGS="${BUILD_LDFLAGS}" - - CROSS_COMPILE=${CHOST}- - AS="$(tc-getAS)" - CC="$(tc-getCC)" - LD="$(tc-getLD)" - AR="$(tc-getAR)" - NM="$(tc-getNM)" - STRIP=":" - OBJCOPY="$(tc-getOBJCOPY)" - OBJDUMP="$(tc-getOBJDUMP)" - - # we need to pass it to override colliding Gentoo envvar - ARCH=$(tc-arch-kernel) - ) - - mkdir -p "${WORKDIR}"/modprep || die - cp "${T}"/.config "${WORKDIR}"/modprep/ || die - emake O="${WORKDIR}"/modprep "${MAKEARGS[@]}" olddefconfig || die "kernel configure failed" - emake O="${WORKDIR}"/modprep "${MAKEARGS[@]}" modules_prepare || die "modules_prepare failed" - cp -pR "${WORKDIR}"/modprep "${WORKDIR}"/build || die - fi -} - -src_compile() { - - if use binary; then - - emake O="${WORKDIR}"/build "${MAKEARGS[@]}" all || "kernel build failed" - fi -} - -src_install() { - - # TODO: Change to SANDBOX_WRITE=".." for installkernel writes - # Disable sandbox - export SANDBOX_ON=0 - - # create sources directory if required - dodir /usr/src - - # copy kernel sources into place - cp -a "${S}" "${D}"/usr/src/linux-${PV}${KERNEL_EXTRAVERSION} || die "failed to install kernel sources" - - # change to installed kernel sources directory - cd "${D}"/usr/src/linux-${PV}${KERNEL_EXTRAVERSION} - - # prepare for real-world use and 3rd-party module building: - make mrproper || die "failed to prepare kernel sources" - - # copy kconfig into place - cp "${T}"/.config .config || die "failed to copy kconfig from ${TEMPDIR}" - - # if we didn't USE=binary - we're done. - # The kernel source tree is left in an unconfigured state - you can't compile 3rd-party modules against it yet. - if use binary; then - make prepare || die - make scripts || die - - local targets=( modules_install ) - - # ARM / ARM64 requires dtb - if (use arm || use arm64); then - targets+=( dtbs_install ) - fi - - emake O="${WORKDIR}"/build "${MAKEARGS[@]}" INSTALL_MOD_PATH="${ED}" INSTALL_PATH="${ED}/boot" "${targets[@]}" - installkernel "${PV}${KERNEL_EXTRAVERSION}" "${WORKDIR}/build/arch/x86_64/boot/bzImage" "${WORKDIR}/build/System.map" "${EROOT}/boot" - - # module symlink fix-up: - rm -rf "${D}"/lib/modules/${PV}${KERNEL_EXTRAVERSION}/source || die "failed to remove old kernel source symlink" - rm -rf "${D}"/lib/modules/${PV}${KERNEL_EXTRAVERSION}/build || die "failed to remove old kernel build symlink" - - # Set-up module symlinks: - ln -s /usr/src/linux-${PV}${KERNEL_EXTRAVERSION} "${ED}"/lib/modules/${PV}${KERNEL_EXTRAVERSION}/source || die "failed to create kernel source symlink" - ln -s /usr/src/linux-${PV}${KERNEL_EXTRAVERSION} "${ED}"/lib/modules/${PV}${KERNEL_EXTRAVERSION}/build || die "failed to create kernel build symlink" - - # Fixes FL-14 - cp "${WORKDIR}/build/System.map" "${D}"/usr/src/linux-${PV}${KERNEL_EXTRAVERSION}/ || die "failed to install System.map" - cp "${WORKDIR}/build/Module.symvers" "${D}"/usr/src/linux-${PV}${KERNEL_EXTRAVERSION}/ || die "failed to install Module.symvers" - - if use sign-modules; then - for x in $(find "${D}"/lib/modules -iname *.ko); do - # $certs_dir defined previously in this function. - ${WORKDIR}/build/scripts/sign-file sha512 $certs_dir/signing_key.pem $certs_dir/signing_key.x509 $x || die - done - # install the sign-file executable for future use. - exeinto /usr/src/linux-${PV}-${KERNEL_EXTRAVERSION}/scripts - doexe ${WORKDIR}/build/scripts/sign-file - fi - fi -} - -pkg_postinst() { - - # TODO: Change to SANDBOX_WRITE=".." for Dracut writes - export SANDBOX_ON=0 - - # if USE=symlink... - if use symlink; then - # delete the existing symlink if one exists - if [[ -h "${EROOT}"/usr/src/linux ]]; then - rm "${EROOT}"/usr/src/linux - fi - # and now symlink the newly installed sources - ewarn "" - ewarn "WARNING... WARNING... WARNING" - ewarn "" - ewarn "/usr/src/linux symlink automatically set to linux-${PV}${KERNEL_EXTRAVERSION}" - ewarn "" - ln -sf "${EROOT}"/usr/src/linux-${PV}${KERNEL_EXTRAVERSION} "${EROOT}"/usr/src/linux - fi - - # if there's a modules folder for these sources, generate modules.dep and map files - if [[ -d ${EROOT}/lib/modules/${PV}${KERNEL_EXTRAVERSION} ]]; then - depmod -a ${PV}${KERNEL_EXTRAVERSION} - fi - - # NOTE: WIP and not well tested yet. - # - # Dracut will build an initramfs when USE=binary. - # - # The initramfs will be configurable via USE, i.e. - # USE=zfs will pass '--zfs' to Dracut - # USE=-systemd will pass '--omit dracut-systemd systemd systemd-networkd systemd-initrd' to exclude these (Dracut) modules from the initramfs. - # - # NOTE 2: this will create a fairly.... minimal, and modular initramfs. It has been tested with things with ZFS and LUKS, and 'works'. - # Things like network support have not been tested (I am currently unsure how well this works with Gentoo Linux based systems), - # and may end up requiring network-manager for decent support (this really needs further research). - if use binary; then - einfo "" - einfo ">>> Dracut: building initramfs" - dracut \ - --stdlog=1 \ - --force \ - --no-hostonly \ - --add "base dm fs-lib i18n kernel-modules rootfs-block shutdown terminfo udev-rules usrmount" \ - --omit "biosdevname bootchart busybox caps convertfs dash debug dmsquash-live dmsquash-live-ntfs fcoe fcoe-uefi fstab-sys gensplash ifcfg img-lib livenet mksh network network-manager qemu qemu-net rpmversion securityfs ssh-client stratis syslog url-lib" \ - $(usex btrfs "-a btrfs" "-o btrfs") \ - $(usex dmraid "-a dmraid" "-o dmraid") \ - $(usex hardened "-o resume" "-a resume") \ - $(usex iscsi "-a iscsi" "-o iscsi") \ - $(usex lvm "-a lvm" "-o lvm") \ - $(usex lvm "--lvmconf" "--nolvmconf") \ - $(usex luks "-a crypt" "-o crypt") \ - $(usex mdadm "--mdadmconf" "--nomdadmconf") \ - $(usex mdadm "-a mdraid" "-o mdraid") \ - $(usex microcode "--early-microcode" "--no-early-microcode") \ - $(usex multipath "-a multipath" "-o multipath") \ - $(usex nbd "-a nbd" "-o nbd") \ - $(usex nfs "-a nfs" "-o nfs") \ - $(usex plymouth "-a plymouth" "-o plymouth") \ - $(usex selinux "-a selinux" "-o selinux") \ - $(usex systemd "-a systemd -a systemd-initrd -a systemd-networkd" "-o systemd -o systemd-initrd -o systemd-networkd") \ - $(usex zfs "-a zfs" "-o zfs") \ - --kver ${PV}${KERNEL_EXTRAVERSION} \ - --kmoddir ${EROOT}/lib/modules/${PV}${KERNEL_EXTRAVERSION} \ - --fwdir ${EROOT}/lib/firmware \ - --kernel-image ${EROOT}/boot/vmlinuz-${PV}${KERNEL_EXTRAVERSION} - einfo "" - einfo ">>> Dracut: Finished building initramfs" - ewarn "" - ewarn "WARNING... WARNING... WARNING..." - ewarn "" - ewarn "Dracut initramfs has been generated!" - ewarn "" - ewarn "Required kernel arguments:" - ewarn "" - ewarn " root=/dev/ROOT" - ewarn "" - ewarn " Where ROOT is the device node for your root partition as the" - ewarn " one specified in /etc/fstab" - ewarn "" - ewarn "Additional kernel cmdline arguments that *may* be required to boot properly..." - ewarn "" - ewarn "If you use hibernation:" - ewarn "" - ewarn " resume=/dev/SWAP" - ewarn "" - ewarn " Where $SWAP is the swap device used by hibernate software of your choice." - ewarn"" - ewarn " Please consult "man 7 dracut.kernel" for additional kernel arguments." - fi - - # warn about the issues with running a hardened kernel - if use hardened; then - ewarn "" - ewarn "WARNING... WARNING... WARNING..." - ewarn "" - ewarn "Hardened patches have been applied to the kernel and KCONFIG options have been set." - ewarn "These KCONFIG options and patches change kernel behavior." - ewarn "Changes include:" - ewarn "Increased entropy for Address Space Layout Randomization" - ewarn "GCC plugins (if using GCC)" - ewarn "Memory allocation" - ewarn "... and more" - ewarn "" - ewarn "These changes will stop certain programs from functioning" - ewarn "e.g. VirtualBox, Skype" - ewarn "Full information available in $DOCUMENTATION" - ewarn "" - fi - - # if there are out-of-tree kernel modules detected, warn warn warn - # TODO: tidy up below - if use binary && [[ -e "${EROOT}"/var/lib/module-rebuild/moduledb ]]; then - ewarn "" - ewarn "WARNING... WARNING... WARNING..." - ewarn "" - ewarn "External kernel modules are not yet automatically built" - ewarn "by USE=binary - emerge @modules-rebuild to do this" - ewarn "and regenerate your initramfs if you are using ZFS root filesystem" - ewarn "" - fi - - if use binary; then - if [[ -e /etc/boot.conf ]]; then - ego boot update - fi - fi -} diff --git a/sys-kernel/cairn-sources/files/5.10.13/dtrace-patches/0001-ctf-generate-CTF-information-for-the-kernel.patch b/sys-kernel/cairn-sources/files/5.10.13/dtrace-patches/0001-ctf-generate-CTF-information-for-the-kernel.patch deleted file mode 100644 index c9ba20a6c135..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/dtrace-patches/0001-ctf-generate-CTF-information-for-the-kernel.patch +++ /dev/null @@ -1,7297 +0,0 @@ -From ee291dd05f9c4904f1c5a110d22cf0c3a5580df6 Mon Sep 17 00:00:00 2001 -From: Nick Alcock <nick.alcock@oracle.com> -Date: Wed, 14 Nov 2018 19:42:21 +0000 -Subject: [PATCH 01/19] ctf: generate CTF information for the kernel - -This introduces a new tool, dwarf2ctf, which runs whenever 'make ctf' is -run, extracting information on the kernel's types and global variables -from the DWARF-format debug information in the kernel build tree, -deduplicating it, and emitting it in Sun's Compact Type Format into a -mmappable type archive named vmlinux.ctfa, which is installed at 'make -install' time into /lib/modules/$(uname -r)/kernel/. Out-of-tree -modules cannot participate in this mechanism since the file is already -written: CTF information for such modules is instead linked into such -modules at build time as new sections named .SUNW_ctf (as a result, most -of the build-time machinery for this is in scripts/Makefile.modpost). -Care should be taken not to strip such sections into debug RPMs (they -are small enough that this should not be a problem). - -Within the ctfa file, the type information is divided into a shared -repository, containing all types used by more than one module, CTF for -the core kernel, and separate CTF for each module built, whether or not -this module has been compiled in or not: if a file *could* be built as a -module, it will be considered to be a module from the perspective of CTF -file emission (and kallmodsyms: see the next commit). This ensures that -external consumers such as DTrace always find types for a given module -in the same place, regardless of the local kernel configuration, as long -as that module is present at all, assisting in portability of D scripts -between installations. The ctf_ar tool in libdtrace-ctf can be used to -inspect ctfa files, and the ctf_dump tool can be used to look at the ctf -files they contain. - -This process needs a pair of new files, objects.builtin (which lists all -object files that are unconditionally built into the kernel and cannot -be built as modules) and modules_thick.builtin, which maps from the thin -archives that make up built-in modules to their constituent object -files. Taken together, these files let dwarf2ctf determine whether a -given object file linked into vmlinux.o is part of a module, and if so, -which one. - -There is a single manually-maintained blacklist of structure members -dwarf2ctf cannot handle in scripts/dwarf2ctf/member.blacklist: this is -used to identify structure members which have different definitions in -different object files even though they are defined in the same location -in the same source file, usually due to preprocessor magic. (Currently, -the only item in this list is present for example purposes only, since -the file in question was recently removed from the kernel: dwarf2ctf can -these days identify most members needing blacklisting automatically, and -will fail with an error if it needs more help. It is quite possible that -dwarf2ctf will fail on make allyesconfig kernel configurations and other -extreme cases: I hope to track all such bugs down in time.) - -The documentation for dwarf2ctf is currently somewhat outdated: an -update is planned. It remains largely accurate except for some details -of the deduplication pass. - -This introduces new kernel build-time dependencies on elfutils, zlib, -glib, and the new libdtrace-ctf package (shared with DTrace userspace). -No new runtime dependencies are introduced. - -v5.6: retain the tristate machinery and scripts/Makefile.modbuiltin, - since there appears to be no other way to get modules_thick.builtin - (or anything like it) generated. - -Signed-off-by: Nick Alcock <nick.alcock@oracle.com> -Signed-off-by: Kris Van Hees <kris.van.hees@oracle.com> -Signed-off-by: Tomas Jedlicka <tomas.jedlicka@oracle.com> ---- - .gitignore | 3 + - Documentation/dontdiff | 1 + - Documentation/dwarf2ctf | 1054 ++++++ - Documentation/kbuild/kconfig.rst | 5 + - Documentation/process/changes.rst | 23 +- - Makefile | 72 +- - lib/Kconfig | 12 + - scripts/Kbuild.include | 6 + - scripts/Makefile | 1 + - scripts/Makefile.modbuiltin | 60 + - scripts/Makefile.modfinal | 141 +- - scripts/dwarf2ctf/.gitignore | 1 + - scripts/dwarf2ctf/Makefile | 10 + - scripts/dwarf2ctf/dwarf2ctf.c | 4962 ++++++++++++++++++++++++++++ - scripts/dwarf2ctf/eu_simple.c | 2 + - scripts/dwarf2ctf/member.blacklist | 1 + - scripts/eu_simple.c | 356 ++ - scripts/eu_simple.h | 91 + - scripts/kconfig/confdata.c | 41 +- - scripts/move-if-change | 8 + - scripts/package/mkspec | 12 + - 21 files changed, 6851 insertions(+), 11 deletions(-) - create mode 100644 Documentation/dwarf2ctf - create mode 100644 scripts/Makefile.modbuiltin - create mode 100644 scripts/dwarf2ctf/.gitignore - create mode 100644 scripts/dwarf2ctf/Makefile - create mode 100644 scripts/dwarf2ctf/dwarf2ctf.c - create mode 100644 scripts/dwarf2ctf/eu_simple.c - create mode 100644 scripts/dwarf2ctf/member.blacklist - create mode 100644 scripts/eu_simple.c - create mode 100644 scripts/eu_simple.h - create mode 100755 scripts/move-if-change - -diff --git a/.gitignore b/.gitignore -index d01cda8e1177..1c10cd7ce033 100644 ---- a/.gitignore -+++ b/.gitignore -@@ -48,6 +48,8 @@ - Module.symvers - modules.builtin - modules.order -+modules_thick.builtin -+objects.builtin - - # - # Top-level generic files -@@ -58,6 +60,7 @@ modules.order - /vmlinux - /vmlinux.32 - /vmlinux.symvers -+/vmlinux.ctfa - /vmlinux-gdb.py - /vmlinuz - /System.map -diff --git a/Documentation/dontdiff b/Documentation/dontdiff -index e361fc95ca29..a763d0fb892e 100644 ---- a/Documentation/dontdiff -+++ b/Documentation/dontdiff -@@ -181,6 +181,7 @@ modpost - modules.builtin - modules.builtin.modinfo - modules.nsdeps -+modules_thick.builtin - modules.order - modversions.h* - nconf -diff --git a/Documentation/dwarf2ctf b/Documentation/dwarf2ctf -new file mode 100644 -index 000000000000..5cc445fbd227 ---- /dev/null -+++ b/Documentation/dwarf2ctf -@@ -0,0 +1,1054 @@ -+dwarf2ctf, a type encoder for the Linux kernel -+========= -+ -+Many kernel-level debugging and tracing systems need access to the kernel's type -+information. Since C doesn't support any form of introspection, the data must -+be extracted in some other way: here, we extract it from the DWARF debugging -+information generated by the compiler. Unfortunately, this information is very -+voluminous (just the type information alone adds up to a couple of hundred -+megabytes in a 'make allyesconfig' kernel): even if users are happy to spend the -+disk space, the time and memory required to read much of this information in is -+likely to be prohibitive. -+ -+This problem is not new -- back in 2004, Sun had the same problem when -+attempting to give DTrace a view of the type information in the Solaris kernel. -+Their solution was the Compact ANSI-C Type Format (CTF), a highly compacted -+representation of C types suitable for debuggers and tracers. They combined -+this with a highly efficient tool for converting DWARF2 types to CTF, and hacks -+in the Solaris kernel causing the kernel itself to emit CTF data for its own -+types. -+ -+Unfortunately while this tool may be highly efficient it is not adequate for the -+Linux kernel. It treats every ELF object as an independent entity with an -+independent set of types -- perfectly all right for the Solaris kernel with a -+few hundred modules maximum, but very much not for Linux, where distro kernels -+often compile in thousands of modules. Ideally, we would like to treat all -+kernel modules, built-in or not, the same way, sharing and deduplicating all -+globally-visible types across the entire set of visible modules and recording -+each precisely once. -+ -+We also want to collect descriptions of global variables and emit descriptions -+of their name->type mapping as well, since the kernel has no easily accessible -+ELF section we can extract this information from at runtime (kernel modules must -+be accessible at runtime for modern Linux systems to work, but the kernel itself -+could have come from over the network or off a USB key or from a non-mounted -+partition or an EFI boot partition or who knows where, and could have any name -+even if it is accessible: so tracing tools should not rely on being able to look -+inside the kernel image). -+ -+We do all this with dwarf2ctf, a CTF generation tool that reads in DWARF from a -+set of object files (usually, every object file in the kernel and all modules) -+and fills a directory with compressed files containing CTF representations of -+the types in those object files: the kernel build system regenerates these as -+necessary and links them directly into kernel modules. -+ -+Caveats: It is somewhat specific to the form of DWARF output emitted by GCC, and -+doesn't yet support DWARF-4 type signatures or compressed DWARF at all. -+ -+We'll look at each part of this system in turn, from the top down, starting with -+using the kernel type information dwarf2ctf produces in other programs. -+ -+ -+Using dwarf2ctf output -+---------------------- -+ -+Using this data is fairly simple. Once you've read the CTF sections from the -+kernel modules and inflated them (or ignored them if they are empty or, as just -+mentioned, one byte long), you simply need to look at the ctf_parent_name() for -+each module, and if it is set to "ctf", call ctf_import() to set the parent of -+this module to the CTF data you have read from the .ctf.shared_ctf section in -+the ctf.ko kernel module. The core kernel's types are stored in the -+.ctf.vmlinux section in the same kernel module, and all built-in kernel modules -+have their types in .ctf.$module_name. Non-built-in kernel modules just have a -+.ctf section containing their types, which again might need their parent set to -+"shared_ctf". (Out-of-tree kernel modules will have no such parent.) -+ -+Once you've set up the parenthood relationships you can call ctf_close() on the -+shared type repository and forget about it entirely: it will be refcounted and -+destroyed when all its children are closed. -+ -+ -+You should end up with a family of CTF files, one per kernel module built-in or -+not and one for the core kernel, freely usable for whatever purpose you need. -+ -+ -+Invocation and build-system connections -+---------- -+ -+dwarf2ctf's command-line syntax emphasises simplicity over compactness. Linux -+has nearly-infinitely-long command lines these days, so we can take advantage of -+this. -+ -+Two syntaxes are supported. The first shares types across multiple modules and -+the core kernel; the second is used for out-of-tree module building, and avoids -+either sharing anything at all across modules or depending on the set of shared -+types defined for the core kernel. -+ -+ -+dwarf2ctf outputdir objects.builtin modules.builtin dedup.blacklist \ -+ vmlinux.o module.o ... -+dwarf2ctf outputdir -e module.o ... -+ -+where: -+ -+ - 'outputdir' is the possibly-relative path to a directory in which the -+ generated CTF files get placed. -+ - 'objects.builtin' is the name of the file containing the object files that -+ correspond to always-built-in kernel code (that cannot be built as modules). -+ - 'modules.builtin' is the name of the file containing the names of -+ kernel modules presently built in to the kernel. -+ - 'dedup.blacklist' is a blacklist of modules that should never participate -+ in deduplication: see 'Duplicate type detection' below. -+ - the .o filenames are the names of object files comprising the kernel and/or -+ modules: you can feed in whole modules at once (before linking with .mod.o). -+ This list is often very, very long (I have seen command-lines in excess of -+ 60Kb). -+ -+dwarf2ctf's output consists of a series of gzip-compressed .ctf.new files in the -+outputdir, which the makefile compares with and if necessary moves over the top -+of .ctf files with the same basename, so as to avoid relinking things if -+dwarf2ctf has written out content identical to what it wrote last time it ran. -+These fall into several classes, partitioned according to the contents of -+objects.builtin and modules.builtin: -+ -+ - shared_ctf.builtin.ctf: The shared type repository. Types shared by more -+ than one of the files below go here. -+ libdtrace-ctf). See 'Using dwarf2ctf output' below regarding use of this -+ data. -+ - vmlinux.builtin.ctf: Types in the core kernel, that cannot be built in to -+ modules, go here. -+ - *.builtin.ctf: One of these is generated for the types in each module that -+ is presently built in to the kernel. -+ - *.mod.ctf: One of these is generated for each .ko. -+ -+All the files in the first three classes are linked into the ctf.ko module under -+various names, an empty module containing nothing but CTF data. -+ -+ -+A lengthy section of Makefile.modpost, and a short section of the toplevel -+Makefile, is dedicated to creating these files, and to linking them into the -+kernel modules. The dependency graph related to dwarf2ctf output is quite -+complex: modules and objects (ld -r'ed *.o files) are processed by dwarf2ctf to -+produce a number of files in the .ctf directory, and the final modules depend on -+the relevant ctf files. The .mod.ctf's go into the .ko's with the same stem -+name, but ctf.ko receives content from all the CTF files corresponding to -+built-in modules, and until dwarf2ctf runs and creates those files we cannot -+tell what those CTF files will be, though we do have a wildcard that matches -+them all. -+[ -+GNU Make's 'secondary expansion' feature comes to the rescue here: we can -+compute a list of expected CTF filenames at runtime, given the names of the -+modules we are linking in. For the builtin modules, we cheat and touch a stamp -+file after moving any .ctf.new files back over a .ctf file, then depend on that -+to see if ctf.ko needs to be relinked. -+ -+The actual incorporation of the CTF data into the kernel modules happens before -+module signing (if signing is active), by calling objcopy --add-section on the -+module in question. This too has some knotty corners. -+ -+First of all, the module linkage process normally links a module using all the -+prerequisites of the module's target -- but we have designated all the CTF files -+as prerequisites of the module's target, and we don't want to link them directly -+in using ld(1), since they aren't object files. So we have to filter them out in -+the link line. -+ -+Secondly, those modules which have no CTF files should acquire empty CTF -+sections to indicate their lack of unique types -- but objcopy in binutils 2.20 -+and below silently exits if asked to --add-section an empty file. So we use dd -+to generate a file with a one-byte null in it instead, and teach the users of -+CTF sections to treat a one-byte-long 'CTF' section as if it were empty. -+ -+ -+Overview of dwarf2ctf operation -+-------- -+ -+There are four phases to dwarf2ctf operation: initialization, duplicate type -+detection, CTF construction, and writeout. Some of these phases can repeat. -+All but the last phase consists purely of sucking data from object files into -+GHashTables in memory. (The last two phases could potentially be combined, -+shrinking the size of one hash and saving memory, but the hash that is shrunk is -+by no means the largest one, so the extra complexity is probably not worth it.) -+ -+dwarf2ctf uses several other libraries to do this: -+ -+ - elfutils, used for DWARF parsing. We could potentially write our own -+ DWARF parser, but elfutils works and is tested. -+ -+ - glib, used for the GHashTable. The rest of the kernel uses roll-your-own -+ hash tables, but dwarf2ctf makes heavy demands of its hashtables: they must -+ be expanding hashes capable of efficiently storing hundreds of thousands of -+ items, with amortized log(N) lookup time, and they must support deletion -+ (though it need not be particularly efficient deletion). This rules out -+ simple fixed-size bucket hashes like the ones used in other parts of the -+ kernel build system: GHashTable is already implemented, and works. -+ -+ - zlib, used to compress the CTF information. -+ -+ - libdtrace-ctf, which both reads and writes the CTF data. This is a port of -+ the Solaris CTF library, GPLed and with additional support for the storage -+ of name->type mappings (meant to represent variables) akin to its existing -+ ELF symbol->type mappings. -+ -+dwarf2ctf has a good few important data structures, described at the top of -+scripts/dwarf2ctf/dwarf2ctf.c. -+ -+dwarf2ctf has its own trace facility, implemented via the dw_ctf_trace() macro -+and enabled by compiling with -DDEBUG and setting DWARF2CTF_TRACE in the -+environment. (The first step is required because some very numerous data -+structures are greatly expanded when debugging is turned on, which would waste -+memory if it were done all the time). This produces a huge volume of trace -+output, several gigabytes when run over an allyesconfig kernel. -+ -+ -+Unless you're interested in how dwarf2ctf works internally, you can stop reading -+here. If you are interested, now is a good time to read the comments above -+main() in scripts/dwarf2ctf/dwarf2ctf.c, which briefly describe dwarf2ctf's data -+structures and functions. -+ -+ -+Flow of Control -+--------------- -+ -+The /* C comments */ point to other sections of this document, -+ -+Functions named in the /* Utilities */ section of dwarf2ctf.c are not mentioned -+here for simplicity's sake. -+ -+[C]: Callback -+[R]: recursive -+[1]: Numbers: Mutually-recursive loop -+|: Several functions which all call the same functions -+->: Call from array of callbacks (filter_ctf_*() omitted as uninteresting) -+ -+main() -+ /* See 'Initialization' */ -+ init_assembly_tab() -+ init_builtin() -+ init_dedup_blacklist() -+ init_member_blacklist() -+ run() -+ init_tu_to_modules() -+ init_ctf_table() -+ -+ /* Duplicate detection */ -+ -+ scan_duplicates() -+ process_file() /* Toplevel DWARF walkers */ -+[C] detect_duplicates_init() -+[R] process_tu_func() -+[C] assembly_filter_tab[] -+[C] detect_duplicates() -+[ 1] mark_shared() -+[R] type_id() /* Type IDs */ -+[C1] mark_shared() -+[R] mark_seen_contained() -+[C] detect_duplicates_done() -+ -+ process_file() -+[C] detect_duplicates_init() -+[R] process_tu_func() -+[C] assembly_filter_tab[] -+[C] detect_duplicates_alias_fixup() -+[R] type_id() -+[C] is_named_struct_union_enum() -+[R] type_id() -+[C] detect_duplicates_alias_fixup_internal() -+ mark_shared() (see above) -+[C] detect_duplicates_done() -+ -+ /* CTF construction */ -+ -+ process_file() -+[R] process_tu_func() -+[C] assembly_filter_tab[] -+[C] construct_ctf() -+[ 2] construct_ctf_id() -+[R3] die_to_ctf() -+ assembly_tab[] -+[C] -> assemble_ctf_base() -+ -> assemble_ctf_pointer() -+ | assemble_ctf_array() -+ | assemble_ctf_array_dimension() -+ | assemble_ctf_typedef() -+ | assemble_ctf_cvr_qual() -+ | assemble_ctf_variable() -+ lookup_ctf_type() -+[ 2] construct_ctf_id() -+ -> assemble_ctf_enumeration() -+ -> assemble_ctf_enumerator() -+ -> assemble_ctf_struct_union() -+ -> assemble_ctf_su_member() -+[ 3] die_to_ctf() -+[ 2] construct_ctf_id() -+ -+ write_types() -+ -+Initialization -+-------------- -+ -+ init_assembly_tab() -+ init_builtin() -+ init_dedup_blacklist() -+ run() -+ init_tu_to_modules() -+ init_ctf_table() -+ -+This happens at the top of main() and run(), and in various functions named -+init_*(). Of these, init_assembly_tab() and init_builtin() serve only to turn -+various static arrays and files mentioned on the command line into more useful -+internal representations (e.g. the assembly filter array of structures is turned -+into a pair of arrays indexed by DWARF tag), and the blacklisting functions are -+described in the section on duplicate type detection below. -+ -+init_ctf_table(), called both at initialization time and later during CTF -+assembly when new CTF files are found to be needed, creates a new CTF file in -+memory and either marks it as a child of the shared type repository, or (if it -+*is* the shared type repository, or deduplication is off and there is only one -+CTF file being processed and no shared type repository at all) creates a few -+types in it which CTF has representations of but DWARF does not: a void type, -+and a generic catchall pointer-to-function-returning-int. -+ -+That leaves init_tu_to_modules(). This walks over all the top-level -+compile_unit DIEs in the DWARF debugging information in every object file -+mentioned in the list of modules and built-in modules, constructing a mapping -+from translation unit name back to the name of the kernel module it comes from, -+even if that module is built in to the kernel. This is normally the same as the -+filename (sans extension), but for built-in kernel modules, the name comes from -+the modules.builtin file's entry for the translation unit instead, so that the -+output can land in a .builtin.ctf file rather than being jammed into -+vmlinux.builtin.ctf with the core kernel's types. -+ -+This means that dwarf2ctf can operate in terms of the kernel module a type is -+contained within rather than having to think about the mapping between object -+file name, translation unit name and module name all the time. -+ -+ -+Toplevel DWARF walkers -+---------------------- -+ -+ process_file() -+[C] (per-TU initialization callback) -+[R] process_tu_func() -+[C] assembly_filter_tab[] -+[C] (per-DIE callback) -+[C] (per-TU cleanup callback) -+ -+All routines in dwarf2ctf other than initialization and writeout are DWARF -+walkers: i.e., they walk over all DWARF DIEs in all object files specified on -+the command line and do something with every DIE. This job is done by -+process_file() and its helper process_tu_func(), which not only digs out the -+corresponding (built-in or non-built-in) module name corresponding to each -+object file, but also detects and skips translation units it has handled before -+(in case they are incrementally linked into multiple object files) and allows -+callbacks to be invoked at the start and end of each translation unit. -+ -+Even though dwarf2ctf only cares about top-level types, in some situations DWARF -+can emit top-level types with references to a non-top-level type: if all -+occurrences of the top-level type are an opaque structure, and the only -+non-opaque definition is inside a function, references in the same translation -+unit as the non-opaque definition will point to the definition inside the -+function (and references outside the translation unit will not point at any -+definition). Thus, if we want to catch all nuances of globally-visible types, -+we have to scan types inside functions and lexical blocks inside functions too. -+ -+To avoid generating a vast number of unnecessary type definitions, the 'assembly -+table' which describes how to construct a CTF type given a DWARF DIE also -+contains a description of a set of filters which are passed the current DIE and -+its parent: if they return false, the DIE is skipped and never passed to the -+callback function. We also avoid calling the callback for any DWARF DIE whose -+tag doesn't appear in the assembly table at all: there's no point doing -+duplicate detection or anything else for a DWARF DIE we won't be generating CTF -+from. There are currently two filters defined: filter_ctf_file_scope(), which -+is called for every DWARF DIE whose tag is one we never expect to see a -+reference to if it is inside a function (except if they relate to a structure or -+union, as above), and filter_ctf_uninteresting(), which is called for variables -+to see if they are worthy of recording (top-level named variables with external -+linkage not part of the internal workings of macros only). -+ -+ -+Type IDs -+-------- -+ -+[R] type_id() -+[C] (optional per-type callback) -+ -+The only thing dwarf2ctf does which the Sun tool does not is the detection of -+duplicate and shared types, both within individual kernel modules and across -+modules. Our ultimate goal is that a type that appears in the source code once -+appears in the CTF output once as well. This goal has mostly been attained, -+except for out-of-tree modules, where cross-module type sharing must be disabled -+to avoid requiring rebuilds of the module whenever the core kernel is rebuilt. -+ -+The core of this is the concept of a *type ID* and the function type_id() which -+computes it. A type ID is an identifier for a type which precisely represents -+that type and only that type. Doing this for types in different headers or at -+different scopes with the same name without needing to encode knowledge of C -+scoping rules into dwarf2ctf is an interesting proposition: we can use the line -+number and filename info provided by DWARF in most user-specified types to help. -+ -+A type ID is a recursively-constructed string of the following form (fixed -+elements represented by {}, optional elements by []): -+ -+//[filename]//[line number]//{type string} -+ -+Types are *based* upon other types iff they have a DW_AT_type attribute pointing -+to some other type. All types based upon other types have a type ID that is the -+type ID of the type upon which they are based, with additional information -+specific to this type appended to it. The filename and line number is only -+added for those types which are not based upon other types and which have a -+filename and line number in the DWARF (lots don't, e.g. base types): the -+filename is canonicalized with realpath(), though since this is quite slow and -+type_id() is called a lot, the mapping from DWARF filename to realpath() result -+is cached. Types that have no filename or line number start with '////'. -+ -+We use // to separate the filename and line number elements because this is the -+shortest string other than NUL that cannot appear in a canonicalized POSIX -+pathname (ignoring Pyramid, Cygwin and other strange systems that actually -+return // in the result of realpath(): Linux doesn't use it and that's all that -+matters. Should it start to use it, we can switch delimiter to ///.) -+ -+Function pointers are not represented (or, rather, are all mapped to the same -+type ID, the generic catchall function-pointer type mentioned above); array -+dimensions are represented by [index-type dimension], or [] for flexible array -+members. Structure members are not represented, since they are not types, but -+the types of their members *are* represented, as are nested structures (the line -+number and filename serving, as ever, to disambiguate them from other structures -+with the same name declared nested inside different structures). -+ -+The following are some examples of valid type IDs (assuming the kernel source -+tree is, implausibly, located at /k/, just off the root directory: comments on -+individual types done /* like C */; the last example is broken across lines for -+formatting's sake): -+ -+//fp//* # a pointer to a function, any function -+////long int -+////char [] -+////unsigned int typedef __kernel_uid_t typedef __kernel_uid32_t -+//fp//* typedef __signalfn_t * typedef __sighandler_t -+////struct nsproxy /* an opaque type */ -+////struct nsproxy * # /* pointer to it */ -+////long unsigned int typedef u64 volatile -+////long unsigned int volatile const * const -+////long unsigned int typedef sector_t [////long unsigned int 511] -+/k/include/linux/types.h//222//struct list_head -+/k/include/linux/types.h//222//struct list_head * -+/k/include/linux/types.h//222//struct list_head [////long unsigned int 5] -+/k/include/linux/types.h//217//struct /* no struct tag */ -+/k/include/linux/types.h//217//struct typedef atomic64_t -+/k/include/linux/mm_types.h//34//struct page * typedef pgtable_t -+/k/fs/eventpoll.c//122//struct nested_calls -+/k/include/linux/sysctl.h//1016//struct ctl_table typedef ctl_table -+ [////long unsigned int 4] var inotify_table /* A global variable */ -+ -+This scheme means that cv-quals and other modifiers applied to other types are -+always merged: if there are a dozen typedefs for a single type 'foo' with the -+same name declared in the same place, they all end up with the same type ID and -+are only emitted into the CTF once. -+ -+The type_id() function can also accept a callback, which is called as the -+recursion unwinds, from base type up to derived type: so it might be called for -+"////unsigned int", then for "////unsigned int typedef __kernel_uid_t", and so -+on up to the DIE that was originally passed in. Because type_id() returns a -+dynamically-allocated string, calls to type_id() made purely for the sake of -+invoking a callback are normally of the peculiar form "free(type_id(...))". -+ -+type_id() is a very hot spot, so syscall results are cached in it (such as -+realpath(), as mentioned above), and when string appending is done, it is done -+all at once where possible, via str_appendn(), which calls realloc() only once -+no matter the number of strings being appended. -+ -+Lots of core data structures in dwarf2ctf consist of hashes mapping type IDs to -+something else (predominantly CTF file/ID pairs and module names). It would -+be possible to map from hashes of type IDs, saving some memory, but this would -+impair debugging so is not yet implemented. (If it is implemented, it should -+probably be implemented only when DEBUG is not defined.) -+ -+ -+Duplicate detection -+------------------- -+ -+ scan_duplicates() -+ process_file() /* Toplevel DWARF walkers */ -+[C] detect_duplicates_init() -+[R] process_tu_func() -+[C] assembly_filter_tab[] -+[C] detect_duplicates() -+[ 1] mark_shared() -+[R] type_id() /* Type IDs */ -+[C1] mark_shared() -+[ 4] type_id() -+[ 4] detect_duplicates_typeid() -+[ 4] detect_duplicates() -+[R] mark_seen_contained() -+ member_blacklisted() -+[C] detect_duplicates_done() -+ -+ process_file() -+[C] detect_duplicates_init() -+[R] process_tu_func() -+[C] assembly_filter_tab[] -+[C] detect_duplicates_alias_fixup() -+[R] type_id() -+[C] is_named_struct_union_enum() -+[R] type_id() -+[C] detect_duplicates_alias_fixup_internal() -+ mark_shared() (see above) -+[C] detect_duplicates_done() -+ -+The job of the duplicate detection pass is to fill out the id_to_module hash, -+which maps type IDs to the module they appear in, with the two special cases -+that types that appear only in the core kernel are said to appear in the module -+'vmlinux', and types that appear in more than one module (or in a module and in -+the core kernel) are said to appear in the module 'shared_ctf', the shared type -+repository. This is quite a tricky multi-pass process, because we must ensure -+that the shared type repository is self-contained: all types in the repository -+must not reference any types outside the repository. -+ -+Detecting duplicates itself is easy: we consider two types duplicates if they -+have the same type ID: if they both reside in the same module, the resulting -+type resides in that module too. However, detecting shared types is harder. -+We consider that a type belongs in the shared module if any of these conditions -+is true: -+ -+ - the type appears multiple times in different modules -+ - a type for which this type is a base type is shared -+ - the type is referenced by a structure or union member, and the structure -+ or union is shared -+ - the type is a non-opaque type with an opaque variant ('struct foo'), or -+ vice versa, and either of these variants is shared: these two types will -+ get different type IDs, so explicit checking is necessary -+ -+Note that we do *not* consider a type to belong in the shared module merely if -+*it* has a base type which is shared: indeed, this is the common case for -+unshared types (even unshared structures tend to have fields of shared types -+like int). -+ -+It should be fairly easy to see that sharedness is a contagious property: -+e.g. if you mark a structure as shared, and one of its members is an -+otherwise-unshared opaque pointer to a structure, you have to mark that as -+shared: this causes the non-opaque definition of the structure, and all *its* -+members, to be shared, and so on. So since dwarf2ctf does not track the members -+of structures itself (not until the CTF generation phase, anyway), this means -+walking over the DWARF DIEs multiple times, checking for sharedness over and -+over until we are done. -+ -+We partition the problem into two parts, both of which are carried out by -+process_file() callback functions: detect_duplicates() and -+detect_duplicates_alias_fixup(). -+ -+ -+detect_duplicates() is called first, once for every DIE in the kernel (via -+process_file()). This identifies types that are duplicated but not shared, and -+identifies shared types without consideration of opaque struct/union aliasing. -+It also flags types that have been seen only once as 'seen': this is checked -+much later on by the CTF construction phase, since construction of CTF for -+any type which has not been inspected by the deduplicator is a sign of a bug in -+the deduplicator. -+ -+This has several subtleties. -+ -+If we are running for an out-of-tree module, we must still identify types as -+duplicated within the module, but must never mark them as shared: out-of-tree -+modules cannot contribute to the shared type repository nor even use types in -+it, since they are rebuilt independently from the kernel proper and thus cannot -+depend on a type currently in the repository remaining there (e.g. perhaps it -+has only two users, both in modules, and the kernel is rebuilt to not build one -+of those modules anymore: this should not require rebuilding of any out-of-tree -+modules). -+ -+If we mark a structure or union type as seen, we must mark aggregate types that -+appear directly within that type's DIE as seen as well. This is done by the -+recursive function mark_seen_contained(). You might wonder what the point of it -+is: such types surely cannot appear anywhere else, and any duplication will -+precisely match the duplication of the containing type. The answer is that they -+can still be referenced as the type of structure members of their containing -+structure, e.g. in -+ -+struct foo { -+ struct bar { -+ } *baz; -+ struct bar wombat[16]; -+}; -+ -+Here, a reference to 'struct bar' appears in 'struct foo', and CTF is -+constructed for it, even though it is not a top-level DIE. In GCC 4.8+, a -+reference to the 16-element array-of-struct-bar can also appear in 'struct foo': -+in fact almost anything can appear in there if used nowhere else in the -+translation unit, even base types. So we look for the appearance of anything -+which we can assemble into CTF (anything in the assembly_tab) other than -+members, since members cannot be used as the type of anything else, and mark -+them all as seen in this module. (Nearly everything in a structure or union is -+a member, so this ends up skipping almost but not quite everything.) -+ -+ -+If we find that a type has appeared more than once in different kernel modules -+(or in a module and in the core kernel), we must mark it as shared. This is -+done via mark_shared(), which is both a function that can be directly called -+(e.g. from detect_duplicates()) and a type_id() callback. If it is called -+directly, it immediately reinvokes itself as a type_id() callback, which calls -+it for the base type of the type in question and then for all qualifiers up the -+type ID stack, marking them all as shared if they weren't already. -+ -+If a structure or union is marked as shared, the types of its members are also -+marked as shared via a recursive call (even if they have already been so marked: -+just because this structure is of a type we've already seen, in a location we've -+already seen, doesn't mean that someone might not have legitimately used -+#defines to add extra members to the end of it, and we need to mark them as -+shared too). We track structures that have been seen in this translation unit -+and avoid recursing into them, to avoid an infinite loop in cases like this: -+ -+struct one; -+struct two { -+ struct one *foo; -+}; -+ -+struct one { -+ struct two *foo; -+} -+ -+The types being pointers does not help here -- the marking of 'struct one *' as -+shared will automatically mark 'struct one' as shared too, because otherwise we -+might have a structure in the shared type repository whose members' types -+could not be found there. -+ -+ -+The second pass is the 'alias fixup' pass, implemented by -+detect_duplicates_alias_fixup(). This pass serves to detect unshared opaque -+types whose non-opaque equivalents are shared, and vice versa. It is executed -+repeatedly until no types have been marked as shared for an entire iteration, -+but is considerably faster per iteration than the first pass, which often -+consumes more than half of dwarf2ctf's total runtime. We work in one direction -+only, looking for non-opaque structures, unions or enums which have structure -+tags. (Structures without tags cannot have opaque variants, and structures -+which are opaque will have non-opaque cousins somewhere, or can be emitted to -+the CTF as an opaque structure harmlessly since they truly have no members and -+are probably manipulated only via casts.) -+ -+We identify structures, unions or enums with tags via the type_id() callback -+is_named_struct_union_enum(), but cannot determine if something is an opaque -+structure at this stage. Instead, we do that after the callback, checking to -+see if the first four characters of the type ID are "////": this relies on the -+fact that GCC never gives opaque structures line numbers in DWARF. We do the -+actual checking and marking of each non-opaque structure using -+detect_duplicates_alias_fixup_internal(), which is yet another type_id() -+callback. -+ -+This function directly synthesises the name which this structure's opaque cousin -+would have, if it existed, by stripping off the line number and filename and -+replacing them with '////', and sees if either of these types have been marked -+as shared while the other has not. If the opaque type is shared, the non-opaque -+variant can be marked shared using the same recursive mark_shared() function as -+before (thus marking the types of all its members and types it depends upon as -+shared too). If it is the opaque type that needs marking shared, this will not -+work, since mark_shared() takes a DWARF DIE, and we don't have one for the -+opaque type, just a faked-up type ID. However, since an opaque type doesn't -+have any members that need recursively tracing, we don't need access to its -+DWARF DIE to figure them out, and can just mark it as shared directly, via an -+insert into the id_to_module hash. -+ -+Since this function is a type_id() callback, it is called not just for -+structures but for types based on them (e.g. in type_id form, "struct foo const -+* [43] volatile *"); at every level of this declarator stack, a shared opaque -+base type will contaminate its non-opaque cousins with sharedness, and vice -+versa. This handles situations in which, say, the opaque version of "struct foo -+const * [43]" was used by more than one module and was marked as shared: the -+marking process will have marked the opaque versions of "struct foo const * -+[43]", "struct foo const *", "struct foo const" and "struct foo" as shared, but -+will not have touched any non-opaque versions of these types which may exist -+until this routine runs. It also handles typedefs to structures with no need -+for any extra code. -+ -+This whole alias fixup process needs to be repeated, because whenever a -+non-opaque type is marked as shared and its member's types traced and marked -+shared, *those* may themselves be structure types with corresponding opaque or -+non-opaque variants, and when they are opaque types the non-opaque variant that -+alias fixup works from may already have passed under the DWARF walker's gaze: so -+another pass over the kernel's DWARF is necessary to be sure we catch it. -+mark_shared() thus sets a flag that scan_duplicates() recognizes and uses to -+trigger another run through the alias fixup pass. -+ -+ -+There are a very few modules that this algorithm doesn't work for. One example -+is snd-ens1371, which reads, in toto -+ -+#define CHIP1371 -+#include "ens1370.c" -+ -+and ens1370.c (itself a distinct kernel module) then defines a 'struct ensoniq' -+whose members vary depending on whether CHIP1371 is defined. Obviously, it is -+impossible to share any such types between kernel modules even though their -+names are the same and they are defined in the same place in the same source -+file in both cases. But this sort of trickery is very rare, so we simply -+implement a 'deduplication blacklist' of modules which will not introduce new -+types into the shared CTF repository, and who do not participate in alias fixup -+detection either. Detecting these cases in order to blacklist them is harder: -+no automated system has yet been implemented, although instances where #defines -+of this nature introduce new types that are then used by later members will -+cause assertion failures inside dwarf2ctf which might be a clue. So it is -+possible that some examples have been missed. (The blacklist only applies to -+cases where structure members change within a single kernel build, so cases -+where structures have members whose presence depends on CONFIG_* values are -+quite all right, as are cases where #defines are introduced by one translation -+that #includes another that then goes on to define whole new structures: it is -+only cases where modules #define something that changes the definition of -+individual possibly-shared types that will need blacklisting.) -+ -+ -+There are a few even worse cases where a single structure is defined with -+different members in different translation units within a single module. In -+this case we can do nothing at all, since our output representation describes -+only a single type per module: we implement a 'member blacklist' which bans -+emission of affected members entirely, leaving a description of a structure with -+an undescribed hole in it. -+ -+ -+CTF construction -+---------------- -+ -+ process_file() -+[R] process_tu_func() -+[C] assembly_filter_tab[] -+[C] construct_ctf() -+[ 2] construct_ctf_id() -+[R3] die_to_ctf() -+ assembly_tab[] -+[C] -> assemble_ctf_base() -+ -> assemble_ctf_pointer() -+ | assemble_ctf_array() -+ | assemble_ctf_array_dimension() -+ | assemble_ctf_typedef() -+ | assemble_ctf_cvr_qual() -+ | assemble_ctf_variable() -+ lookup_ctf_type() -+[ 2] construct_ctf_id() -+ -> assemble_ctf_enumeration() -+ -> assemble_ctf_enumerator() -+ -> assemble_ctf_struct_union() -+ -> assemble_ctf_su_member() -+ member_blacklisted() -+[ 3] die_to_ctf() -+[ 2] construct_ctf_id() -+[C] cleanup_sou_member_count() -+ -+The next stage after the detection of duplicate and cross-module shared types is -+to generate CTF. We generate all CTF at once before emitting it: this is -+potentially somewhat wasteful of memory, but in practice has not proved to be a -+problem: substantially less memory is used than is used by other parts of the -+kernel build, unless -DDEBUG is enabled. Its job is to look through the -+kernel's type DWARF (via process_file(), as usual) and create CTF for every -+file-or-global-scope type and every externally-visible variable in the CTF file -+in which the duplicate detection pass has said that type should appear. -+(Variables are treated exactly like types: it just so happens that they are -+never shared because no type or variable can depend upon them, so they always go -+directly into the appropriate module and never into the shared type repository.) -+ -+At this stage, the 'CTF files' are not actually files but rather ctf_file_t -+structures maintained by libdtrace-ctf and tracked in the per_module hash, along -+with other information which varies by module name. We track every single -+individual type in the CTF file in the id_to_type hash, which maps type IDs to -+pairs of (CTF file ID, ctf type ID): this lets us use the type IDs described -+above when considering cross-references within CTF files (e.g. from one CTF type -+to a type it depends upon). -+ -+The most important functions in this phase are: -+ -+ - construct_ctf_id(), the top-level process_file() callback which is given a -+ DWARF DIE, looks in module_to_ctf_file for the CTF file where this type -+ should land (creating it if necessary), makes sure a type with this type ID -+ has not already been created there, calls die_to_ctf() to create the CTF, -+ notes where it was created in id_to_type, and handles errors. -+ -+ - die_to_ctf(), a recursive function which calls the assembly function for the -+ DIE it is given and all its immediate children, with special-case handling -+ for tagged structures and unions. If you want to create a type but not note -+ where it was created for future lookups by lookup_ctf_type(), this is what to -+ call. (This is only done currently for unnamed structures/unions.) -+ -+ - lookup_ctf_type(), which is called by CTF assembly functions for those -+ types that depend upon other types: it calls construct_ctf_id() again -+ to construct the type, and double-checks that all such types appear -+ either in the module we are constructing types for, or in the shared CTF -+ module. CTF represents all function pointers the same way, and has a -+ special type ID for 'void', so we special-case both of these cases. -+ -+These functions are mostly straightforward (though highly recursive, with all -+three plus CTF construction functions participating in loop 2 above, -+die_to_ctf() calling itself directly, and even one situation, the -+already-mentioned unnamed structures/unions, in which die_to_ctf() is directly -+called back by a CTF construction function, in loop 3 above.) -+ -+ -+There are a few subtleties, though. Firstly, error handling. We consider that -+errors that will lead to unusable CTF are fatal: mostly, these are errors where -+a bug in the deduplicator has failed to trace types correctly and has left at -+least one type in the shared module depending on a type in a non-shared module, -+or has failed to mark a type as shared at all. In all these cases, you'll -+eventually get an error from lookup_ctf_type() of the general form -+ -+blah.c:413:foo_t: Internal error: lookup of flob found in different file. -+ -+The first two parts of this error are the translation unit and line number the -+type being assembled (usually a structure or union) was found in: foo_t is the -+name of the type being assembled. The type of the structure being looked up -+appears nowhere, because we don't know it, but the name of the member is given -+("flob" above, or "(unnamed)" if we don't know it). If you want more -+information, you can pass -DDEBUG to the compilation of dwarf2ctf.c in -+scripts/dwarf2ctf/Makefile, and rerun dwarf2ctf, and you'll get the module and -+filename in which both the originating and the target types appear. In order to -+actually track down the bug you'll probably have to run dwarf2ctf with -+DWARF2CTF_TRACE set in the environment, and look at the place where the target -+type was deduplicated, and try to figure out why the deduplicator didn't trace -+the reference to the type in foo_t correctly. -+ -+There is another kind of error, though: a failure to assemble a single type, -+perhaps because DWARF was emitted that we don't know how to understand (this is -+particularly likely in structure assembly, where we are highly dependent on the -+form of the DWARF that GCC happens to emit for DW_AT_member_location). We pass -+an 'enum skip_type' around, which has three possible values, one of which is -+SKIP_ABORT. Before each type is assembled, we call ctf_snapshot() to take a -+snapshot of the variable-plus-type set in the CTF file we're working over. If a -+SKIP_ABORT propagates up to construct_ctf_id(), we call ctf_rollback(), which -+throws away every type constructed since the last ctf_snapshot() -- i.e., the -+specific erroneous type we've just been working on. (We might have emitted some -+parts of it and then failed, so we should try to clean up). -+ -+A SKIP_ABORT is not fatal unless DEBUG is defined: its only effect is to omit -+one single type from the resulting CTF, which is probably still usable. -+ -+libdtrace-ctf causes additional problems here. It can only see the types we -+added once the notably expensive function ctf_update() is called. This takes -+the in-memory structures and serializes them (all of them, every time). This -+only affects libctf when structure and union members are added: libctf needs to -+know the sizes and alignments of the types of those members, which might quite -+possibly just have been added, e.g. if this structure contains a pointer to its -+own structure tag. So, when we insert a member in assemble_ctf_su_member(), we -+note a bad type-ID error and do a ctf_update() on the file we're working over -+and try again: even then that can fail if the type was added to the shared -+repository, so we do a ctf_update() on *that* and try again, and only if that -+fails do we declare a SKIP_ABORT error. (We check the shared repository last -+because it is very large, so takes longer to serialize than other CTF files do). -+ -+The need to keep the number of calls to ctf_update() down means we must avoid -+all access to the CTF types we are assembling if we can possibly get at the same -+data another way. Hence the member_counts hash, a member of the per_module -+state, which tracks the number of members in structures with a given C-style -+name and their CTF IDs. This structure allows us to handle the (valid) C idiom -+of redeclaring the same structure with a different number of members, merging -+the definitions across translation units and discarding them (iff the structure -+was unshared) when we transition into a new module, without ever having to -+consult the CTF to see how many members we put into it. (We have to use the -+C-style name here, because by definition the type IDs of such redeclared -+structures will be different, since a type ID contains a line number and -+translation unit name.) -+ -+ -+There's more error-handling complexity inside die_to_ctf(), where errors from -+libdtrace-ctf are actually reported (there may be multiple of them for a single -+type, e.g. if we are assembling a structure and several members somehow refer to -+a type we do not know about). -+ -+die_to_ctf() itself has the sort of parameter list that can make people swear -+off C for life. It is largely explained in the description of ctf_assembly_fun. -+Most parts of it are hardly used in the function itself, just passed down to CTF -+assembly functions. -+ -+Finally, we must note the override flag. Both die_to_ctf() and -+construct_ctf_id() return a CTF ID. This is thrown away by the DWARF walking -+code (the function construct_ctf() exists just for that purpose), but when -+called by lookup_ctf_type(), this CTF ID is taken to be the single ID of the CTF -+type that's just been assembled. Normally this is the same as the CTF ID -+returned by the CTF assembly function for the top-level DWARF DIE, but there are -+a few structures for which we want to return the result of some other CTF -+assembly function. -+ -+The only currently-existing example is array dimensions, which DWARF represents -+as a typed array DIE whose child is a dimension, but which CTF represents as an -+array-with-dimensions that you can't change afterwards. We can't assemble an -+'array' at the top level because we don't know how big it is, but we have to -+track the type recorded there somehow. We handle this by having -+assemble_ctf_array(), the assembly function for the top-level DW_TAG_array_type -+DIE, simply look up the type of the array's members and return its ID as if it -+had just constructed it, after which assemble_ctf_array_dimension(), the -+assembly function for DW_TAG_subrange_type, actually constructs the array, -+wrapping it around the CTF 'ID' 'assembled' by the parent and setting the -+override flag to make sure that this is what is really recorded. -+ -+ -+CTF construction functions -+-------------------------- -+ -+Each CTF construction function takes a single DWARF DIE and turns it into CTF, -+somehow. They are laid out in the assembly table described in 'toplevel DWARF -+walkers' above. They all start the same way, with a series of CTF_DW_ENFORCE or -+CTF_DW_ENFORCE_NOT assertions. These guard against corrupted DWARF missing some -+of the attributes we need, or DWARF containing attributes which indicate that we -+can't handle the content (e.g. DW_AT_signature or DW_AT_specification on -+structures, which would both indicate this is DWARF 4, which we can't handle -+yet.) -+ -+We'll go through these functions one by one, pointing out anything that -+maintainers should be aware of. -+ -+ -+assemble_ctf_base() assembles all integral base types (DW_TAG_base_type) and -+transforms them into the corresponding CTF type. The functions we need to call -+for this in the CTF API all have the same type signature but have different -+names; CTF also distinguishes between the various differently-sized -+floating-point types, so we must figure out from the type size which type a -+given DWARF base type is referring to. We map from DWARF encoding to a triple -+of (CTF addition function, CTF integral type, type size) where the latter is -+optional and depends on the size of the DWARF type we are encoding and the size -+of various floating_point types on the current system. (This does mean that -+cross-compilation using dwarf2ctf is likely to fail fairly often: we need -+machinery to determine the sizeof() types on the target system before that can -+function.) -+ -+This sizeof()-based search procedure is why we do not currently support -+DW_AT_bit_size for base types: we could easily support it for sizes modulo 8, -+but GCC happens to emit DW_AT_byte_size in this case. In C DW_AT_bit_size is -+likely to be emitted only for bitfields in structures anyway, not for base -+types. -+ -+ -+assemble_ctf_pointer() and assemble_ctf_typedef() are trivial: look up the -+associated type with lookup_ctf_type() and assemble the appropriate thing. -+assemble_ctf_cvr_qual() is almost as trivial, but has to figure out which of -+const, volatile or restrict it was called for and call the corresponding CTF API -+function. assemble_ctf_enumeration() and assemble_ctf_enumerator() are quite -+simple too. -+ -+ -+assemble_ctf_variable() has a couple of extra complexities: we unconditionally -+set the skip parameter to SKIP_SKIP, suppressing recursion into containing DIEs, -+since we already know we won't care about any of them. Also, while the -+deduplication pass unifies opaque and non-opaque structures into the same type, -+it never makes sure that variables declared in the same header by translation -+units which have opaque versus non-opaque structures in scope are deduplicated. -+e.g. you could well end up with these two type IDs, depending on whether -+<linux/pid_namespace.h> was included before <linux/pid.h> in a given translation -+unit: -+ -+////struct pid_namespace var init_pid_ns -+/path/to/kernel/include/linux/pid_namespace.h//19//struct pid_namespace var init_pid_ns -+ -+These variables both refer to the same type, but deduplicating them would -+require an additional deduplication pass. Since variables are always terminal -+and nothing can refer to them, nothing will ever look up any of those type IDs -+(since the only thing that looks up type IDs is code that is searching for type -+that other types depend on). So we don't care about this duplication and -+running an additional deduplication pass to eliminate it would slow down -+dwarf2ctf to no good end. It's better just to ignore duplicate errors from -+ctf_add_variable(). -+ -+ -+assemble_ctf_array() and assemble_ctf_array_dimension() we talked about -+above. One last subtlety remains, which is that figuring out the actual -+dimensionality of an array is complicated enough that it has been hived off into -+a private_subrange_dimension() function, called both from here and from -+type_id(). Arrays with neither a DW_AT_upper_bound nor a DW_AT_count, and -+arrays without an indexing type, are best considered flexible arrays; arrays -+whose upper bound or count is not unsigned or signed integral data are also -+flexible (perhaps they're using a full-blown location list, but we can't encode -+that in CTF so we treat it as flexible); and if an upper bound is used, we want -+to add one to its value before treating it as a count of elements. -+ -+ -+This leaves structure/union assembly, both of which are assembled by the same -+pair of functions, assemble_ctf_struct_union for the type itself and -+assemble_ctf_su_member() for the individual members. As with -+assemble_ctf_cvr_qual(), we have to look at the tag to figure out which CTF -+function to use to do the assembly, but we have an extra constraint: it is -+perfectly idiomatic C to declare a structure repeatedly with a different number -+of members every time. This is perfectly permissible as long as the leading -+portions of all declarations match. We do not verify this (we hope that the -+compiler will diagnose it, which it will unless the conflicting declarations -+cross modules), though perhaps we should: we simply look up the structure in the -+CTF and the DWARF and skip assembly of the structure members via SKIP_SKIP if -+the already-assembled structure has at least as many members as the current one. -+ -+assemble_ctf_su_member() is by far the most complex of the assembly functions. -+It has to handle members that already exist, members that need assembly, members -+that correspond to unnamed structure members, numerous different ways of -+representing structure offsets and members with no offset at all. -+ -+The offset computation is quite laborious and by no means complete: a complete -+implementation would require an interpreter for DWARF location lists, which is -+total overkill given that in DWARF2 GCC emits a totally stereotyped location -+list, and in DWARF3+ we don't need location list parsing at all. CTF wants an -+offset in bits. -+ -+We have five cases: -+ - for DW_AT_data_bit_offset, we just use the offset unchanged. -+ -+ - for DW_AT_data_member_location with an integral form (data2, data4, data8, -+ udata, or sdata) we just look it up and multiply it by eight, adding the -+ parent's DW_AT_bit_offset to handle structures nested inside other -+ structures. -+ -+ - for DW_AT_data_member_location with a block form, we make sure that the list -+ is of one particular simple form (DW_OP_plus_uconst and a constant value in -+ bytes), and abort assembly otherwise. The only case I know of where this -+ test will trip is C++ virtual bases: if people are using C++ code with -+ virtual bases inside the kernel they deserve sympathy, but probably not -+ support in the code. CTF can't represent C++ types in any case. -+ -+ - for expression location lists, or anything else that we don't understand, we -+ simply die (we could simply skip the type, but this seems serious enough that -+ dying is warranted). -+ -+ - with none of these present, we have no offset: the member is at the same -+ location as the start of the structure. -+ -+But where is the 'start of the structure'? That depends on whether this is an -+unnamed struct/union member (usually a union). If it is, we want to fold all -+its members directly into the parent structure, with their offsets increased by -+the offset of the unnamed member as a whole. This is done by directly calling -+die_to_ctf() with the first child of the anonymous member's type and with all -+other parameters set as if the parent DIE was the current structure, thus -+fooling die_to_ctf() into believing that these members are members of the -+current structure, not of the anonymous one. The offset-increasing magic is -+done via the parent_bias parameter to die_to_ctf() and all the CTF construction -+functions: it is ignored by all of them except for assemble_ctf_su_member() -+itself, which adds the parent bias onto the normally-computed offset, and is -+otherwise passed down unchanged to all children. This means that even this -+terribly contrived case works: -+ -+struct horror { -+ int spacer; -+ union { -+ struct { -+ int spacer; -+ struct { -+ int foo; -+ int bar; -+ } b; -+ } a; -+ }; -+}; -+ -+In this situation, horror.a.b.bar may have: -+ -+ - a nonzero parent_bias due to the offset of the anonymous union in 'struct -+ horror' -+ - a nonzero offset due to the offset of 'bar' in its containing structure -+ - if DW_AT_data_member_location with integral form is used, a nonzero -+ DW_AT_bit_offset of 'b' in 'a' -+ -+If this is not an anonymous union, we are dealing with only one member: we look -+up its type and add it reasonably conventionally via ctf_add_member_offset(). -+Even here there are subtleties: we use construct_ctf_id() directly rather than -+via lookup_ctf_type() so we can get a better error message on failure, and we -+ignore any duplicate-member errors because this is probably a sign that this -+structure has already been encountered and we are working through another -+instance of it with more members. -+ -+ -+Writeout -+-------- -+ -+ write_types() -+ -+This couldn't really be simpler, as the trivial call graph shows. We create an -+output directory with the requested name, then work over the entire -+module_to_ctf_file hash, writing out every CTF file into a new suitably-named -+file via zlib's compressed file I/O functions. -diff --git a/Documentation/kbuild/kconfig.rst b/Documentation/kbuild/kconfig.rst -index dce6801d66c9..a9a855f894b3 100644 ---- a/Documentation/kbuild/kconfig.rst -+++ b/Documentation/kbuild/kconfig.rst -@@ -154,6 +154,11 @@ KCONFIG_AUTOCONFIG - This environment variable can be set to specify the path & name of the - "auto.conf" file. Its default value is "include/config/auto.conf". - -+KCONFIG_TRISTATE -+---------------- -+This environment variable can be set to specify the path & name of the -+"tristate.conf" file. Its default value is "include/config/tristate.conf". -+ - KCONFIG_AUTOHEADER - ------------------ - This environment variable can be set to specify the path & name of the -diff --git a/Documentation/process/changes.rst b/Documentation/process/changes.rst -index dac17711dc11..1bce2aab4109 100644 ---- a/Documentation/process/changes.rst -+++ b/Documentation/process/changes.rst -@@ -56,9 +56,14 @@ iptables 1.4.2 iptables -V - openssl & libcrypto 1.0.0 openssl version - bc 1.06.95 bc --version - Sphinx\ [#f1]_ 1.3 sphinx-build --version -+elfutils\ [#f2]_ 0.156 eu-readelf --version -+pkg-config\ [#f2]_ 0.16 pkg-config --version -+glib\ [#f2]_ 2.x pkg-config --exists glib-2.0 && echo present -+libdtrace-ctf\ [#f2]_ 1.1 - ====================== =============== ======================================== - - .. [#f1] Sphinx is needed only to build the Kernel documentation -+.. [#f2] This is needed at build-time when CTF or DTrace are enabled - - Kernel compilation - ****************** -@@ -94,7 +99,8 @@ pkg-config - The build system, as of 4.18, requires pkg-config to check for installed - kconfig tools and to determine flags settings for use in - 'make {g,x}config'. Previously pkg-config was being used but not --verified or documented. -+verified or documented. dwarf2ctf also relies on it during 'make ctf' and -+while building out-of-tree modules with CONFIG_CTF enabled. - - Flex - ---- -@@ -371,6 +377,21 @@ OpenSSL - - - <https://www.openssl.org/> - -+elfutils -+-------- -+ -+- <https://fedorahosted.org/elfutils/> -+ -+glib 2.x -+-------- -+ -+- <http://www.gtk.org/> -+ -+libdtrace-ctf -+------------- -+ -+- <https://oss.oracle.com/git/?p=libdtrace-ctf.git> -+ - System utilities - **************** - -diff --git a/Makefile b/Makefile -index a6b2e64bcf6c..e94e5bfc9c4f 100644 ---- a/Makefile -+++ b/Makefile -@@ -1166,7 +1166,7 @@ cmd_link-vmlinux = \ - $(CONFIG_SHELL) $< "$(LD)" "$(KBUILD_LDFLAGS)" "$(LDFLAGS_vmlinux)"; \ - $(if $(ARCH_POSTLINK), $(MAKE) -f $(ARCH_POSTLINK) $@, true) - --vmlinux: scripts/link-vmlinux.sh autoksyms_recursive $(vmlinux-deps) FORCE -+vmlinux: scripts/link-vmlinux.sh autoksyms_recursive $(vmlinux-deps) modules_thick.builtin FORCE - +$(call if_changed,link-vmlinux) - - targets := vmlinux -@@ -1406,6 +1406,45 @@ modules.order: $(subdir-modorder) FORCE - - targets += modules.order - -+ifneq (CONFIG_CTF@,'@') -+ -+# We need to force everything to be built, since we need the .o files below. -+KBUILD_BUILTIN := 1 -+ -+# This contains all the object files that are built directly into the -+# kernel (including built-in modules), for consumption by dwarf2ctf in -+# Makefile.modpost. -+# This is made doubly annoying by the presence of '.o' files which are actually -+# thin ar archives, and the need to support file(1) versions too old to -+# recognize them as archives at all. (So we assume that everything that is not -+# an ELF object is an archive.) -+ifeq ($(SRCARCH),x86) -+objects.builtin: $(vmlinux-dirs) $(if $(KBUILD_BUILTIN),bzImage) FORCE -+else -+objects.builtin: $(vmlinux-dirs) $(if $(KBUILD_BUILTIN),vmlinux) FORCE -+endif -+ @echo $(KBUILD_VMLINUX_OBJS) | \ -+ tr " " "\n" | grep "\.o$$" | xargs -r file | \ -+ grep ELF | cut -d: -f1 > objects.builtin -+ @for archive in $$(echo $(KBUILD_VMLINUX_OBJS) |\ -+ tr " " "\n" | xargs -r file | grep -v ELF | cut -d: -f1); do \ -+ $(AR) t "$$archive" >> objects.builtin; \ -+ done -+ -+ctf: vmlinux.ctfa -+PHONY += ctf -+ -+# Making CTF needs the builtin files unless out-of-tree. -+ifeq ($(KBUILD_EXTMOD),) -+vmlinux.ctfa: modules_thick.builtin objects.builtin -+endif -+vmlinux.ctfa: -+ $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modfinal vmlinux.ctfa -+else -+PHONY += objects.builtin -+objects.builtin: -+endif -+ - # Target to prepare building external modules - PHONY += modules_prepare - modules_prepare: prepare -@@ -1428,6 +1467,9 @@ _modinst_: - @sed 's:^:kernel/:' modules.order > $(MODLIB)/modules.order - @cp -f modules.builtin $(MODLIB)/ - @cp -f $(objtree)/modules.builtin.modinfo $(MODLIB)/ -+ @if [ -f $(objtree)/vmlinux.ctfa ] ; then \ -+ cp -f $(objtree)/vmlinux.ctfa $(MODLIB)/kernel ; \ -+ fi - $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modinst - - # This depmod is only for convenience to give the initial -@@ -1459,6 +1501,23 @@ modules modules_install: - - endif # CONFIG_MODULES - -+# modules_thick.builtin maps from kernel modules (or rather the object file -+# names they would have had had they not been built in) to their constituent -+# object files: dwarf2ctf uses this to determine which modules any given object -+# file is part of. (We cannot eliminate the slight redundancy here without -+# double-expansion.) -+ -+modthickbuiltin-dirs := $(addprefix _modthickbuiltin_, $(build-dirs)) -+ -+modules_thick.builtin: $(modthickbuiltin-dirs) -+ $(Q)$(AWK) '!x[$$0]++' $(addsuffix /$@, $(build-dirs)) > $@ -+ -+PHONY += $(modthickbuiltin-dirs) -+# tristate.conf is not included from this Makefile. Add it as a prerequisite -+# here to make it self-healing in case somebody accidentally removes it. -+$(modthickbuiltin-dirs): include/config/tristate.conf -+ $(Q)$(MAKE) $(modbuiltin)=$(patsubst _modthickbuiltin_%,%,$@) builtin-file=modules_thick.builtin -+ - ### - # Cleaning is done on three levels. - # make clean Delete most generated files -@@ -1467,9 +1526,10 @@ endif # CONFIG_MODULES - # make distclean Remove editor backup files, patch leftover files and the like - - # Directories & files removed with 'make clean' --CLEAN_FILES += include/ksym vmlinux.symvers \ -- modules.builtin modules.builtin.modinfo modules.nsdeps \ -- compile_commands.json -+CLEAN_FILES += include/ksym .ctf vmlinux.symvers \ -+ modules.builtin modules.builtin.modinfo objects.builtin \ -+ modules.nsdeps compile_commands.json \ -+ .ctf.filelist .ctf.filelist.raw - - # Directories & files removed with 'make mrproper' - MRPROPER_FILES += include/config include/generated \ -@@ -1564,6 +1624,8 @@ help: - @echo ' (requires a recent binutils and recent build (System.map))' - @echo ' dir/file.ko - Build module including final link' - @echo ' modules_prepare - Set up for building external modules' -+ @echo ' ctf - Generate CTF type information for DTrace, installed by ' -+ @echo ' make modules_install' - @echo ' tags/TAGS - Generate tags file for editors' - @echo ' cscope - Generate cscope index' - @echo ' gtags - Generate GNU GLOBAL index' -@@ -1825,7 +1887,7 @@ clean: $(clean-dirs) - -o -name '*.symtypes' -o -name 'modules.order' \ - -o -name '.tmp_*.o.*' \ - -o -name '*.c.[012]*.*' \ -- -o -name '*.ll' \ -+ -o -name '*.ll' -o -name '*.ctfa' \ - -o -name '*.gcno' \) -type f -print | xargs rm -f - - # Generate tags for editors -diff --git a/lib/Kconfig b/lib/Kconfig -index b46a9fd122c8..e2906daac926 100644 ---- a/lib/Kconfig -+++ b/lib/Kconfig -@@ -582,6 +582,18 @@ config DIMLIB - # - config LIBFDT - bool -+# -+# CTF support is select'ed if needed -+# -+config CTF -+ bool "Compact Type Format generation" -+ default n -+ select STRIP_ASM_SYMS -+ depends on DEBUG_INFO && !DEBUG_INFO_REDUCED && !DEBUG_INFO_SPLIT && !DEBUG_INFO_DWARF4 && DTRACE -+ help -+ Emit a compact, compressed description of the kernel's datatypes and -+ global variables into the vmlinux.ctfa archive (for in-tree modules) -+ or into .ctf sections in kernel modules (for out-of-tree modules). - - config OID_REGISTRY - tristate -diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include -index 08e011175b4c..d3c6f0f56e65 100644 ---- a/scripts/Kbuild.include -+++ b/scripts/Kbuild.include -@@ -157,6 +157,12 @@ ld-ifversion = $(shell [ $(ld-version) $(1) $(2) ] && echo $(3) || echo $(4)) - # $(Q)$(MAKE) $(build)=dir - build := -f $(srctree)/scripts/Makefile.build obj - -+### -+# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.modbuiltin obj= -+# Usage: -+# $(Q)$(MAKE) $(modbuiltin)=dir -+modbuiltin := -f $(srctree)/scripts/Makefile.modbuiltin obj -+ - ### - # Shorthand for $(Q)$(MAKE) -f scripts/Makefile.dtbinst obj= - # Usage: -diff --git a/scripts/Makefile b/scripts/Makefile -index b5418ec587fb..041bcf48cc5c 100644 ---- a/scripts/Makefile -+++ b/scripts/Makefile -@@ -34,6 +34,7 @@ targets += module.lds - - subdir-$(CONFIG_GCC_PLUGINS) += gcc-plugins - subdir-$(CONFIG_MODVERSIONS) += genksyms -+subdir-$(CONFIG_CTF) += dwarf2ctf - subdir-$(CONFIG_SECURITY_SELINUX) += selinux - - # Let clean descend into subdirs -diff --git a/scripts/Makefile.modbuiltin b/scripts/Makefile.modbuiltin -new file mode 100644 -index 000000000000..f2c085e8640f ---- /dev/null -+++ b/scripts/Makefile.modbuiltin -@@ -0,0 +1,60 @@ -+# SPDX-License-Identifier: GPL-2.0 -+# ========================================================================== -+# Generating modules_thick.builtin -+# ========================================================================== -+ -+src := $(obj) -+ -+PHONY := __modbuiltin -+__modbuiltin: -+ -+include include/config/auto.conf -+# tristate.conf sets tristate variables to uppercase 'Y' or 'M' -+# That way, we get the list of built-in modules in obj-Y -+include include/config/tristate.conf -+ -+include scripts/Kbuild.include -+ -+ifdef building_out_of_srctree -+# Create output directory if not already present -+_dummy := $(shell [ -d $(obj) ] || mkdir -p $(obj)) -+endif -+ -+# The filename Kbuild has precedence over Makefile -+kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src)) -+kbuild-file := $(if $(wildcard $(kbuild-dir)/Kbuild),$(kbuild-dir)/Kbuild,$(kbuild-dir)/Makefile) -+include $(kbuild-file) -+ -+include scripts/Makefile.lib -+__subdir-Y := $(patsubst %/,%,$(filter %/, $(obj-Y))) -+subdir-Y += $(__subdir-Y) -+subdir-ym := $(sort $(subdir-y) $(subdir-Y) $(subdir-m)) -+subdir-ym := $(addprefix $(obj)/,$(subdir-ym)) -+pathobj-Y := $(addprefix $(obj)/,$(obj-Y)) -+ -+modthickbuiltin-subdirs := $(patsubst %,%/modules_thick.builtin, $(subdir-ym)) -+modthickbuiltin-target := $(obj)/modules_thick.builtin -+ -+__modbuiltin: $(obj)/$(builtin-file) $(subdir-ym) -+ @: -+ -+$(modthickbuiltin-target): $(subdir-ym) FORCE -+ $(Q) $(foreach mod-o, $(filter %.o,$(obj-Y)),\ -+ printf "%s:" $(addprefix $(obj)/,$(mod-o)) >> $@; \ -+ printf " %s" $(sort $(strip $(addprefix $(obj)/,$($(mod-o:.o=-objs)) \ -+ $($(mod-o:.o=-y)) $($(mod-o:.o=-Y))))) >> $@; \ -+ printf "\n" >> $@; ) \ -+ cat /dev/null $(modthickbuiltin-subdirs) >> $@; -+ -+PHONY += FORCE -+ -+FORCE: -+ -+# Descending -+# --------------------------------------------------------------------------- -+ -+PHONY += $(subdir-ym) -+$(subdir-ym): -+ $(Q)$(MAKE) $(modbuiltin)=$@ builtin-file=$(builtin-file) -+ -+.PHONY: $(PHONY) -diff --git a/scripts/Makefile.modfinal b/scripts/Makefile.modfinal -index ae01baf96f4e..920545d75da9 100644 ---- a/scripts/Makefile.modfinal -+++ b/scripts/Makefile.modfinal -@@ -1,11 +1,21 @@ - # SPDX-License-Identifier: GPL-2.0-only - # =========================================================================== --# Module final link -+# Module final link and CTF generation - # =========================================================================== -+# 1) compile all <module>.mod.c files -+# 2) for external modules, generate CTF for the module (there is an extra, -+# externally-invoked target that does this for the entire kernel but does -+# not invoke the rst of the module-building process) -+# 3) final link of the module to a <module.ko> file -+ -+# We need secondary expansion for 'module-ctfs-modular-prereq', below. -+ -+.SECONDEXPANSION: - - PHONY := __modfinal - __modfinal: - -+include include/config/auto.conf - include $(srctree)/scripts/Kbuild.include - - # for c_flags -@@ -27,16 +37,141 @@ quiet_cmd_cc_o_c = CC [M] $@ - %.mod.o: %.mod.c FORCE - $(call if_changed_dep,cc_o_c) - -+# Generate CTF for the entire kernel, or for the module alone if this is a -+# build of an external module. -+ -+# These are overridden below for standalone modules only. -+module-ctfs-modular-prereq = -+module-ctfs-modular = -+module-ctf-flags = -+cmd_touch_ctf = -+ctf-dir = ///.nonexistent -+cmd-touch-ctf = @: -+ -+ifdef CONFIG_CTF -+ -+# This is quite tricky. If called for non-external-modules, dwarf2ctf needs to -+# be told about all the built-in objects as well as all the external modules -- -+# but Makefile.modpost only knows about the latter. So the toplevel makefile -+# emits the names of the built-in objects into a temporary file, which is -+# then catted and its contents used as prerequisites by this rule. -+# -+# We write the names of the object files to be scanned for CTF content into a -+# file, then use that, to avoid hitting command-line length limits. -+ -+ifeq ($(KBUILD_EXTMOD),) -+ctf-dir-mk := -+quiet_cmd_ctf = CTFA -+ cmd_ctf = scripts/dwarf2ctf/dwarf2ctf vmlinux.ctfa $(srctree) objects.builtin modules_thick.builtin $(srctree)/scripts/dwarf2ctf/member.blacklist $(ctf-filelist) -+ctf-builtins := objects.builtin -+ctf-builtins-prereq := $(ctf-builtins) -+ ctf-modules := $(shell find . -name '*.ko' -print) -+ctf-filelist := .ctf.filelist -+ctf-filelist-raw := .ctf.filelist.raw -+ctf-stamp := -+ -+else -+ctf-dir := $(KBUILD_EXTMOD)/.ctf -+ctf-dir-mk := $(ctf-dir) -+quiet_cmd_ctf = CTF -+ cmd_ctf = scripts/dwarf2ctf/dwarf2ctf $(ctf-dir) -e $(ctf-filelist) -+ctf-builtins := ////.no-builtins -+ctf-builtins-prereq := -+ctf-modules := $(modules:.ko=.o) -+ctf-filelist := $(ctf-dir)/$(notdir $(M)-extmod).ctf.filelist -+ctf-filelist-raw := $(ctf-dir)/$(notdir $(M)-extmod).ctf.filelist.raw -+ctf-stamp = $(ctf-dir)/$(notdir $(M)-extmod).stamp -+ -+# All the modules' CTF depends on the stamp file. -+ -+all-module-ctfs = $(addprefix $(ctf-dir)/,$(notdir $(modules:.ko=.mod.ctf))) -+$(all-module-ctfs): $(ctf-stamp) -+ -+endif -+ -+# Split a list up like shell xargs does. -+define xargs = -+$(1) $(wordlist 1,1024,$(2)) -+$(if $(word 1025,$(2)),$(call xargs,$(1),$(wordlist 1025,$(words $(2)),$(2)))) -+endef -+ -+$(ctf-filelist-raw): $(ctf-builtins-prereq) $(ctf-modules) -+ @rm -f $(ctf-filelist-raw); -+ @if [ -n "$(ctf-dir-mk)" ]; then \ -+ mkdir -p "$(ctf-dir-mk)"; \ -+ fi -+ $(call xargs,@printf "%s\n" >> $(ctf-filelist-raw),$^) -+ @touch $(ctf-filelist-raw) -+ -+$(ctf-filelist): $(ctf-filelist-raw) -+ @rm -f $(ctf-filelist); -+ @cat $(ctf-filelist-raw) | while read -r obj; do \ -+ case $$obj in \ -+ $(ctf-builtins)) cat $$obj >> $(ctf-filelist);; \ -+ *.a) ar t $$obj > $(ctf-filelist);; \ -+ *.builtin) cat $$obj >> $(ctf-filelist);; \ -+ *) echo "$$obj" >> $(ctf-filelist);; \ -+ esac; \ -+ done -+ @touch $(ctf-filelist) -+ -+ifeq ($(KBUILD_EXTMOD),) -+# The CTF depends on the output CTF file list, and that depends -+# on the .ko files for the modules. -+vmlinux.ctfa: $(ctf-filelist) -+ $(call if_changed,ctf) -+else -+ -+# The CTF depends on the output CTF file list, and that depends -+# on the .o files for the modules -+$(ctf-stamp): $(ctf-filelist) -+ $(call if_changed,ctf) -+ @shopt -s nullglob; \ -+ for name in $(ctf-dir)/*.ctf.new; do \ -+ $(srctree)/scripts/move-if-change $$name $${name%.new}; \ -+ done; \ -+ touch $(ctf-stamp) -+ -+# Expands to the names of the CTF files to be incorporated into this module. -+# The former is used in prerequisite lists, thanks to secondary expansion. -+ -+module-ctfs-modular-prereq = $$(addprefix $(ctf-dir)/,$$(notdir $$*.mod.ctf)) -+module-ctfs-modular = $(addprefix $(ctf-dir)/,$(notdir $*.mod.ctf)) -+ -+# Expands to the name of a CTF file, given a target of a module name given to -+# one of the link rules below. -+ -+ctf-module-name = $(addprefix $(ctf-dir)/,$(notdir $(basename $@)).mod.ctf) -+ -+# An objcopy --add-section argument to add the CTF section to a standalone -+# module. -+ -+module-ctf-flags = --add-section .ctf=$(ctf-module-name) -+ -+# We have to put content in our dummy no-CTF files because --add-section -+# in binutils 2.20 silently fails if asked to add an empty file as a section. -+ -+cmd_touch_ctf = @for name in $(filter $(ctf-dir)/%,$(module-ctfs-modular)); do \ -+ test -f $$name || dd if=/dev/zero of=$$name bs=1 count=1 2>/dev/null; \ -+ done -+ -+endif # KBUILD_EXTMOD -+ -+endif # !CONFIG_CTF -+ - ARCH_POSTLINK := $(wildcard $(srctree)/arch/$(SRCARCH)/Makefile.postlink) - - quiet_cmd_ld_ko_o = LD [M] $@ - cmd_ld_ko_o = \ - $(LD) -r $(KBUILD_LDFLAGS) \ - $(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \ -- -T scripts/module.lds -o $@ $(filter %.o, $^); \ -+ -T scripts/module.lds $(LDFLAGS_$(modname)) -o $@.tmp \ -+ $(patsubst $(ctf-dir)/%,,$(filter %.o, $^)) && \ -+ $(OBJCOPY) $(module-ctf-flags) $@.tmp $@ && rm -f $@.tmp ; \ - $(if $(ARCH_POSTLINK), $(MAKE) -f $(ARCH_POSTLINK) $@, true) - --$(modules): %.ko: %.o %.mod.o scripts/module.lds FORCE -+$(modules): %.ko: %.o %.mod.o scripts/module.lds $(module-ctfs-modular-prereq) FORCE -+ $(call cmd_touch_ctf) - +$(call if_changed,ld_ko_o) - - targets += $(modules) $(modules:.ko=.mod.o) -diff --git a/scripts/dwarf2ctf/.gitignore b/scripts/dwarf2ctf/.gitignore -new file mode 100644 -index 000000000000..e37b47cf3028 ---- /dev/null -+++ b/scripts/dwarf2ctf/.gitignore -@@ -0,0 +1 @@ -+dwarf2ctf -diff --git a/scripts/dwarf2ctf/Makefile b/scripts/dwarf2ctf/Makefile -new file mode 100644 -index 000000000000..2b40419add31 ---- /dev/null -+++ b/scripts/dwarf2ctf/Makefile -@@ -0,0 +1,10 @@ -+ifdef CONFIG_CTF -+hostprogs-always-$(CONFIG_CTF) := dwarf2ctf -+ -+dwarf2ctf-objs := dwarf2ctf.o eu_simple.o -+ -+HOSTCFLAGS_eu_simple.o := -I$(srctree)/scripts -+HOSTCFLAGS_dwarf2ctf.o := $(shell pkg-config --cflags glib-2.0) -I$(srctree)/scripts -+ -+HOSTLDLIBS_dwarf2ctf := -ldtrace-ctf -lelf -ldw $(shell pkg-config --libs glib-2.0) -lz -+endif -diff --git a/scripts/dwarf2ctf/dwarf2ctf.c b/scripts/dwarf2ctf/dwarf2ctf.c -new file mode 100644 -index 000000000000..ecd430174442 ---- /dev/null -+++ b/scripts/dwarf2ctf/dwarf2ctf.c -@@ -0,0 +1,4962 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * dwarf2ctf.c: Read in DWARF[23] debugging information from some set of ELF -+ * files, and generate CTF in correspondingly-named files, or in a single -+ * representation meant for mmapping. -+ * -+ * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#define _GNU_SOURCE 1 -+#include <stdio.h> -+#include <stdlib.h> -+#include <string.h> -+#include <errno.h> -+#include <stddef.h> -+#include <sys/stat.h> -+#include <sys/types.h> -+#include <fcntl.h> -+#include <limits.h> -+#include <endian.h> -+#include <unistd.h> -+ -+#include <libelf.h> -+#include <dwarf.h> -+#include <elfutils/libdwfl.h> -+#include <elfutils/libdw.h> -+#include <elfutils/version.h> -+#include <sys/ctf_api.h> -+#include <glib.h> -+ -+#include <eu_simple.h> -+ -+#ifndef PATH_MAX -+#define PATH_MAX 1024 -+#endif -+ -+#define __unused__ __attribute__((__unused__)) -+ -+/* -+ * If non-NULL, tracing is on. -+ */ -+static const char *trace; -+ -+/* -+ * Trace something. -+ */ -+#ifdef DEBUG -+#define dw_ctf_trace(format, ...) do { \ -+ if (trace) \ -+ fprintf(stderr, (format), ## __VA_ARGS__); \ -+} while (0) -+#else -+#define dw_ctf_trace(format, ...) -+#endif -+ -+/* -+ * Run dwarf2ctf over a single object file or set thereof. -+ * -+ * output_dir is the directory into which the CTF goes, if 'standalone', or the -+ * CTF archive file name otherwise. -+ */ -+static void run(char *output, int standalone); -+ -+/* -+ * Whether we are deduplicating. We do not deduplicate if run over external -+ * modules. -+ */ -+static int deduplicating; -+ -+/* -+ * A fully descriptive CTF type ID: both file and type ID in one place. -+ */ -+struct ctf_full_id { -+ ctf_file_t *ctf_file; -+ ctf_id_t ctf_id; -+#ifdef DEBUG -+ char module_name[PATH_MAX]; -+ char file_name[PATH_MAX]; -+#endif -+}; -+ -+/* -+ * A hash mapping 'atoms' (almost entirely type IDs) to nothing. -+ */ -+static GHashTable *atoms; -+ -+/* -+ * A mapping from the type ID of a DIE (see type_id()) to ctf_full_id_t's -+ * describing the type with that ID. The type ID is an atom. -+ * -+ * This is used to look up types regardless of which CTF file they may reside -+ * in. Not the same as a DWARF4 type signature because we must encode scope -+ * information which DWARF4 can encode in its DIE refs. -+ * -+ * (TODO: store a hash of the ID rather than the ID itself, to save memory. -+ * Makes debugging slightly harder though.) -+ */ -+static GHashTable *id_to_type; -+ -+/* -+ * A mapping from the type ID of a DIE (an atom) to the name of the module (and -+ * thus CTF table) incorporating that type. (Modules in this context, and -+ * throughout dwarf2ctf, are DTrace modules: a name without suffix or path.) -+ * -+ * This is used to merge types identical across modules (e.g. those in global -+ * header files). -+ */ -+static GHashTable *id_to_module; -+ -+/* -+ * Module-specific state. The module named 'vmlinux' is that corresponding to -+ * the types in always-built-in translation units; the module named 'shared_ctf' -+ * (not appearing in this mapping) is that corresponding to types shared between -+ * more than one module (even between two currently-built-in modules: we do not -+ * distinguish at this level between built-in modules and non-built-in modules.) -+ */ -+static GHashTable *per_module; -+ -+/* -+ * The data structure that per_module maps module names to. -+ */ -+struct per_module { -+ /* -+ * The CTF file containing the types in this module. -+ */ -+ ctf_file_t *ctf_file; -+ -+ /* -+ * A hash from a "CTF-form" structure name (in the form 's/u NAME') to -+ * a struct ctf_memb_count (see below). -+ */ -+ GHashTable *member_counts; -+}; -+ -+/* -+ * A count associating a type ID relating to a structure or union with a count -+ * of members in that structure. -+ */ -+struct ctf_memb_count { -+ ctf_id_t ctf_id; -+ size_t count; -+}; -+ -+/* -+ * A mapping from the absolute pathname of a TU to a hashtable mapping -+ * DIE offsets of child DIEs to DIE offsets of parents. Populated on first -+ * iteration. Contains only those DIEs that we know are necessary for other -+ * functions' use of this structure, to keep memory usage down. -+ */ -+static GHashTable *fn_to_die_to_parent; -+ -+/* -+ * Get a ctf_file out of the per_module hash for a given module. -+ */ -+static ctf_file_t *lookup_ctf_file(const char *module_name); -+ -+/* -+ * The names of the object files to run over. Except in -e mode, this comes -+ * straight from the module filelist passed in. -+ */ -+static char **object_names; -+static size_t object_names_cnt; -+ -+/* -+ * Populate the object_names list from the module filelist. -+ */ -+static void init_object_names(const char *object_names_file); -+ -+/* -+ * Populate and object_to_module from the objects.builtin and modules.builtin -+ * file. -+ */ -+static void init_builtin(const char *builtin_objects_file, -+ const char *builtin_module_file); -+ -+/* -+ * The member blacklist bans fields with specific names in specifically named -+ * structures, declared in specific source files, from being emitted. The -+ * mapping is from absolute source file name:structure.member to NULL (this is -+ * safe because type names cannot contain a colon, and structure names cannot -+ * contain a period). -+ */ -+static GHashTable *member_blacklist; -+ -+/* -+ * Populate the member blacklist from the member_blacklist file. -+ */ -+static void init_member_blacklist(const char *member_blacklist_file, -+ const char *srcdir); -+ -+/* -+ * Return 1 if a given DWARF DIE, which must be a DW_TAG_member, appears in the -+ * member blacklist. -+ */ -+static int member_blacklisted(Dwarf_Die *die, Dwarf_Die *parent_die); -+ -+/* -+ * The variable blacklist, like the others, is an automatically-maintained -+ * blacklist giving variables in specific modules which should not be emitted. -+ * (These are variables whose names are ambiguous within a module, and may -+ * appear multiple times in /proc/kallmodsyms, identical but for address and -+ * thus indistinguishable.) -+ * -+ * The mapping is from module`variable to NULL (safe because variable names -+ * cannot begin with a backtick, and even if they could DTrace's notation could -+ * not reference such variables). -+ */ -+static GHashTable *variable_blacklist; -+ -+/* -+ * A mapping from object file name to the name of the module that translation -+ * unit is part of. -+ * -+ * Actual, real, on-disk .ko modules do not appear here, because the translation -+ * is trivial for them. -+ */ -+static GHashTable *object_to_module; -+ -+/* -+ * Initialize a CTF type table, and possibly fill it with those special types -+ * that appear in CTF but not in DWARF (such as 'void'). (This filling happens -+ * only for the type table named "shared_ctf", unless deduplication is turned -+ * off.) -+ * -+ * If this is a local type table, and deduplication is active, make the global -+ * type table its parent. -+ */ -+static void init_ctf_table(const char *module_name); -+ -+/* -+ * A few useful singleton CTF type IDs in the global type table: a void pointer -+ * and a function pointer. Constructed by init_ctf_table(). -+ */ -+static ctf_id_t ctf_void_type; -+static ctf_id_t ctf_funcptr_type; -+ -+/* -+ * Initialize the child->parent DIE mapping for a single file. -+ */ -+static void init_parent_die(const char *file_name, Dwfl *dwfl); -+ -+/* -+ * Initialize one layer of a child->parent mapping. -+ */ -+static int init_parent_die_internal(const char *file_name, -+ GHashTable *offs, Dwarf_Die *parent, -+ int depth, int found_subprogram); -+ -+/* -+ * Override the presence and value of FORM_u/sdata attributes on DWARF DIEs, -+ * either adding to it, or replacing it. -+ * -+ * (Used so that a caller of construct_ctf_id() that wants a type to be created -+ * can override aspects of that type.) -+ * -+ * The 'chain', if set, causes the various private_*() functions that handle -+ * overrides to look back along the chain to find a suitable attribute. The -+ * chain must be set on the last element in the array. The search for -+ * attributes terminates at the first match. -+ * -+ * Note: this is not a particularly generic implementation: a better approach -+ * would be to keep walking the chain on DIE_OVERRIDE_ADD, and keep adding until -+ * we are done: but we have only one user of ADD, and it implements the addition -+ * itself because it is adding to a value from a different DIE: so this added -+ * generality is not needed yet. -+ */ -+struct die_override { -+ int tag; -+ int attribute; -+ enum { DIE_OVERRIDE_REPLACE, DIE_OVERRIDE_ADD } op; -+ Dwarf_Sword value; -+ struct die_override *chain; -+}; -+ -+/* -+ * Compute the type ID of a DWARF DIE (with possibly-overridden attributes) and -+ * return it in a new dynamically-allocated string. -+ * -+ * Optionally, call a callback with the computed ID once we know it (this is a -+ * recursive process, so the callback can be called multiple times as the ID -+ * is built up). -+ * -+ * An ID of NULL indicates that this DIE has no ID and need not be considered. -+ */ -+static char *type_id(Dwarf_Die *die, struct die_override *overrides, -+ void (*fun)(Dwarf_Die *die, -+ const char *id, -+ struct die_override *overrides, -+ void *data), -+ void *data) __attribute__((__warn_unused_result__)); -+ -+/* -+ * Internal: allows flags to be passed to affect one (and only one) type ID -+ * recursion, without affecting other type_id()s launched from the 'fun'. -+ */ -+static char *type_id_internal(Dwarf_Die *die, -+ struct die_override *overrides, -+ void (*fun)(Dwarf_Die *die, -+ const char *id, -+ struct die_override *overrides, -+ void *data), -+ void *data, -+ int flags); -+ -+/* -+ * Internal: generate the type ID for a type DIE. -+ * -+ * If there are no overrides, look for a bit_size and bit_offset and pass them -+ * down as well. -+ */ -+static char *type_id_type_die(Dwarf_Die *die, -+ Dwarf_Die *type_die, -+ struct die_override *overrides, -+ void (*fun)(Dwarf_Die *die, -+ const char *id, -+ struct die_override *overrides, -+ void *data), -+ void *data); -+ -+/* -+ * Convert 'long unsigned int' to 'sizetype'. Internal use within type_id(). -+ */ -+#define TI_COLLAPSE_SIZETYPE 0x1 -+ -+/* -+ * Process a file, calling the dwarf_process function for every type found -+ * therein (even types in functions). Optionally call tu_init() at the start of -+ * each translation unit, and tu_done() at the end. -+ */ -+static void process_file(const char *file_name, -+ void (*dwarf_process)(const char *module_name, -+ const char *file_name, -+ Dwarf_Die *die, -+ Dwarf_Die *parent_die, -+ void *data), -+ void (*tu_init)(const char *module_name, -+ const char *file_name, -+ Dwarf_Die *tu_die, -+ void *data), -+ void (*tu_done)(const char *module_name, -+ const char *file_name, -+ Dwarf_Die *tu_die, -+ void *data), -+ void *data); -+ -+/* -+ * process_file() helper, walking over the top level and picking up types -+ * therein. -+ */ -+static void process_tu_func(const char *module_name, -+ const char *file_name, -+ Dwarf *dwarf, -+ Dwarf_Die *parent_die, -+ Dwarf_Die *die, -+ void (*dwarf_process)(const char *module_name, -+ const char *file_name, -+ Dwarf_Die *die, -+ Dwarf_Die *parent_die, -+ void *data), -+ void *data); -+ -+/* -+ * Records the type ID of interesting types, the files they are contained in, -+ * and their DWARF offset, so they can be found rapidly. -+ * -+ * Used to avoid rescanning files that can contain no duplicates. -+ */ -+struct dedup_id_file { -+ char *file_name; -+ char *id; -+ Dwarf_Off dieoff; -+}; -+ -+/* -+ * The structure used as the data argument for dedup() and -+ * dedup_alias_fixup(). -+ * -+ * structs_seen tracks the IDs of structures marked as duplicates within a given -+ * translation unit, in order that recursion terminates if two such structures -+ * have pointers to each other. -+ * -+ * vars_seen tracks variables seen in this module, mapping from unadorned name -+ * to a non-NULL pointer (for static, non-'external') or NULL (for non-static or -+ * 'extern'). If a static variable coexists with any other variable with the -+ * same name, static or not, the variable is blacklisted. (Non-static -+ * coexistence is fine, because they are just different references to the same -+ * variable). Note that management of this variable is a little annoying -+ * because it varies by module, not by TU, so we can't use tu_init/tu_done to -+ * manage its lifetime. -+ * -+ * named_structs tracks type IDs and contained modules for every type that may -+ * contain undetected duplicates and thus may require rescanning. -+ * -+ * dwfl and dwfl_file_name identify the opened DWARF file (if any) during the -+ * second duplicates detection pass. -+ * -+ * repeat_detection is set by each phase if it considers that another round of -+ * alias fixup detection is needed. -+ */ -+struct dedup_state { -+ const char *file_name; -+ const char *module_name; -+ GHashTable *structs_seen; -+ GList *named_structs; -+ GHashTable *vars_seen; -+ char *dwfl_file_name; -+ Dwarf *dwarf; -+ Dwfl *dwfl; -+ int repeat_detection; -+}; -+ -+/* -+ * Scan and identify duplicates across the entire set of object files. -+ */ -+static void scan_dups(void); -+ -+/* -+ * Recursively detect duplicate types and types referenced by them, and -+ * determine which CTF file they should be located in, and request a -+ * dedup_alias_fixup() pass if any structures are shared. -+ * Determine the mapping from translation unit name to module name. -+ */ -+static void dedup(const char *module_name, const char *file_name, -+ Dwarf_Die *die, Dwarf_Die *parent_die, void *data); -+ -+/* -+ * Do the underlying marking of a DIE as shared, iff need be. (No variable -+ * blacklisting, non-opaque structure checks, or anything else needed only by -+ * top-level DIEs.) -+ * -+ * This function may be called multiple times for overridden DIEs that are -+ * dependent types of bitfields. -+ */ -+static void dedup_mark_inner_die(const char *module_name, Dwarf_Die *die, -+ const char *id, -+ struct die_override *overrides, -+ void *data); -+ -+/* -+ * Note in the dedup_id_file list that we will rescan a DIE in a later duplicate -+ * detection pass. -+ * -+ * A type_id() callback. -+ */ -+static void dedup_will_rescan(Dwarf_Die *die, const char *id, -+ struct die_override *overrides, void *data); -+ -+/* -+ * Note the variable referenced by this DIE in vars_seen: blacklist it if an -+ * entry for this variable already exists in vars_seen and this instance is -+ * static, or if a static entry already exists in vars_seen, whether this -+ * instance is static or not. -+ */ -+static void dedup_blacklist_var_dups(Dwarf_Die *die, -+ struct dedup_state *state); -+ -+/* -+ * Detect duplicates and mark seen types for a given type, via a type_id() -+ * callback: used to detect dependent types (particularly those at child-DIE -+ * level) as duplicates. -+ */ -+static void dedup_typeid(Dwarf_Die *die, const char *id, -+ struct die_override *overrides, void *data); -+ -+/* -+ * Mark any aggregates contained within a particular type DIE as seen. This is -+ * needed since even nameless aggregates contained within other aggregates can -+ * be used as the type of members of the outer aggregate (though they cannot -+ * possibly be found in a module different from that of their containing -+ * aggregate, any more than a structure member can). -+ */ -+static void mark_seen_contained(Dwarf_Die *die, const char *module_name, -+ struct die_override *overrides, void *data); -+ -+/* -+ * Determine if some type (whose ultimate base type is an non-opaque structure, -+ * alias, or enum) has an opaque equivalent which is shared, and mark it and -+ * all its bases as shared too if so. -+ * -+ * A list_filter() filter function. -+ */ -+static int dedup_alias_fixup(void *id_file_data, void *data); -+ -+/* -+ * Mark a basic type shared by name and intern it in all relevant hashes. (Used -+ * for marking basic types we don't have a DIE for.) -+ */ -+static void mark_shared_by_name(ctf_file_t *ctf, ctf_id_t ctf_id, -+ const char *name); -+ -+/* -+ * Determine if a type is a named struct, union, or enum. -+ * -+ * A type_id() callback. -+ */ -+static void is_named_struct_union_enum(Dwarf_Die *die, const char *unused, -+ struct die_override *overrides, -+ void *data); -+ -+/* -+ * Set up state for dedup(). A tu_init() callback. -+ */ -+static void dedup_tu_init(const char *module_name, const char *file_name, -+ Dwarf_Die *tu_die, void *data); -+ -+/* -+ * Free state for dedup(). A tu_done() callback. -+ */ -+static void dedup_tu_done(const char *module_name, const char *file_name, -+ Dwarf_Die *tu_die, void *data); -+ -+/* -+ * Free DWARF state for dedup(). -+ */ -+static void dedup_dwarf_free(struct dedup_state *state); -+ -+/* -+ * Determine if a type is duplicated and needs sharing. -+ */ -+enum needs_sharing { NS_NOT_SHARED, NS_NO_MARKING, NS_NEEDS_SHARING }; -+static enum needs_sharing type_needs_sharing(const char *module_name, -+ const char *id); -+ -+/* -+ * Mark a type (optionally, with an already-known ID) as duplicated and located -+ * in the shared CTF table. -+ * -+ * A type_id() callback (though also called directly). -+ */ -+static void mark_shared(Dwarf_Die *die, const char *id, -+ struct die_override *overrides, void *data); -+ -+/* -+ * Construct CTF out of each type. -+ */ -+static void construct_ctf(const char *module_name, const char *file_name, -+ Dwarf_Die *die, -+ Dwarf_Die *parent_die, -+ void *unused __unused__); -+ -+/* -+ * Write out the CTF files from the per_module->ctf_file into files in the -+ * output directory (if standalone), or into the output file (otherwise). -+ */ -+static void write_types(char *output, int standalone); -+ -+/* -+ * Construct CTF out of each type and return that type's ID and file. -+ */ -+static struct ctf_full_id *construct_ctf_id(const char *module_name, -+ const char *file_name, -+ Dwarf_Die *die, -+ Dwarf_Die *parent_die, -+ struct die_override *overrides); -+ -+/* -+ * Things to do after a CTF recursion step. -+ */ -+enum skip_type { SKIP_CONTINUE = 0, SKIP_SKIP, SKIP_ABORT }; -+ -+/* -+ * Recursive over a given DWARF DIE and its children andconstruct CTF out of it. -+ * -+ * Most parameters are shared with the ctf_assembly_fun: see the comment below. -+ */ -+static ctf_id_t die_to_ctf(const char *module_name, const char *file_name, -+ Dwarf_Die *die, Dwarf_Die *parent_die, -+ ctf_file_t *ctf, ctf_id_t parent_ctf_id, -+ struct die_override *overrides, int top_level_type, -+ int backwards, enum skip_type *skip, int *replace, -+ const char *id); -+ -+/* -+ * Return the next DIE, if that DIE needs to be emitted before this one. -+ */ -+static Dwarf_Die *die_emit_next_backwards(Dwarf_Die *next, Dwarf_Die *die, -+ struct die_override *overrides); -+ -+/* -+ * Look up a type through its reference: return its ctf_id_t, or -+ * recursively construct it if need be. -+ * -+ * Must be called on a DIE with a type attribute. -+ */ -+static ctf_id_t lookup_ctf_type(const char *module_name, const char *file_name, -+ Dwarf_Die *die, ctf_file_t *ctf, -+ struct die_override *overrides, -+ const char *locerrstr); -+ -+/* -+ * Assemble a given DIE and its children into CTF in some fashion, returning the -+ * ID of the top-level piece of generated CTF (only relevant for aggregates). -+ * -+ * The parent_ctf_id is the ID of the CTF entity that was or is being generated -+ * from the enclosing DWARF DIE, or 0 if population succeeded but did not yield -+ * a type ID (e.g. for variable assembly), or -1 on error. The parent_die is -+ * the parent of the current DWARF DIE, and is always populated (even if just -+ * with the CU's DIE). The parent_ctf_id is always in the same CTF file as the -+ * ctf_id, just as the parent DWARF DIE is always in the same DWARF CU: this is -+ * lexical scope, not dynamic, so referenced types themselves located at the top -+ * level have the CU as their parent. -+ * -+ * Returning an error value (see below) indicates that no CTF was generated from -+ * this DWARF DIE. -+ * -+ * Setting skip to SKIP_ABORT indicates that the translation of this entity -+ * failed, and the entire top-level type of which it is a part should be -+ * skipped. Setting it to SKIP_SKIP indicates that this entity does not need to -+ * be translated (perhaps because it already exists), so recursion into -+ * sub-entities can be skipped, but translation of the containing type should -+ * continue. Setting it to SKIP_CONTINUE indicates no error. -+ * -+ * Setting 'replace' to 1 in a child DIE indicates that this type should -+ * entirely *replace* its parent's type (generally because it has wrapped it up -+ * in something). This replacemenu takes immediate effect for later children of -+ * the same DIE. -+ * -+ * die_to_ctf() calls these functions repeatedly for every child of the -+ * requested DIE: the CTF ID eventually returned is whatever ID is returned by -+ * the last such function, and parent_ctf_id is repeatedly replaced with the ID -+ * returned by the last assembly function. Thus, assembly functions that -+ * augment an already-present ctf_id should return parent_ctf_id: assembly -+ * functions that wrap it in a new ctf_id referring to the parent_ctf_id should -+ * return the new ID. (Assembly functions should never entirely disregard the -+ * parent_ctf_id.) -+ */ -+typedef ctf_id_t (*ctf_assembly_fun)(const char *module_name, -+ const char *file_name, -+ Dwarf_Die *die, -+ Dwarf_Die *parent_die, -+ ctf_file_t *ctf, -+ ctf_id_t parent_ctf_id, -+ const char *locerrstr, -+ struct die_override *overrides, -+ int top_level_type, -+ enum skip_type *skip, -+ int *replace); -+ -+#define ASSEMBLY_FUN(name) \ -+ static ctf_id_t assemble_ctf_##name(const char *module_name, \ -+ const char *file_name, \ -+ Dwarf_Die *die, \ -+ Dwarf_Die *parent_die, \ -+ ctf_file_t *ctf, \ -+ ctf_id_t parent_ctf_id, \ -+ const char *locerrstr, \ -+ struct die_override *overrides, \ -+ int top_level_type, \ -+ enum skip_type *skip, \ -+ int *replace) -+ -+/* -+ * Defined assembly functions. -+ */ -+ASSEMBLY_FUN(base); -+ASSEMBLY_FUN(array); -+ASSEMBLY_FUN(array_dimension); -+ASSEMBLY_FUN(cvr_qual); -+ASSEMBLY_FUN(enumeration); -+ASSEMBLY_FUN(enumerator); -+ASSEMBLY_FUN(pointer); -+ASSEMBLY_FUN(struct_union); -+ASSEMBLY_FUN(su_member); -+ASSEMBLY_FUN(typedef); -+ASSEMBLY_FUN(variable); -+ -+/* -+ * An assembly filter is an optional function called with the DIE and parent DIE -+ * of a top-level type alone, before calling down into the process_file() -+ * processing function: it can be used to rapidly determine that this DIE is not -+ * worth processing. (It should return 0 in this case, and nonzero otherwise.) -+ */ -+typedef int (*ctf_assembly_filter_fun)(const char *file_name, -+ Dwarf *dwarf, -+ Dwarf_Die *die, -+ Dwarf_Die *parent_die); -+ -+/* -+ * A CTF assembly filter function which excludes all types not at the global -+ * scope (i.e. whose immediate parent is not a CU DIE) and which does not have a -+ * structure or union as its ultimate dependent type. (All structures and -+ * unions and everything dependent on them must be recorded, even inside -+ * functions, because GCC may emit references to the opaque variants of those -+ * types from file scope.) -+ */ -+static int filter_ctf_file_scope(const char *file_name, -+ Dwarf *dwarf, -+ Dwarf_Die *die, -+ Dwarf_Die *parent_die); -+ -+/* -+ * A CTF assembly filter function which excludes all names not at the global -+ * scope, all static symbols, and all names whose names are unlikely to be -+ * interesting. (DTrace userspace contains a similar list, but the two lists -+ * need not be in sync.) -+ */ -+static int filter_ctf_uninteresting(const char *file_name, -+ Dwarf *dwarf, -+ Dwarf_Die *die, -+ Dwarf_Die *parent_die); -+ -+/* -+ * Error return values from CTF assembly functions. These differ only in that -+ * die_to_ctf() reports the ctf_errmsg() if CTF_NO_ERROR_REPORTED is returned, -+ * but says nothing in the CTF_ERROR_REPORTED case. -+ */ -+#define CTF_NO_ERROR_REPORTED CTF_ERR -+#define CTF_ERROR_REPORTED (-2L) -+ -+/* -+ * The total number of type errors encountered. -+ */ -+static long num_errors; -+ -+/* -+ * A mapping from DW_TAG_* to functions which assemble this DW_TAG_* and -+ * possibly its children into the passed CTF. This table is not used -+ * directly, but rather assembled into a lookup table. -+ */ -+static struct assembly_tab_t -+{ -+ int tag; -+ ctf_assembly_filter_fun filter; -+ ctf_assembly_fun fun; -+} assembly_tab_init[] = -+{{ DW_TAG_base_type, filter_ctf_file_scope, assemble_ctf_base }, -+ { DW_TAG_array_type, filter_ctf_file_scope, assemble_ctf_array }, -+ { DW_TAG_subrange_type, NULL, assemble_ctf_array_dimension }, -+ { DW_TAG_const_type, filter_ctf_file_scope, assemble_ctf_cvr_qual }, -+ { DW_TAG_restrict_type, filter_ctf_file_scope, assemble_ctf_cvr_qual }, -+ { DW_TAG_enumeration_type, NULL, assemble_ctf_enumeration }, -+ { DW_TAG_enumerator, NULL, assemble_ctf_enumerator }, -+ { DW_TAG_pointer_type, filter_ctf_file_scope, assemble_ctf_pointer }, -+ { DW_TAG_structure_type, NULL, assemble_ctf_struct_union }, -+ { DW_TAG_union_type, NULL, assemble_ctf_struct_union }, -+ { DW_TAG_member, NULL, assemble_ctf_su_member }, -+ { DW_TAG_typedef, NULL, assemble_ctf_typedef }, -+ { DW_TAG_variable, filter_ctf_uninteresting, assemble_ctf_variable }, -+ { DW_TAG_volatile_type, filter_ctf_file_scope, assemble_ctf_cvr_qual }, -+ { 0, NULL }}; -+ -+/* -+ * The CTF assembly and filter lookup tables, in constructed form. -+ */ -+static ctf_assembly_fun *assembly_tab; -+static ctf_assembly_filter_fun *assembly_filter_tab; -+static size_t assembly_len; -+ -+/* -+ * Populate the assembly_tab and assembly_filter_tab from the assembly_tab_init. -+ */ -+static void init_assembly_tab(void); -+ -+/* -+ * A mapping from sizeof() to CTF type encoding. -+ */ -+struct type_encoding_tab { -+ size_t size; -+ int ctf_encoding; -+}; -+ -+/* -+ * Given a type encoding table, and a size, return the CTF encoding for that -+ * type, or 0 if none. -+ */ -+static int find_ctf_encoding(struct type_encoding_tab *type_tab, size_t size); -+ -+/* -+ * Count the number of members of a DWARF aggregate. -+ */ -+static long count_dwarf_members(Dwarf_Die *die); -+ -+/* -+ * Given a DIE that may contain a type attribute, look up the target of that -+ * attribute and return it, or NULL if none. -+ */ -+static Dwarf_Die *private_dwarf_type(Dwarf_Die *die, Dwarf_Die *target_die); -+ -+/* -+ * Check for existence of an attribute in a DIE, chasing through -+ * DW_AT_specification if need be. -+ */ -+static inline int private_dwarf_hasattr(Dwarf_Die *die, -+ unsigned int search_name); -+ -+/* -+ * Return a DIE attribute, chasing through DW_AT_specification if need be. -+ */ -+static inline Dwarf_Attribute *private_dwarf_attr(Dwarf_Die *die, -+ unsigned int search_name, -+ Dwarf_Attribute *result); -+ -+/* -+ * Given a DIE that contains a udata attribute, look up that attribute and -+ * return its value (optionally overridden or modified by the die_overrides). -+ */ -+static inline Dwarf_Word private_dwarf_udata(Dwarf_Die *die, int attribute, -+ struct die_override *overrides); -+ -+/* -+ * Given a DIE, return its byte size, if known and interpretable, or -1 -+ * otherwise. -+ */ -+static inline long long private_dwarf_size(Dwarf_Die *die); -+ -+/* -+ * Find an override in an override list. -+ */ -+static struct die_override * -+private_find_override(Dwarf_Die *die, -+ int attribute, -+ struct die_override *overrides); -+ -+/* -+ * Determine the dimensions of an array subrange, or 0 if variable. -+ */ -+static Dwarf_Word private_subrange_dimensions(Dwarf_Die *die); -+ -+/* -+ * A string appender working on dynamic strings. -+ */ -+static char *str_append(char *s, const char *append) -+ __attribute__((__warn_unused_result__)); -+ -+/* -+ * A vararg string appender. -+ */ -+static char *str_appendn(char *s, ...) -+ __attribute__((__warn_unused_result__, sentinel)); -+ -+/* -+ * An error-checking strdup(). -+ */ -+static char *xstrdup(const char *s) __attribute__((__nonnull__, -+ __warn_unused_result__, -+ __malloc__)); -+ -+/* -+ * Filter a GList, calling a predicate on it and removing all elements for which -+ * the predicate returns true, calling the free_func on them if set. -+ */ -+typedef int (*filter_pred_fun) (void *element, void *data); -+static GList *list_filter(GList *list, filter_pred_fun fun, -+ GDestroyNotify free_func, void *data); -+ -+/* -+ * Intern an atom in the atoms table and return it, or free it and return the -+ * existing atom if one is already interned. (Despite the type signature, this -+ * return value is constant and should not be freed.) -+ */ -+static void *intern(char *atom); -+ -+/* -+ * Figure out the (pathless, suffixless) module name for a given module file (.o -+ * or .ko), and return it in a new dynamically allocated string. -+ * -+ * Takes the object_to_module mapping into account. -+ */ -+static char *fn_to_module(const char *file_name); -+ -+/* -+ * Determine, and cache, absolute filenames. -+ */ -+static const char *abs_file_name(const char *file_name); -+ -+/* -+ * Determine absolute filenames relative to some other directory: do not cache -+ * them. It is the caller's responsibility to free them. -+ */ -+static char *rel_abs_file_name(const char *file_name, const char *relative_to); -+ -+/* -+ * Free a per_module's contents. -+ */ -+static void private_per_module_free(void *per_module); -+ -+/* -+ * Free a dedup_id_file's contents. -+ */ -+static void free_dups_id_file(void *id_file); -+ -+/* -+ * Free a fn_to_die_to_parent subhash. -+ */ -+static void private_fn_die_parent_free(void *ptr); -+ -+/* -+ * dwarf_dieoffset() with a return type better for printf(). -+ */ -+#define DIEOFFSET(die) (unsigned long) dwarf_dieoffset((die)) -+ -+/* -+ * A line-shortener with a kernel-familiar name for fprintfing to stderr. -+ */ -+#define pr_err(fmt, ...) fprintf(stderr, fmt, ## __VA_ARGS__); -+ -+/* Initialization. */ -+ -+int main(int argc, char *argv[]) -+{ -+ char *output; -+ -+ trace = getenv("DWARF2CTF_TRACE"); -+ -+ if ((argc != 4 && argc != 7) || -+ (argc == 4 && strcmp(argv[2], "-e") != 0)) { -+ pr_err("Syntax: dwarf2ctf output-file srcdir objects.builtin\n"); -+ pr_err(" modules.builtin member.blacklist filelist\n"); -+ pr_err(" or dwarf2ctf output-dir -e filelist\n" -+ "for external module use\n"); -+ exit(1); -+ } -+ -+ output = argv[1]; -+ -+ elf_version(EV_CURRENT); -+ -+ if (elf_errno()) { -+ pr_err("Version synchronization fault: %s\n", -+ elf_errmsg(elf_errno())); -+ exit(1); -+ } -+ -+ init_assembly_tab(); -+ object_to_module = g_hash_table_new_full(g_str_hash, g_str_equal, -+ free, free); -+ -+ /* -+ * When not building an external module, we run over all the arguments -+ * at once, deduplicating them. In external-module mode, we act as if -+ * independently invoked with every argument. -+ */ -+ if (strcmp(argv[2], "-e") != 0) { -+ const char *srcdir; -+ char *builtin_objects_file; -+ char *builtin_module_file; -+ char *member_blacklist_file; -+ -+ srcdir = argv[2]; -+ builtin_objects_file = argv[3]; -+ builtin_module_file = argv[4]; -+ member_blacklist_file = argv[5]; -+ deduplicating = 1; -+ -+ init_builtin(builtin_objects_file, builtin_module_file); -+ init_member_blacklist(member_blacklist_file, srcdir); -+ init_object_names(argv[6]); -+ -+ run(output, 0); -+ } else { -+ char *single_object_name; -+ char **all_object_names; -+ size_t all_object_names_cnt; -+ size_t i; -+ -+ deduplicating = 0; -+ init_object_names(argv[3]); -+ -+ /* -+ * Repeatedly populate object_names with one object name, and -+ * call run() with that. -+ */ -+ all_object_names = object_names; -+ all_object_names_cnt = object_names_cnt; -+ object_names = &single_object_name; -+ object_names_cnt = 1; -+ -+ for (i = 0; i < all_object_names_cnt; i++) { -+ single_object_name = all_object_names[i]; -+ -+ run(output, 1); -+ } -+ } -+ -+ g_hash_table_destroy(object_to_module); -+ -+ if (num_errors > 0) -+ pr_err("%li CTF construction errors.\n", num_errors); -+ -+ return 0; -+} -+ -+/* -+ * Run dwarf2ctf over a single object file or set thereof. -+ * -+ * output is the directory into which the CTF goes, if 'standalone', or the -+ * CTF archive file name otherwise. -+ */ -+static void run(char *output, int standalone) -+{ -+ size_t i; -+ -+ /* -+ * Create all the hashes, assemble the translation unit->module list for -+ * builtin modules, and create the shared CTF file if deduplicating. -+ */ -+ -+ atoms = g_hash_table_new_full(g_str_hash, g_str_equal, free, NULL); -+ id_to_type = g_hash_table_new_full(g_str_hash, g_str_equal, -+ NULL, free); -+ id_to_module = g_hash_table_new_full(g_str_hash, g_str_equal, -+ NULL, free); -+ per_module = g_hash_table_new_full(g_str_hash, g_str_equal, free, -+ private_per_module_free); -+ variable_blacklist = g_hash_table_new_full(g_str_hash, g_str_equal, -+ free, free); -+ fn_to_die_to_parent = g_hash_table_new_full(g_str_hash, -+ g_str_equal, free, -+ private_fn_die_parent_free); -+ -+ dw_ctf_trace("Initializing...\n"); -+ -+ if (deduplicating) -+ init_ctf_table("shared_ctf"); -+ -+ scan_dups(); -+ -+ /* -+ * Now construct CTF out of the types. -+ */ -+ dw_ctf_trace("CTF construction.\n"); -+ for (i = 0; i < object_names_cnt; i++) -+ process_file(object_names[i], construct_ctf, NULL, NULL, NULL); -+ -+ /* -+ * Finally, emit the types into their .ctf files, and generate the -+ * necessary linker scripts. -+ */ -+ dw_ctf_trace("Writeout.\n"); -+ write_types(output, standalone); -+ -+ g_hash_table_destroy(id_to_type); -+ g_hash_table_destroy(id_to_module); -+ g_hash_table_destroy(per_module); -+ g_hash_table_destroy(variable_blacklist); -+ g_hash_table_destroy(fn_to_die_to_parent); -+ g_hash_table_destroy(atoms); -+} -+ -+/* -+ * Populate the object_names list from the module filelist. -+ */ -+static void init_object_names(const char *object_names_file) -+{ -+ FILE *f; -+ char *line = NULL; -+ size_t line_size = 0; -+ -+ f = fopen(object_names_file, "r"); -+ if (f == NULL) { -+ pr_err("Cannot open object names file %s: %s\n", -+ object_names_file, strerror(errno)); -+ exit(1); -+ } -+ -+ /* -+ * This needs no massaging other than linefeed removal, just reading and -+ * stashing. -+ */ -+ -+ while (getline(&line, &line_size, f) >= 0) { -+ size_t len = strlen(line); -+ -+ if (len == 0) -+ continue; -+ -+ if (line[len-1] == '\n') -+ line[len-1] = '\0'; -+ -+ object_names = realloc(object_names, -+ ++object_names_cnt * -+ sizeof(char *)); -+ -+ if (object_names == NULL) { -+ pr_err("Out of memory reading %s\n", object_names_file); -+ exit(1); -+ } -+ -+ object_names[object_names_cnt-1] = xstrdup(line); -+ } -+ free(line); -+ -+ if (ferror(f)) { -+ pr_err("Error reading from %s: %s\n", object_names_file, -+ strerror(errno)); -+ exit(1); -+ } -+ -+ fclose(f); -+} -+ -+/* -+ * Populate object_to_module from the objects.builtin and modules.builtin file. -+ */ -+static void init_builtin(const char *builtin_objects_file, -+ const char *builtin_module_file) -+{ -+ FILE *f; -+ struct modules_thick_iter *i; -+ char *line = NULL; -+ size_t line_size = 0; -+ char *module_name = NULL; -+ char **paths; -+ -+ /* -+ * Iterate over all modules in modules_thick.builtin and add each to -+ * object_to_module. -+ */ -+ i = modules_thick_iter_new(builtin_module_file); -+ if (i == NULL) { -+ pr_err("Cannot iterate over builtin module file.\n"); -+ exit(1); -+ } -+ -+ while ((paths = modules_thick_iter_next(i, &module_name)) != NULL) { -+ size_t j; -+ -+ for (j = 0; paths[j] != NULL; j++) { -+ dw_ctf_trace("noting built-in module mapping %s -> %s\n", -+ module_name, paths[j]); -+ g_hash_table_replace(object_to_module, -+ strdup(paths[j]), -+ xstrdup(module_name)); -+ } -+ free(paths); -+ } -+ free(module_name); -+ modules_thick_iter_free(i); -+ -+ f = fopen(builtin_objects_file, "r"); -+ if (f == NULL) { -+ pr_err("Cannot open builtin objects file %s: %s\n", -+ builtin_objects_file, strerror(errno)); -+ exit(1); -+ } -+ -+ /* -+ * Those entries in builtin.objects that are not already known are -+ * unconditionally-built-in object files. -+ */ -+ while (getline(&line, &line_size, f) >= 0) { -+ size_t len = strlen(line); -+ -+ if (len == 0) -+ continue; -+ -+ if (line[len-1] == '\n') -+ line[len-1] = '\0'; -+ -+ if (!g_hash_table_lookup(object_to_module, line)) -+ g_hash_table_replace(object_to_module, xstrdup(line), -+ xstrdup("vmlinux")); -+ } -+ -+ if (ferror(f)) { -+ pr_err("Error reading from %s: %s\n", builtin_objects_file, -+ strerror(errno)); -+ exit(1); -+ } -+ -+ free(line); -+ fclose(f); -+} -+ -+/* -+ * Translate the assembly lookup table into the assembly_tab and -+ * assembly_filter_tab arrays. -+ */ -+static void init_assembly_tab(void) -+{ -+ struct assembly_tab_t *walk; -+ -+ for (walk = assembly_tab_init; walk->fun != NULL; walk++) { -+ if (assembly_len < walk->tag) -+ assembly_len = walk->tag; -+ } -+ assembly_len++; -+ -+ assembly_tab = calloc(sizeof(ctf_assembly_fun *), assembly_len); -+ assembly_filter_tab = calloc(sizeof(ctf_assembly_filter_fun *), -+ assembly_len); -+ if ((assembly_tab == NULL) || (assembly_filter_tab == NULL)) { -+ pr_err("Out of memory allocating assembly table\n"); -+ exit(1); -+ } -+ -+ for (walk = assembly_tab_init; walk->fun != NULL; walk++) { -+ assembly_tab[walk->tag] = walk->fun; -+ assembly_filter_tab[walk->tag] = walk->filter; -+ } -+} -+ -+/* -+ * Populate the member blacklist from the member_blacklist file. -+ */ -+static void init_member_blacklist(const char *member_blacklist_file, -+ const char *srcdir) -+{ -+ FILE *f; -+ char *line = NULL; -+ size_t line_num = 0; -+ size_t line_size = 0; -+ -+ /* -+ * Not having a member blacklist is not an error. -+ */ -+ f = fopen(member_blacklist_file, "r"); -+ if (f == NULL) -+ return; -+ -+ member_blacklist = g_hash_table_new(g_str_hash, g_str_equal); -+ -+ while (getline(&line, &line_size, f) >= 0) { -+ size_t len = strlen(line); -+ char *last_colon; -+ const char *last_dot; -+ char *absolutized; -+ -+ line_num++; -+ -+ if (len == 0) -+ continue; -+ -+ if (line[len-1] == '\n') -+ line[len-1] = '\0'; -+ -+ last_colon = strrchr(line, ':'); -+ last_dot = strrchr(last_colon + 1, '.'); -+ if (!last_colon || !last_dot) { -+ pr_err("Syntax error on line %li of %s.\n" -+ "Syntax: filename:structure.member.\n", -+ line_num, member_blacklist_file); -+ continue; -+ } -+ -+ *last_colon = '\0'; -+ last_colon++; -+ absolutized = rel_abs_file_name(line, srcdir); -+ absolutized = str_appendn(absolutized, ":", last_colon, NULL); -+ -+ g_hash_table_insert(member_blacklist, absolutized, NULL); -+ } -+ free(line); -+ -+ if (ferror(f)) { -+ pr_err("Error reading from %s: %s\n", member_blacklist_file, -+ strerror(errno)); -+ exit(1); -+ } -+ -+ fclose(f); -+} -+ -+/* -+ * Return 1 if a given DWARF DIE, which must be a DW_TAG_member, appears in the -+ * member blacklist. -+ */ -+static int member_blacklisted(Dwarf_Die *die, Dwarf_Die *parent_die) -+{ -+ const char *fname = dwarf_decl_file(die); -+ char *id; -+ int blacklisted = 0; -+ -+ /* -+ * If there is no member blacklist, do nothing. -+ */ -+ if (!member_blacklist) -+ return 0; -+ -+ /* -+ * Unnamed structure and union members cannot be blacklisted, for now. -+ */ -+ if ((dwarf_diename(parent_die) == NULL) || -+ (dwarf_diename(die) == NULL)) -+ return 0; -+ -+ /* -+ * The compiler can define its own structures, which appear in no -+ * decl_file. -+ * -+ * We can't blacklist them with this mechanism, so skip them. -+ */ -+ if (__builtin_expect(fname == NULL, 0)) -+ return 0; -+ -+ fname = abs_file_name(fname); -+ -+ if (dwarf_tag(die) != DW_TAG_member || -+ (dwarf_tag(parent_die) != DW_TAG_structure_type && -+ dwarf_tag(parent_die) != DW_TAG_union_type)) { -+ pr_err("Warning: member_blacklisted() called on " -+ "%s:%s.%s at offset %li, which is not a structure member.\n", -+ fname, dwarf_diename(parent_die), dwarf_diename(die), -+ DIEOFFSET(die)); -+ return 0; -+ } -+ -+ id = xstrdup(fname); -+ id = str_appendn(id, ":", dwarf_diename(parent_die), ".", -+ dwarf_diename(die), NULL); -+ -+ if (g_hash_table_lookup_extended(member_blacklist, id, NULL, NULL)) -+ blacklisted = 1; -+ -+ free(id); -+ return blacklisted; -+} -+ -+/* -+ * Initialize a CTF type table, and possibly fill it with those special types -+ * that appear in CTF but not in DWARF (such as 'void'). (This filling happens -+ * only for the type table named "shared_ctf", unless deduplication is turned -+ * off.) -+ * -+ * If this is a local type table, and deduplication is active, make the global -+ * type table its parent. -+ */ -+static void init_ctf_table(const char *module_name) -+{ -+ ctf_file_t *ctf_file; -+ struct per_module *new_per_mod; -+ int ctf_err; -+ -+ ctf_file = ctf_create(&ctf_err); -+ if (ctf_file == NULL) { -+ pr_err("Cannot create CTF file: %s\n", strerror(ctf_err)); -+ exit(1); -+ } -+ new_per_mod = malloc(sizeof(struct per_module)); -+ if (new_per_mod == NULL) { -+ pr_err("Out of memory allocating per-module CTF info\n"); -+ exit(1); -+ } -+ -+ new_per_mod->ctf_file = ctf_file; -+ new_per_mod->member_counts = g_hash_table_new_full(g_str_hash, -+ g_str_equal, -+ free, free); -+ g_hash_table_replace(per_module, xstrdup(module_name), new_per_mod); -+ -+ dw_ctf_trace("Initializing module: %s\n", module_name); -+ if ((strcmp(module_name, "shared_ctf") == 0) || -+ !deduplicating) { -+ ctf_encoding_t void_encoding = { CTF_INT_SIGNED, 0, 0 }; -+ ctf_encoding_t int_encoding = { CTF_INT_SIGNED, 0, -+ sizeof(int) * 8 }; -+ ctf_id_t int_type; -+ ctf_id_t func_type; -+ ctf_funcinfo_t func_info; -+ -+ /* -+ * Global types module, or deduplication is disabled. Add a -+ * type for 'void *' to point to, and a type for the return -+ * value of pointers to functions: then add the (single, -+ * universal) pointer-to-function value. -+ */ -+ ctf_void_type = ctf_add_integer(ctf_file, CTF_ADD_ROOT, -+ "void", &void_encoding); -+ int_type = ctf_add_integer(ctf_file, CTF_ADD_ROOT, "int", -+ &int_encoding); -+ mark_shared_by_name(ctf_file, ctf_void_type, "void"); -+ mark_shared_by_name(ctf_file, int_type, "int"); -+ -+ func_info.ctc_return = int_type; -+ func_info.ctc_argc = 0; -+ func_info.ctc_flags = 0; -+ func_type = ctf_add_function(ctf_file, CTF_ADD_ROOT, -+ &func_info, NULL); -+ ctf_funcptr_type = ctf_add_pointer(ctf_file, CTF_ADD_ROOT, -+ func_type); -+ -+ if (ctf_update(ctf_file) < 0) { -+ pr_err("Cannot initialize shared CTF file: %s\n", -+ ctf_errmsg(ctf_errno(ctf_file))); -+ exit(1); -+ } -+ } else { -+ /* -+ * Local types module with deduplication enabled: point the -+ * parent at the global CTF file, which must exist by this -+ * point. -+ */ -+ if (ctf_import(ctf_file, lookup_ctf_file("shared_ctf")) < 0) { -+ pr_err("Cannot set parent of CTF file for module %s: %s\n", -+ module_name, ctf_errmsg(ctf_errno(ctf_file))); -+ exit(1); -+ } -+ ctf_parent_name_set(ctf_file, "shared_ctf"); -+ } -+ -+ dw_ctf_trace("Created CTF file for module %s: %p\n", -+ module_name, ctf_file); -+} -+ -+/* DWARF walkers. */ -+ -+/* -+ * Initialize the child->parent DIE mapping for a single file. -+ */ -+static void init_parent_die(const char *file_name, Dwfl *dwfl) -+{ -+ GHashTable *offs; -+ Dwarf_Die *tu_die = NULL; -+ Dwarf_Addr junk; -+ -+ offs = g_hash_table_new(g_direct_hash, g_direct_equal); -+ if (offs == NULL) { -+ pr_err("Out of memory creating DIE offset hash\n"); -+ exit(1); -+ } -+ -+ while ((tu_die = dwfl_nextcu(dwfl, tu_die, &junk)) != NULL) { -+ init_parent_die_internal(file_name, offs, tu_die, 0, 0); -+ } -+ -+ g_hash_table_insert(fn_to_die_to_parent, -+ strdup(abs_file_name(file_name)), offs); -+} -+ -+/* -+ * Initialize one layer of a child->parent mapping. -+ * -+ * We traverse children of top-level subprograms hunting for anything we know -+ * how to emit, and record parent->child mappings for all intermediate DIEs. -+ */ -+static int init_parent_die_internal(const char *file_name, -+ GHashTable *offs, Dwarf_Die *parent, -+ int depth, int found_subprogram) -+{ -+ Dwarf_Die child; -+ int sib_ret; -+ Dwarf_Off parent_offset; -+ const char *err; -+ int add_parent = 0; -+ -+ if (dwarf_tag(parent) == DW_TAG_subprogram) -+ found_subprogram = 1; -+ -+ switch (dwarf_child(parent, &child)) { -+ case -1: -+ err = "child DIEs"; -+ goto err; -+ case 1: /* This DIE has no children */ -+ goto out; -+ } -+ -+ parent_offset = dwarf_dieoffset(parent); -+ -+ do { -+ int add_child = 0; -+ -+ /* -+ * Add links from the parent to all children for which a -+ * recursive call says they should be added, and note that we -+ * should add links to the parent too. Always look down to -+ * depth 2, since the topmost level is always -+ * DW_TAG_compile_unit, and we are interested in -+ * DW_TAG_subprograms one level below that. -+ */ -+ if (found_subprogram || depth < 2) -+ add_child = init_parent_die_internal(file_name, offs, -+ &child, depth+1, -+ found_subprogram); -+ -+ if (add_child) { -+ g_hash_table_insert(offs, -+ GUINT_TO_POINTER(dwarf_dieoffset(&child)), -+ GUINT_TO_POINTER(parent_offset)); -+ add_parent = 1; -+ } -+ } while ((sib_ret = dwarf_siblingof (&child, &child)) == 0); -+ -+ if (sib_ret == -1) { -+ err = "sibling DIEs"; -+ goto err; -+ } -+ -+out: -+ /* -+ * Emit a link for the next level up if we're under a subprogram and -+ * either we emitted a child link or the parent is itself something we -+ * know how to emit (and thus might possibly appear in a type DIE we -+ * care about). -+ */ -+ return (found_subprogram && -+ (add_parent || -+ (dwarf_tag(parent) < assembly_len && -+ assembly_tab[dwarf_tag(parent)] != NULL))); -+err: -+ pr_err("Cannot fetch %s of DIE at offset %lu in %s: %s\n", -+ err, DIEOFFSET(parent), file_name, -+ dwarf_errmsg(dwarf_errno())); -+ exit(1); -+} -+ -+/* -+ * Type ID computation. -+ * -+ * A type ID is a constant, recursively-constructed, dynamically-allocated -+ * string describing a given DWARF DIE in such a way that any DWARF file -+ * containing the same type will have the same type ID. (It even works for -+ * variables! Variables of the same name and referring to the same type have -+ * the same ID...) -+ * -+ * Optionally, call a callback with the computed ID once we know it (this is a -+ * recursive process, so the callback can be called multiple times as the ID is -+ * built up). -+ * -+ * An ID of NULL indicates that this DIE has no ID and need not be considered. -+ * -+ * It is probably an error for two DWARF DIEs representing top-level types to -+ * return the same ID, but for certain other DIEs (notably those representing -+ * the members of structures or unions), it is expected that they return the -+ * same ID as their type DIE. -+ * -+ * This function is the hottest hot spot in dwarf2ctf, so is somewhat -+ * aggressively optimized. -+ * -+ * The "overrides" allow the overriding of DWARF attributes, so that the -+ * machinery notices different DWARF from what actually appears in the -+ * debuginfo, so that the CTF that is emitted is suitably modified (and possibly -+ * duplicated). This is mostly used by type_id() to generate different IDs for -+ * dependent types of bitfields, but can be used for other purposes too, such as -+ * adjusting the offsets of types in unnamed structures, etc. Overrides are -+ * passed down if provided: overrides relating to bitfields are only applied by -+ * type_id() if no other overrides are provided. -+ * -+ * In general, you do not need to pass overrides down if you know you will only -+ * be called directly on top-level DIEs, but otherwise, you should do so. -+ */ -+static char *type_id(Dwarf_Die *die, -+ struct die_override *overrides, -+ void (*fun)(Dwarf_Die *die, -+ const char *id, -+ struct die_override *overrides, -+ void *data), -+ void *data) -+{ -+ return type_id_internal(die, overrides, fun, data, 0); -+} -+ -+/* -+ * Internal: generate the type ID for a type DIE. -+ * -+ * If there are no overrides, look for a bit_size and bit_offset and pass them -+ * down as well. -+ */ -+static char *type_id_type_die(Dwarf_Die *die, -+ Dwarf_Die *type_die, -+ struct die_override *overrides, -+ void (*fun)(Dwarf_Die *die, -+ const char *id, -+ struct die_override *overrides, -+ void *data), -+ void *data) -+{ -+ char *id; -+ -+ /* -+ * bit_size and bit_offset go together: we can assume that if a member -+ * has the one, it has the other. -+ */ -+ -+ if (private_dwarf_hasattr(die, DW_AT_bit_size)) { -+ Dwarf_Word size; -+ Dwarf_Word offset; -+ -+ size = private_dwarf_udata(die, DW_AT_bit_size, NULL); -+ offset = private_dwarf_udata(die, DW_AT_bit_offset, NULL); -+ struct die_override o[] = { -+ { DW_TAG_base_type, -+ DW_AT_bit_size, -+ DIE_OVERRIDE_REPLACE, -+ size, NULL }, -+ { DW_TAG_base_type, -+ DW_AT_bit_offset, -+ DIE_OVERRIDE_REPLACE, -+ offset, overrides }, -+ {0} -+ }; -+ id = type_id(type_die, o, fun, data); -+ } else -+ id = type_id(type_die, overrides, fun, data); -+ return id; -+} -+ -+/* -+ * Internal: allows flags to be passed to affect one (and only one) type ID -+ * recursion, without affecting other type_id()s launched from the 'fun'. -+ */ -+static char *type_id_internal(Dwarf_Die *die, -+ struct die_override *overrides, -+ void (*fun)(Dwarf_Die *die, -+ const char *id, -+ struct die_override *overrides, -+ void *data), -+ void *data, -+ int flags) -+{ -+ char *id = NULL; -+ int no_type_id = 0; -+ int decorated = 1; -+ -+ /* -+ * The ID of a null pointer is NULL. -+ */ -+ if (die == NULL) -+ return NULL; -+ -+ /* -+ * The ID of a function pointer is '//fp//', as a special case, -+ * with no location or overrides, ever. -+ */ -+ if (dwarf_tag(die) == DW_TAG_subroutine_type) { -+ id = xstrdup("//fp//"); -+ if (fun) -+ fun(die, id, NULL, data); -+ return id; -+ } -+ -+ /* -+ * If we have a type DIE, generate it first, passing any overrides down. -+ * (Base types and enumerations don't have a type DIE that CTF can -+ * encode the type of in any useful fashion.) -+ * -+ * Otherwise, note the location of this DIE, providing scoping -+ * information for all types based upon this one. Location elements are -+ * separated by //, an element impossible in a Linux path. The -+ * blacklist type prefix (if set) follows this (which is a name which, -+ * while not impossible in a Linux path, is very unlikely.) -+ * -+ * Array dimensions get none of this: they must be contained within -+ * another DIE, so will always have a location attached via that DIE, -+ * and get their type chased further down (so as to arrange that they -+ * appear inside an [].) -+ */ -+ if (dwarf_tag(die) != DW_TAG_subrange_type) { -+ if ((dwarf_tag(die) != DW_TAG_base_type) && -+ (dwarf_tag(die) != DW_TAG_enumeration_type)) { -+ Dwarf_Die type_die; -+ Dwarf_Die *diep = private_dwarf_type(die, &type_die); -+ -+ if (diep) -+ id = type_id_type_die(die, diep, overrides, -+ fun, data); -+ } -+ -+ /* -+ * Location information. We use cached realpath() results, and -+ * call str_appendn() only once, minimizing the number of -+ * strlen()s. -+ */ -+ if (id == NULL) { -+ const char *decl_file_name = dwarf_decl_file(die); -+ int decl_line_num; -+ const char *fname = ""; -+ char line_num[21] = ""; /* > than 2^64's digit count */ -+ -+ no_type_id = 1; -+ if (decl_file_name != NULL) -+ fname = abs_file_name(decl_file_name); -+ -+ if (dwarf_decl_line(die, &decl_line_num) >= 0) { -+ snprintf(line_num, sizeof(line_num), "%i", -+ decl_line_num); -+ } -+ id = str_appendn(id, fname, "//", line_num, "//", NULL); -+ } -+ } -+ -+ /* -+ * We implement this via a switch statement, rather than a jump table -+ * like the assembly_tab, simply because most cases are so small that -+ * splitting them into separate functions would do more harm than good -+ * to readability. -+ * -+ * WARNING: The spaces in the strings in this switch statement are not -+ * just for appearance: types with spaces in their names are impossible -+ * in C. If you move those spaces around for appearance's sake, please -+ * adjust mark_shared_by_name and dedup_alias_fixup(), which -+ * construct the IDs of basic types, structures, and unions by hand. -+ */ -+ switch (dwarf_tag(die)) { -+ case DW_TAG_base_type: { -+ Dwarf_Word bit_size = -1; -+ Dwarf_Word type_size = -1; -+ Dwarf_Word bit_offset = -1; -+ const char *diename = dwarf_diename(die); -+ -+ if ((flags & TI_COLLAPSE_SIZETYPE) && -+ (strcmp(diename, "long unsigned int") == 0)) -+ diename = "sizetype"; -+ -+ /* -+ * CTF encodes the size and bitwise-offset of bit-fields in the -+ * base type, so it must be stored once for each size, even if -+ * it only appears once for all sizes in the DWARF. -+ */ -+ if (private_dwarf_hasattr(die, DW_AT_bit_size) || -+ private_find_override(die, DW_AT_bit_size, -+ overrides)) -+ bit_size = private_dwarf_udata(die, DW_AT_bit_size, -+ overrides); -+ if (private_dwarf_hasattr(die, DW_AT_bit_offset) || -+ private_find_override(die, DW_AT_bit_offset, -+ overrides)) -+ bit_offset = private_dwarf_udata(die, DW_AT_bit_offset, -+ overrides); -+ -+ /* -+ * Bitfields that occupy their entire containing type are not -+ * bitfields, but just redundant DWARF. GCC emits these now and -+ * again, but the dups would trip CTF consistency checks, so -+ * must be skipped. -+ */ -+ if (bit_size > -1) { -+ /* -+ * This "may be omitted" in DWARF, but GCC doesn't: -+ * bitfields always get both. (See -+ * gcc/dwarf2out.c:gen_field_die().) -+ */ -+ type_size = private_dwarf_udata(die, DW_AT_bit_size, -+ overrides); -+ } -+ if (bit_size != type_size) { -+ char bitsize[22]; /* > 2^64's digit count */ -+ char bitoffset[22]; /* > 2^64's digit count */ -+ -+ snprintf(bitsize, sizeof(bitsize), "%li", bit_size); -+ id = str_appendn(id, diename, ":", bitsize, NULL); -+ if (bit_offset != -1) { -+ snprintf(bitoffset, sizeof(bitoffset), "%li", -+ bit_offset); -+ id = str_appendn(id, ":", bitoffset, NULL); -+ } -+ id = str_append(id, " "); -+ } else { -+ /* -+ * Ordinary (non-bit-field) base type. -+ */ -+ id = str_appendn(id, diename, " ", NULL); -+ } -+ break; -+ } -+ case DW_TAG_enumeration_type: -+ id = str_appendn(id, "enum ", dwarf_diename(die), " ", NULL); -+ break; -+ case DW_TAG_structure_type: -+ case DW_TAG_union_type: { -+ /* -+ * Incorporate the unaligned sizeof() the structure, if -+ * statically known (the offset of the last member in the DWARF) -+ * so that most structures which are redefined on the fly by -+ * preprocessor defines are disambiguated despite being defined -+ * in the same place. -+ * -+ * Only do this if this is a non-opaque structure/union -+ * definition: opaque definitions cannot have a size, but if -+ * they do by some mischance get one, notating it will mess up -+ * the several other places that manually construct opaque -+ * structure identifiers (and cannot incorporate a size, since -+ * they don't know it). -+ */ -+ const char *sou; -+ -+ if (strncmp(id, "////", 4) != 0) { -+ long long size; -+ char byte_size[24]; -+ -+ size = private_dwarf_size(die); -+ if (size > -1) { -+ sprintf(byte_size, "%lli", size); -+ id = str_appendn(id, byte_size, "//", NULL); -+ } -+ } -+ -+ if (dwarf_tag(die) == DW_TAG_union_type) -+ sou = "union "; -+ else -+ sou = "struct "; -+ -+ id = str_appendn(id, sou, dwarf_diename(die), " ", NULL); -+ break; -+ } -+ case DW_TAG_variable: -+ id = str_appendn(id, "var ", dwarf_diename(die), " ", NULL); -+ break; -+ case DW_TAG_typedef: -+ id = str_appendn(id, "typedef ", dwarf_diename(die), " ", NULL); -+ break; -+ case DW_TAG_const_type: -+ id = str_append(id, "const "); -+ break; -+ case DW_TAG_restrict_type: -+ id = str_append(id, "restrict "); -+ break; -+ case DW_TAG_volatile_type: -+ id = str_append(id, "volatile "); -+ break; -+ case DW_TAG_pointer_type: -+ if (no_type_id) -+ id = str_append(id, "void "); -+ id = str_append(id, "* "); -+ break; -+ -+ case DW_TAG_array_type: { -+ /* -+ * No explicit notation: all done per-dimension: so recurse to -+ * those. -+ */ -+ -+ int sib_ret; -+ int dimens = 0; -+ Dwarf_Die dim_die; -+ -+ switch (dwarf_child(die, &dim_die)) { -+ case -1: -+ pr_err("Corrupt DWARF: Cannot get array dimensions: %s\n", -+ dwarf_errmsg(dwarf_errno())); -+ exit(1); -+ case 1: /* No dimensions. */ -+ id = str_append(id, "[] "); -+ break; -+ default: -+ dimens = 1; -+ } -+ -+ if (!dimens) -+ break; -+ -+ do { -+ char *sub_id = type_id_internal(&dim_die, overrides, -+ fun, data, -+ TI_COLLAPSE_SIZETYPE); -+ id = str_append(id, sub_id); -+ free(sub_id); -+ } while ((sib_ret = dwarf_siblingof(&dim_die, &dim_die)) == 0); -+ -+ if (sib_ret == -1) { -+ pr_err("Corrupt DWARF: Cannot get array dimensions: %s\n", -+ dwarf_errmsg(dwarf_errno())); -+ exit(1); -+ } -+ break; -+ } -+ case DW_TAG_subrange_type: { -+ Dwarf_Word nelems = private_subrange_dimensions(die); -+ -+ id = str_append(id, "["); -+ -+ if (nelems > 0) { -+ Dwarf_Die type_die; -+ char elems[22]; /* bigger than 2^64's digit count */ -+ char *sub_id = type_id_internal(private_dwarf_type(die, &type_die), -+ overrides, fun, data, -+ TI_COLLAPSE_SIZETYPE); -+ -+ snprintf(elems, sizeof(elems), " %li", nelems); -+ id = str_appendn(id, sub_id, elems, NULL); -+ free(sub_id); -+ } -+ id = str_append(id, "] "); -+ break; -+ } -+ default: -+ /* -+ * Some tags (e.g. structure members) get the same ID as their -+ * associated type. We don't need to call the hook function -+ * again for such tags. -+ */ -+ decorated = 0; -+ } -+ -+ if (fun && decorated) -+ fun(die, id, overrides, data); -+ -+ return id; -+} -+ -+/* -+ * Process a file, calling the dwarf_process function for every top-level type -+ * found therein. Optionally call tu_init() at the start of each translation -+ * unit, and tu_done() at the end. -+ */ -+static void process_file(const char *file_name, -+ void (*dwarf_process)(const char *module_name, -+ const char *file_name, -+ Dwarf_Die *die, -+ Dwarf_Die *parent_die, -+ void *data), -+ void (*tu_init)(const char *module_name, -+ const char *file_name, -+ Dwarf_Die *tu_die, -+ void *data), -+ void (*tu_done)(const char *module_name, -+ const char *file_name, -+ Dwarf_Die *tu_die, -+ void *data), -+ void *data) -+{ -+ const char *err; -+ char *fn_module_name = fn_to_module(file_name); -+ const char *module_name = fn_module_name; -+ -+ Dwfl_Module *mod; -+ Dwfl *dwfl; -+ Dwarf *dwarf; -+ GHashTable *seen_before = g_hash_table_new_full(g_str_hash, g_str_equal, -+ free, free); -+ Dwarf_Die *tu_die = NULL; -+ Dwarf_Addr junk; -+ -+ if (seen_before == NULL) { -+ pr_err("Out of memory creating seen_before hash\n"); -+ exit(1); -+ } -+ -+ dwfl = simple_dwfl_new(file_name, &mod); -+ dwarf = dwfl_module_getdwarf(mod, &junk); -+ -+ /* -+ * On first traversal, make sure the DIE parent mapping is populated, -+ * so that filter_ctf_file_scope can use it. -+ */ -+ if (!g_hash_table_lookup_extended(fn_to_die_to_parent, -+ abs_file_name(file_name), -+ NULL, NULL)) -+ init_parent_die(file_name, dwfl); -+ -+ while ((tu_die = dwfl_nextcu(dwfl, tu_die, &junk)) != NULL) { -+ const char *tu_name; -+ -+ if (dwarf_tag(tu_die) != DW_TAG_compile_unit) { -+ err = "Malformed DWARF: non-compile_unit at top level"; -+ goto fail; -+ } -+ -+ tu_name = dwarf_diename(tu_die); -+ -+ dw_ctf_trace("Processing %s\n", tu_name); -+ -+ /* -+ * If we have seen this TU before, skip it. We assume that -+ * types in multiple identical TUs are always entirely -+ * identical. This lets us skip cases where the same object -+ * file is linked in multiple places without scanning every type -+ * in it. (Note: this may be inaccurate if a TU is built -+ * repeatedly with different #defines in force. I hope this -+ * cannot happen, but if it does, a workaround a-la libtool is -+ * simple: rename or symlink the TU for such repeated builds.) -+ * -+ * Otherwise, note the name of the module to which this TU maps, -+ * if it is not already known: otherwise, extract that name. -+ * -+ * This is purely an optimization: it breaks somewhat for -+ * multifile modules but this has no effect but a slight -+ * slowdown. -+ */ -+ if (g_hash_table_lookup_extended(seen_before, tu_name, -+ NULL, NULL)) -+ continue; -+ -+ g_hash_table_replace(seen_before, xstrdup(tu_name), NULL); -+ -+ /* -+ * We are only interested in top-level definitions within each -+ * TU. -+ */ -+ Dwarf_Die die; -+ -+ switch (dwarf_child(tu_die, &die)) { -+ case -1: -+ err = "fetch first child of TU"; -+ goto fail; -+ case 1: /* No DIEs at all in this TU */ -+ continue; -+ default: /* Child DIEs exist. */ -+ break; -+ } -+ -+ if (tu_init != NULL) -+ tu_init(module_name, file_name, tu_die, data); -+ -+ process_tu_func(module_name, file_name, dwarf, tu_die, &die, -+ dwarf_process, data); -+ -+ if (tu_done != NULL) -+ tu_done(module_name, file_name, tu_die, data); -+ } -+ -+ free(fn_module_name); -+ simple_dwfl_free(dwfl); -+ g_hash_table_destroy(seen_before); -+ -+ return; -+ -+ fail: -+ pr_err("Cannot %s for %s: %s\n", err, module_name, -+ dwarf_errmsg(dwarf_errno())); -+ exit(1); -+} -+ -+/* -+ * process_file() helper, walking over the top level and picking up types -+ * therein. -+ */ -+static void process_tu_func(const char *module_name, -+ const char *file_name, -+ Dwarf *dwarf, -+ Dwarf_Die *parent_die, -+ Dwarf_Die *die, -+ void (*dwarf_process)(const char *module_name, -+ const char *file_name, -+ Dwarf_Die *die, -+ Dwarf_Die *parent_die, -+ void *data), -+ void *data) -+{ -+ const char *err; -+ int sib_ret; -+ -+ /* -+ * We are only interested in definitions for which we can (eventually) -+ * emit CTF: call the processing function for all such. -+ */ -+ do { -+ if ((dwarf_tag(die) < assembly_len) && -+ (assembly_filter_tab[dwarf_tag(die)] == NULL || -+ assembly_filter_tab[dwarf_tag(die)](file_name, dwarf, die, -+ parent_die)) && -+ (assembly_tab[dwarf_tag(die)] != NULL)) -+ dwarf_process(module_name, file_name, die, -+ parent_die, data); -+ } while ((sib_ret = dwarf_siblingof(die, die)) == 0); -+ -+ if (sib_ret == -1) { -+ err = "fetch sibling"; -+ goto fail; -+ } -+ -+ return; -+ fail: -+ pr_err("Cannot %s for %s: %s\n", err, module_name, -+ dwarf_errmsg(dwarf_errno())); -+ exit(1); -+} -+ -+/* Duplicate detection. */ -+ -+/* -+ * Scan and identify duplicates across the entire set of object files. -+ */ -+static void scan_dups(void) -+{ -+ size_t i; -+ -+ /* -+ * First, determine which types are referenced by more than one -+ * translation unit, and construct the mapping from translation unit to -+ * non-builtin module name. -+ * -+ * The first pass detects duplicated types in need of sharing, without -+ * considering opaque/transparent structure/union aliasing. It requests -+ * an alias detection pass if any structures, or typedefs to them, are -+ * newly marked as shared. -+ * -+ * We must do this even when deduplication is disabled, because we need -+ * the TU->module-name mapping, even if in this case it is trivial. -+ */ -+ -+ struct dedup_state state = {0}; -+ -+ dw_ctf_trace("Duplicate detection: primary pass.\n"); -+ -+ /* -+ * This is merely flushed between TUs, not recreated: we create it here. -+ */ -+ state.vars_seen = g_hash_table_new_full(g_str_hash, -+ g_str_equal, -+ free, NULL); -+ -+ for (i = 0; i < object_names_cnt; i++) -+ process_file(object_names[i], dedup, -+ dedup_tu_init, dedup_tu_done, &state); -+ -+ if ((!state.repeat_detection) || !deduplicating) -+ goto out; -+ -+ do { -+ /* -+ * The second pass recognizes that opaque structures must be -+ * shared if the transparent equivalents are, and vice versa, -+ * and re-traces all transparent types that need sharing. -+ * -+ * It requests another alias detection pass if any non-opaque -+ * structures are newly marked as shared. -+ */ -+ dw_ctf_trace("Duplicate detection: alias fixup pass.\n"); -+ -+ state.repeat_detection = 0; -+ state.named_structs = list_filter(state.named_structs, -+ dedup_alias_fixup, -+ free_dups_id_file, &state); -+ } while (state.repeat_detection); -+ out: -+ g_hash_table_destroy(state.vars_seen); -+ dedup_dwarf_free(&state); -+ dw_ctf_trace("Duplicate detection: complete.\n"); -+ dw_ctf_trace("%llu distinct type IDs known.\n", -+ (unsigned long long) g_hash_table_size(id_to_module)); -+ dw_ctf_trace("%llu variables blacklisted for static/nonstatic conflicts.\n", -+ (unsigned long long) g_hash_table_size(variable_blacklist)); -+ g_list_free_full(state.named_structs, free_dups_id_file); -+} -+ -+/* -+ * Set up state for dedup(). A tu_init() callback. -+ */ -+static void dedup_tu_init(const char *module_name, const char *file_name, -+ Dwarf_Die *tu_die, void *data) -+{ -+ struct dedup_state *state = data; -+ struct per_module *per_mod; -+ -+ /* -+ * Make sure that even if this module has no types in it we still end up -+ * generating a CTF file. (Userspace depends on this, since a CTF file -+ * with no types in means the module is known and typeless, while no CTF -+ * file at all means the module is not known.) -+ */ -+ -+ per_mod = g_hash_table_lookup(per_module, module_name); -+ if (per_mod == NULL) { -+ init_ctf_table(module_name); -+ dw_ctf_trace("%s: initialized CTF file.\n", module_name); -+ } -+ -+ state->structs_seen = g_hash_table_new(g_str_hash, g_str_equal); -+ g_hash_table_remove_all(state->vars_seen); -+ state->module_name = module_name; -+} -+ -+/* -+ * Free state for dedup(). A tu_done() callback. -+ */ -+static void dedup_tu_done(const char *module_name, const char *file_name, -+ Dwarf_Die *tu_die, void *data) -+{ -+ struct dedup_state *state = data; -+ -+ /* -+ * We have to annul module_name because it is freed between object files -+ * by process_file(). Since we use that to track whether vars_seen -+ * needs reconstructing, that means we have to destroy that as well. -+ */ -+ g_hash_table_destroy(state->structs_seen); -+ state->structs_seen = NULL; -+ state->module_name = NULL; -+} -+ -+/* -+ * Free DWARF state for dedup(). -+ */ -+static void dedup_dwarf_free(struct dedup_state *state) -+{ -+ if (state->dwfl == NULL) -+ return; -+ simple_dwfl_free(state->dwfl); -+ state->dwfl = NULL; -+ state->dwarf = NULL; -+ free(state->dwfl_file_name); -+ state->dwfl_file_name = NULL; -+ if (state->structs_seen) -+ g_hash_table_destroy(state->structs_seen); -+ state->structs_seen = NULL; -+} -+ -+/* -+ * Duplicate detection. -+ * -+ * Scan for duplicate types. A duplicate type is defined as any type which -+ * appears in more than one module, or, more precisely, any type for which a -+ * type with the same ID already exists in another module. -+ * -+ * This pass also constructs the id_to_module table, so is essential even when -+ * deduplication is disabled (though then it need be run only once.) -+ */ -+ -+static void dedup(const char *module_name, const char *file_name, -+ Dwarf_Die *die, Dwarf_Die *parent_die, void *data) -+{ -+ struct dedup_state *state = data; -+ int is_sou = 0; -+ char *id = type_id(die, NULL, is_named_struct_union_enum, &is_sou); -+ -+ state->file_name = file_name; -+ /* -+ * If a DWARF-4 type signature is found, abort. While we can support -+ * DWARF-4 eventually, support in elfutils is insufficiently robust for -+ * now (elfutils 0.152). -+ */ -+ if (private_dwarf_hasattr(die, DW_AT_type)) { -+ Dwarf_Attribute type_attr; -+ -+ if ((private_dwarf_attr(die, DW_AT_type, &type_attr) != NULL) && -+ (dwarf_whatform(&type_attr) == DW_FORM_ref_sig8)) { -+ pr_err("Sorry, not yet implemented: %s contains DWARF-4 debugging information.\n", -+ module_name); -+ exit(1); -+ } -+ } -+ -+ /* -+ * Non-anonymous, non-opaque structure/union/enum types in -+ * non-dedup-blacklisted modules get their names and locations recorded -+ * for subsequent passes; all type_id()-descendant types are similarly -+ * noted. -+ */ -+ if (is_sou && strncmp(id, "////", strlen("////")) != 0) -+ free(type_id(die, NULL, dedup_will_rescan, state)); -+ -+ /* -+ * Handle static variable blacklisting. (We still shuffle blacklisted -+ * variables into the right place in id_to_module because we check for -+ * blacklisting at the lowest level, by which point we have already -+ * depended on id_to_module being correctly populated.) -+ * -+ * Avoid calling this for recursive dependent-type scans: variables -+ * cannot be dependent types. -+ */ -+ if (parent_die != NULL && dwarf_tag(die) == DW_TAG_variable) -+ dedup_blacklist_var_dups(die, state); -+ -+ dedup_mark_inner_die(module_name, die, id, NULL, data); -+ free(id); -+} -+ -+/* -+ * Do the underlying marking of a DIE as shared, iff need be. (No variable -+ * blacklisting, non-opaque structure checks, or anything else needed only by -+ * top-level DIEs.) -+ * -+ * This function may be called multiple times for overridden DIEs that are -+ * dependent types of bitfields. (On multiple calls for normal types, the -+ * second call will enter the NS_NO_MARKING case block and terminate recursion.) -+ */ -+static void dedup_mark_inner_die(const char *module_name, Dwarf_Die *die, -+ const char *id, -+ struct die_override *overrides, -+ void *data) -+{ -+ /* -+ * If we know of a single module incorporating this type, and it is not -+ * the same as the module we are currently in, then this type is -+ * duplicated across modules and belongs in the global type table. -+ * (This means that duplicated types are repeatedly so marked: this -+ * is unavoidable, because pass 3 requires re-marking structures that -+ * have already been marked, to pick up unmarked intermediate types.) -+ * -+ * We never consider types in modules on the deduplication blacklist -+ * to introduce duplicates. -+ */ -+ switch (type_needs_sharing(module_name, id)) { -+ case NS_NEEDS_SHARING: -+ mark_shared(die, NULL, overrides, data); -+ mark_seen_contained(die, "shared_ctf", overrides, data); -+ /* Fall through */ -+ case NS_NO_MARKING: -+ /* -+ * A duplicated type, but in the same module, or deduplication -+ * is disabled, so id_to_module is already correct. (When -+ * deduplication is disabled, we will be running with only one -+ * module at a time, and id_to_module will be a trivial -+ * mapping.) -+ */ -+ return; -+ case NS_NOT_SHARED: -+ break; -+ } -+ -+ /* -+ * Record that we have seen this type, and all its dependent types, in -+ * this module (or in the shared module if need be). -+ */ -+ -+ dw_ctf_trace("Marking %s as seen in %s\n", id, module_name); -+ g_hash_table_replace(id_to_module, intern(xstrdup(id)), -+ xstrdup(module_name)); -+ mark_seen_contained(die, module_name, overrides, data); -+ free(type_id(die, overrides, dedup_typeid, data)); -+} -+ -+/* -+ * Note in the dedup_id_file list that we will rescan a DIE in a later duplicate -+ * detection pass. -+ * -+ * A type_id() callback. -+ */ -+static void dedup_will_rescan(Dwarf_Die *die, const char *id, -+ struct die_override *overrides, void *data) -+{ -+ struct dedup_state *state = data; -+ struct dedup_id_file *id_file; -+ -+ /* -+ * We don't care about array index types, which will never be structures -+ * in C. -+ */ -+ if (id[0] == '[') -+ return; -+ -+ id_file = calloc(1, sizeof(struct dedup_id_file)); -+ if (id_file == NULL) { -+ pr_err("Out of memory allocating id_file\n"); -+ exit(1); -+ } -+ id_file->file_name = intern(xstrdup(state->file_name)); -+ id_file->id = intern(xstrdup(id)); -+ id_file->dieoff = dwarf_dieoffset(die); -+ state->named_structs = g_list_prepend(state->named_structs, id_file); -+} -+ -+/* -+ * Note the variable referenced by this DIE in vars_seen: blacklist it if an -+ * entry for this variable already exists in vars_seen and this instance is -+ * static, or if a static entry already exists in vars_seen, whether this -+ * instance is static or not. -+ */ -+static void dedup_blacklist_var_dups(Dwarf_Die *die, -+ struct dedup_state *state) -+{ -+ void *static_var; -+ int blacklist = 0; -+ -+ if (g_hash_table_lookup_extended(state->vars_seen, -+ dwarf_diename(die), -+ NULL, &static_var)) { -+ if (!private_dwarf_hasattr(die, DW_AT_external) && -+ !private_dwarf_hasattr(die, DW_AT_declaration)) -+ blacklist = 1; -+ if (static_var != NULL) -+ blacklist = 1; -+ } else -+ /* -+ * We need a non-NULL address here, but that is all we need. -+ * The address of a random variable will do. -+ */ -+ g_hash_table_insert(state->vars_seen, -+ xstrdup(dwarf_diename(die)), -+ (!private_dwarf_hasattr(die, DW_AT_external) && -+ !private_dwarf_hasattr(die, DW_AT_declaration)) ? -+ &static_var : NULL); -+ -+ if (blacklist) { -+ char *var = NULL; -+ var = str_appendn(var, state->module_name, "`", -+ dwarf_diename(die), NULL); -+ g_hash_table_replace(variable_blacklist, var, NULL); -+ } -+} -+ -+/* -+ * Free a dedup_id_file's contents. -+ */ -+static void free_dups_id_file(void *data) -+{ -+ struct dedup_id_file *id_file = data; -+ free(id_file); -+} -+ -+/* -+ * Determine if a type is duplicated and needs sharing. -+ */ -+static enum needs_sharing type_needs_sharing(const char *module_name, -+ const char *id) -+{ -+ const char *existing_type_module; -+ existing_type_module = g_hash_table_lookup(id_to_module, id); -+ -+ /* -+ * Types not already known about do not need sharing. -+ * -+ * Types already in the current modules and any types in external-module -+ * mode do not even need marking. -+ */ -+ if (existing_type_module == NULL) -+ return NS_NOT_SHARED; -+ -+ if ((strcmp(existing_type_module, module_name) == 0) || -+ (strcmp(existing_type_module, "shared_ctf") == 0) || -+ !deduplicating) -+ return NS_NO_MARKING; -+ -+ return NS_NEEDS_SHARING; -+} -+ -+/* -+ * Detect duplicates and mark seen types for a given type, via a type_id() -+ * callback: used to detect dependent types (particularly those at child-DIE -+ * level) as duplicates. -+ */ -+static void dedup_typeid(Dwarf_Die *die, const char *id, -+ struct die_override *overrides, void *data) -+{ -+ struct dedup_state *state = data; -+ -+ dedup_mark_inner_die(state->module_name, die, id, overrides, data); -+} -+ -+/* -+ * Mark any types contained within a particular type DIE as seen. This is -+ * needed since even nameless types contained within other aggregates can be -+ * used as the type of members in any of their enclosing aggregates (though they -+ * cannot possibly be found in a module different from that of their containing -+ * aggregate, any more than a structure member can). -+ */ -+static void mark_seen_contained(Dwarf_Die *die, const char *module_name, -+ struct die_override *overrides, -+ void *data) -+{ -+ const char *err; -+ Dwarf_Die child; -+ -+ if ((dwarf_tag(die) != DW_TAG_structure_type) && -+ (dwarf_tag(die) != DW_TAG_union_type)) -+ return; -+ -+ switch (dwarf_child(die, &child)) { -+ case -1: -+ err = "fetch first child of aggregate"; -+ goto fail; -+ case 1: /* No DIEs at all in this aggregate */ -+ return; -+ default: /* Child DIEs exist. */ -+ break; -+ } -+ -+ /* -+ * We iterate over all immediate children and recursively call ourselves -+ * for all those of type DW_TAG_structure_type and DW_TAG_union_type. -+ * -+ * Further, everything with an entry in assembly_tab other than -+ * non-bitfield members needs marking, since these may be declared at -+ * structure scope rather than being confined to global scope. -+ * Non-bitfield members are skipped because they cannot be used as the -+ * type of another field. These types cannot be duplicates if their -+ * containing type is not a duplicate, and typedefs cannot occur at this -+ * level so they cannot be aliased; thus we can mark them directly -+ * without going back into the top of dedup(). -+ * -+ * (Bit-field members are not skipped: they use different CTF from their -+ * non-bitfield equivalents, even though they refer to the same -+ * top-level DIE. The actual different CTF is handled by type_id() -+ * itself, but we do have to call it.) -+ */ -+ int sib_ret; -+ -+ do -+ switch (dwarf_tag(&child)) { -+ case DW_TAG_member: { -+ /* -+ * bit_size and bit_offset go together: we can assume -+ * that if a member has the one, it has the other, -+ * is a bitfield, and needs recursive marking. -+ */ -+ if (dwarf_tag(&child) == DW_TAG_member && -+ !private_dwarf_hasattr(&child, DW_AT_bit_size)) -+ break; -+ -+ free(type_id(&child, overrides, dedup_typeid, data)); -+ break; -+ } -+ case DW_TAG_structure_type: -+ case DW_TAG_union_type: -+ mark_seen_contained(&child, module_name, overrides, data); -+ /* fall through */ -+ default: -+ if (dwarf_tag(&child) < assembly_len && -+ assembly_tab[dwarf_tag(&child)] != NULL) { -+ -+ char *id = type_id(&child, overrides, NULL, NULL); -+ -+ dw_ctf_trace("Marking member %s as seen in " -+ "%s\n", id, module_name); -+ g_hash_table_replace(id_to_module, intern(id), -+ xstrdup(module_name)); -+ } -+ } -+ while ((sib_ret = dwarf_siblingof(&child, &child)) == 0); -+ -+ if (sib_ret == -1) { -+ err = "iterate over members"; -+ goto fail; -+ } -+ -+ return; -+ -+ fail: -+ pr_err("Cannot %s while marking aggregates as seen: %s\n", -+ err, dwfl_errmsg(dwfl_errno())); -+ exit(1); -+} -+ -+/* -+ * Mark a type as duplicated and located in the shared CTF table. Recursive, -+ * via the type_id() callback mechanism. -+ * -+ * A type_id() callback (though also called directly). -+ */ -+static void mark_shared(Dwarf_Die *die, const char *id, -+ struct die_override *overrides, void *data) -+{ -+ struct dedup_state *state = data; -+ const char *existing_module; -+ -+ /* -+ * Non-recursive call. Trigger type_id for its recursive callback, -+ * throwing the result away. -+ */ -+ if (id == NULL) { -+ free(type_id(die, overrides, mark_shared, state)); -+ return; -+ } -+ -+ existing_module = g_hash_table_lookup(id_to_module, id); -+ -+ if ((existing_module == NULL) || -+ (strcmp(existing_module, "shared_ctf") != 0)) { -+ -+ dw_ctf_trace("Marking %s as duplicate\n", id); -+ g_hash_table_replace(id_to_module, intern(xstrdup(id)), -+ xstrdup("shared_ctf")); -+ -+ /* -+ * Newly-marked structures/unions/enums must trigger a new -+ * duplicate detection pass (even if they are opaque). -+ */ -+ -+ if (((dwarf_tag(die) == DW_TAG_structure_type) || -+ (dwarf_tag(die) == DW_TAG_union_type) || -+ (dwarf_tag(die) == DW_TAG_enumeration_type)) && -+ (!state->repeat_detection)) { -+ dw_ctf_trace("Requesting another duplicate detection pass.\n"); -+ state->repeat_detection = 1; -+ } -+ } -+ -+ /* -+ * If this is a structure or union, mark its members as duplicates too. -+ * -+ * Do this even if we've seen this structure before, as this instance of -+ * the structure may have more members than the last we saw. However, -+ * if we have seen this structure before *in this translation unit*, -+ * skip it, to avoid infinite recursion in mutually referential -+ * structures. -+ */ -+ if ((dwarf_tag(die) == DW_TAG_structure_type) || -+ (dwarf_tag(die) == DW_TAG_union_type)) { -+ Dwarf_Die child; -+ -+ if (g_hash_table_lookup_extended(state->structs_seen, id, -+ NULL, NULL)) -+ return; -+ g_hash_table_replace(state->structs_seen, intern(xstrdup(id)), -+ NULL); -+ -+ switch (dwarf_child(die, &child)) { -+ case -1: -+ goto fail; -+ case 1: /* No DIEs at all in this aggregate */ -+ return; -+ } -+ -+ /* -+ * We are only interested in non-blacklisted children of type -+ * DW_TAG_member. -+ */ -+ int sib_ret; -+ -+ do -+ if ((dwarf_tag(&child) == DW_TAG_member) && -+ !member_blacklisted(&child, die)) -+ free(type_id(&child, overrides, -+ mark_shared, state)); -+ while ((sib_ret = dwarf_siblingof(&child, &child)) == 0); -+ -+ if (sib_ret == -1) -+ goto fail; -+ } -+ -+ return; -+ -+ fail: -+ pr_err("Cannot mark aggregate %s members as duplicated: %s\n", -+ dwarf_diename(die), dwarf_errmsg(dwarf_errno())); -+ exit(1); -+} -+ -+/* -+ * Determine if a type is a named struct, union, or enum. -+ * -+ * A type_id() callback. -+ */ -+static void is_named_struct_union_enum(Dwarf_Die *die, const char *unused, -+ struct die_override *overrides, -+ void *data) -+{ -+ int *is_sou = data; -+ -+ if (((dwarf_tag(die) == DW_TAG_structure_type) || -+ (dwarf_tag(die) == DW_TAG_union_type) || -+ (dwarf_tag(die) == DW_TAG_enumeration_type)) && -+ (private_dwarf_hasattr(die, DW_AT_name))) -+ *is_sou = 1; -+} -+ -+/* -+ * Duplicate detection alias fixup pass. Once the first pass is complete, we -+ * may have marked an opaque 'struct/union/enum foo' for sharing but not caught -+ * the non-opaque instance, because no users of the non-opaque instance appeared -+ * in the DWARF after the opaque copy was detected as a duplicate. This pass -+ * detects such cases, and marks their members as duplicates too. -+ * -+ * (The inverse case of a non-opaque structure/union/enum detected as a -+ * duplicate after the last usage of its opaque alias will be caught by this -+ * trap too.) -+ * -+ * Warning: this routine directly computes type_id()s without access to the -+ * corresponding type DIE, and as such is dependent on the format of type_id()s. -+ * (This is why it must run over non-opaque structures: given a non-opaque -+ * structure, its opaque alias is easy to compute, but the converse is not -+ * true.) -+ * -+ * As a list_filter() filter function, returns nonzero if this structure will -+ * not need to be checked again (because both its opaque and transparent -+ * variants are shared). -+ */ -+static int dedup_alias_fixup(void *id_file_data, void *data) -+{ -+ struct dedup_id_file *id_file = id_file_data; -+ struct dedup_state *state = data; -+ -+ int transparent_shared = 0; -+ int opaque_shared = 0; -+ int made_shared = 0; -+ -+ char *opaque_id; -+ const char *line_num; -+ const char *type_size; -+ const char *type_name; -+ -+ /* -+ * Compute the opaque variant corresponding to this transparent type, -+ * and check to see if either is marked shared, then find the DIE and -+ * mark both as shared if either is. (Unfortunately this means a double -+ * recursion in such cases, but this is unavoidable.) -+ */ -+ -+ line_num = strstr(id_file->id, "//"); -+ if (!line_num) { -+ pr_err("Internal error: type ID %s is corrupt.\n", -+ id_file->id); -+ exit(1); -+ } -+ -+ type_size = strstr(line_num + 2, "//"); -+ if (!type_size) { -+ pr_err("Internal error: type ID %s is corrupt.\n", -+ id_file->id); -+ exit(1); -+ } -+ -+ type_name = strstr(type_size + 2, "//"); -+ if (!type_name) { -+ /* -+ * That's OK: the type size is optional, so what we thought was -+ * the type size is actually the type name. -+ */ -+ type_name = type_size; -+ } -+ type_name += 2; -+ -+ opaque_id = xstrdup("////"); -+ opaque_id = str_append(opaque_id, type_name); -+ -+ const char *transparent_module = g_hash_table_lookup(id_to_module, -+ id_file->id); -+ const char *opaque_module = g_hash_table_lookup(id_to_module, -+ opaque_id); -+ -+ transparent_shared = ((transparent_module != NULL) && -+ (strcmp(transparent_module, "shared_ctf") == 0)); -+ -+ opaque_shared = ((opaque_module != NULL) && -+ (strcmp(opaque_module, "shared_ctf") == 0)); -+ -+ /* -+ * Transparent type needs sharing. -+ */ -+ if (opaque_shared && !transparent_shared) { -+ Dwarf_Die die; -+ Dwfl_Module *mod; -+ Dwarf_Addr dummy; -+ -+ /* -+ * Since we are not using process_file(), we must handle -+ * translation unit switches by hand, including resetting -+ * structs_seen. We also need to open the DWARF file, since -+ * type_id() needs access to the DIE of this type and all its -+ * dependent types as well. -+ */ -+ -+ if (state->dwfl != NULL && -+ strcmp(state->dwfl_file_name, id_file->file_name) != 0) -+ dedup_dwarf_free(state); -+ -+ if (state->dwfl_file_name == NULL) { -+ state->dwfl = simple_dwfl_new(id_file->file_name, &mod); -+ state->dwarf = dwfl_module_getdwarf(mod, &dummy); -+ state->dwfl_file_name = xstrdup(id_file->file_name); -+ if (state->structs_seen) -+ g_hash_table_destroy(state->structs_seen); -+ state->structs_seen = g_hash_table_new(g_str_hash, -+ g_str_equal); -+ } -+ if (!dwarf_offdie(state->dwarf, id_file->dieoff, -+ &die)) { -+ pr_err("Cannot look up offset %li in %s for type with ID %s\n", -+ id_file->dieoff, id_file->file_name, id_file->id); -+ exit(1); -+ } -+ mark_shared(&die, NULL, NULL, state); -+ made_shared = 1; -+ } -+ -+ /* -+ * We don't have the opaque type's DIE, so we can't use mark_shared(): -+ * this is also good since this triggers another duplicate detection -+ * pass, and we don't want to trigger another pass merely because of a -+ * nonshared opaque type (since they don't have members that may have -+ * structure or union type themselves and thus force more unshared -+ * types to become shared). -+ * -+ * Instead, do it by hand: this is simple, as member recursion is -+ * guaranteed not to be required for an opaque type. -+ */ -+ if (transparent_shared && !opaque_shared) { -+ dw_ctf_trace("Marking %s as duplicate\n", opaque_id); -+ g_hash_table_replace(id_to_module, intern(xstrdup(opaque_id)), -+ xstrdup("shared_ctf")); -+ made_shared = 1; -+ } -+ -+ free(opaque_id); -+ -+ return made_shared || (opaque_shared && transparent_shared); -+} -+ -+/* -+ * Mark a basic type shared by name and intern it in all relevant hashes. (Used -+ * for marking basic types we don't have a DIE for.) -+ */ -+static void mark_shared_by_name(ctf_file_t *ctf, ctf_id_t ctf_id, -+ const char *name) -+{ -+ struct ctf_full_id static_ctf_id = { ctf, ctf_id }; -+ struct ctf_full_id *full_ctf_id; -+ char *id = NULL; -+ -+ full_ctf_id = malloc(sizeof(struct ctf_full_id)); -+ if (full_ctf_id == NULL) { -+ pr_err("%s: out of memory\n", __func__); -+ exit(1); -+ } -+ *full_ctf_id = static_ctf_id; -+ -+ id = str_appendn(id, "////", name, " ", NULL); -+#ifdef DEBUG -+ strcpy(full_ctf_id->module_name, "shared_ctf"); -+ strcpy(full_ctf_id->file_name, "<built-in type>"); -+#endif -+ g_hash_table_replace(id_to_module, intern(xstrdup(id)), xstrdup("shared_ctf")); -+ g_hash_table_replace(id_to_type, intern(id), full_ctf_id); -+} -+ -+/* -+ * Type assembly. -+ * -+ * Given a DWARF DIE corresponding to a top-level type, call the appropriate -+ * construction function, passing it the appropriate ctf_file_t, constructing it -+ * if necessary, and stashing them in the appropriate hashes. Return the -+ * ctf_file_t and ctf_id_t of this type. -+ * -+ * Indirectly recursively called for types depending on other types, and for -+ * the types of variables (which for the sake of argument we call 'types' here -+ * too, since we treat them exactly like types, and dealing with types is our -+ * most important function). In such calls, the module_name may be 'shared_ctf' -+ * if this type is in the shared CTF repository. -+ * -+ * Select properties of the DIE can be overridden via the overrides array, if -+ * needed. -+ */ -+static struct ctf_full_id *construct_ctf_id(const char *module_name, -+ const char *file_name, -+ Dwarf_Die *die, -+ Dwarf_Die *parent_die, -+ struct die_override *overrides) -+{ -+ char *id = type_id(die, overrides, NULL, NULL); -+ char *ctf_module; -+ ctf_file_t *ctf; -+ ctf_snapshot_id_t snapshot; -+ -+ dw_ctf_trace(" %p: %s: looking up %s: %s\n", &id, -+ module_name ? module_name : "(no module)", -+ dwarf_diename(die), id); -+ /* -+ * Make sure this type does not already exist. (Recursive chasing for -+ * referenced types can lead to construct_ctf() being called on them -+ * more than once.) -+ */ -+ struct ctf_full_id *ctf_id; -+ -+ ctf_id = g_hash_table_lookup(id_to_type, id); -+ if (ctf_id != NULL) { -+ dw_ctf_trace(" %p: %p:%i found in module %s, file %s\n", &id, -+ ctf_id->ctf_file, (int) ctf_id->ctf_id, -+ ctf_id->module_name, ctf_id->file_name); -+ free(id); -+ return ctf_id; -+ } -+ -+ /* -+ * Create the CTF file for this type, if it does not exist. Verify that -+ * the duplicate-detection pass scanned this type, and that this is -+ * either the current module or the shared CTF module. -+ */ -+ -+ ctf_module = g_hash_table_lookup(id_to_module, id); -+ -+ if (ctf_module == NULL) { -+ pr_err("Internal error: within file %s, module %s, type at DIE offset %lx\n" -+ "with ID %s was not already noted by dedup().\n", -+ file_name, module_name, DIEOFFSET(die), id); -+ pr_err("dedup() is probably buggy.\n"); -+ exit(1); -+ } -+ -+ if ((strcmp(ctf_module, module_name) != 0) && -+ (strcmp(ctf_module, "shared_ctf") != 0)) { -+ pr_err("Internal error: within file %s, module %s, type at DIE offset %lx\n" -+ "with ID %s is in a different non-shared module, %s.\n", -+ file_name, module_name, DIEOFFSET(die), id, ctf_module); -+ pr_err("dedup() is probably buggy.\n"); -+ exit(1); -+ } -+ -+ ctf = lookup_ctf_file(ctf_module); -+ -+ /* -+ * Construct the CTF, then insert the top-level CTF entity into the -+ * id->type hash so that references from other types can find it, and -+ * update the CTF container. If conversion failed, roll back all -+ * changes made since the last successful call to this function. -+ * -+ * NOTE: references within DWARF to non-top-level types will currently -+ * fail, but I'm not sure if these can exist. (The type ID -+ * representation implicitly assumes that they cannot.) -+ */ -+ -+ snapshot = ctf_snapshot(ctf); -+ -+ enum skip_type skip = SKIP_CONTINUE; -+ -+ dw_ctf_trace("%p: into die_to_ctf() for %s\n", &id, id); -+ ctf_id_t this_ctf_id = die_to_ctf(ctf_module, file_name, die, -+ parent_die, ctf, -1, overrides, -+ 1, 0, &skip, NULL, id); -+ dw_ctf_trace("%p: out of die_to_ctf()\n", &id); -+ -+ ctf_id = malloc(sizeof(struct ctf_full_id)); -+ if (ctf_id == NULL) { -+ pr_err("Out of memory\n"); -+ exit(1); -+ } -+ -+ if (skip != SKIP_ABORT) { -+ ctf_id->ctf_file = ctf; -+ ctf_id->ctf_id = this_ctf_id; -+#ifdef DEBUG -+ strcpy(ctf_id->module_name, ctf_module); -+ strcpy(ctf_id->file_name, file_name); -+#endif -+ dw_ctf_trace(" %lx: %s: new type added, CTF ID %p:%li\n", -+ DIEOFFSET(die), id, ctf_id->ctf_file, -+ ctf_id->ctf_id); -+ -+ g_hash_table_replace(id_to_type, intern(id), ctf_id); -+ } else { -+ /* -+ * Failure. Remove the type from the id_to_type mapping, if it -+ * is there, and discard any added types from the CTF. -+ * -+ * If we have had to ctf_update() due to a new type getting -+ * used, the rollback will fail: discard instead. It might leave -+ * some spurious types hanging around but it will clean up as -+ * much as we can at this point. (This cannot happen when -+ * LIBDTRACE_CTF_OMISSIBLE_CTF_UPDATE, but it costs nothing to -+ * leave in: failure is a rare case.) -+ */ -+ -+ if (ctf_rollback(ctf, snapshot) < 0) -+ if (ctf_errno(ctf) == ECTF_OVERROLLBACK) -+ ctf_discard(ctf); -+ -+ free(ctf_id); -+ ctf_id = NULL; -+ -+ g_hash_table_remove(id_to_type, id); -+ free(id); -+ -+ dw_ctf_trace(" %p: (failure)\n", &id); -+ } -+ -+ return ctf_id; -+} -+ -+/* -+ * Given a DWARF DIE corresponding to a top-level type, or to an aggregate -+ * member, and the ctf_file_t where it is to be placed, call the appropriate -+ * construction function to place it and (for aggregates) its siblings there, -+ * recursing to handle contained aggregates. -+ * -+ * The parameters to this function are: -+ * -+ * module_name: The kernel module. -+ * file_name: The object file. -+ * die: The DWARF DIE. -+ * parent_die: Its parent, i.e. if a structure member, this is a structure: if -+ * top-level, this is a CU DIE. -+ * ctf: The CTF file this object should go into (possibly shared_ctf). -+ * parent_ctf_id: The CTF ID of the parent DIE, or -1 if none. -+ * struct die_override: Overrides for DWARF attributes (a NULL-terminated array, -+ * or NULL). -+ * top_level_type: 1 if this is a top-level type that can have a name and be -+ * referred to by other types. -+ * backwards: if 1, this is an internal call to process a series of bitfields -+ * with descending bit_offset and identical data_member_location. -+ * skip: The error-handling / skipping enum. -+ * replace: if 1, this type should replace its parent type entirely. -+ * id: the ID of this type. -+ * -+ * Note: id is only defined when top_level_type is 1. (We never use it -+ * in other situations, and computing it is quite expensive.) -+ */ -+static ctf_id_t die_to_ctf(const char *module_name, const char *file_name, -+ Dwarf_Die *die, Dwarf_Die *parent_die, -+ ctf_file_t *ctf, ctf_id_t parent_ctf_id, -+ struct die_override *overrides, int top_level_type, -+ int backwards, enum skip_type *skip, int *replace, -+ const char *id) -+{ -+ int sib_ret = 0; -+ ctf_id_t this_ctf_id; -+ int dummy; -+ -+ do { -+ const char *id_name; -+ const char *decl_file_name = dwarf_decl_file(die); -+ int decl_line_num; -+ int emitted_backwards = 0; -+ char locerrstr[1024]; -+ Dwarf_Die next_die; -+ -+ /* -+ * If the next DWARF DIE is at the same location as this one but -+ * with a lower bit_offset, we need to process the set of DIEs -+ * at this location in *reverse*, because DWARF has the DIEs in -+ * declaration order, while CTF wants them in in-memory order: -+ * so recurse to handle the next until we get to an element with -+ * a sibling at a different data_member_location (safe because -+ * there can't be that many of them per data_member_location), -+ * then (at the end of die_to_ctf()) exit the recursion and skip -+ * over the lot. -+ * -+ * We can ignore 'replace' and the return value of die_to_ctf -+ * because bitfields must be structure or union members and -+ * cannot be array dimensions. -+ */ -+ if (die_emit_next_backwards(&next_die, die, -+ overrides) != NULL) { -+ ctf_id_t dummy; -+ -+ dw_ctf_trace("Emitting %s:%s:%lx backwards\n", -+ module_name, file_name, -+ DIEOFFSET(&next_die)); -+ -+ dummy = die_to_ctf(module_name, file_name, &next_die, -+ parent_die, ctf, parent_ctf_id, -+ overrides, top_level_type, 1, skip, -+ replace, NULL); -+ if (*skip == SKIP_ABORT) -+ return dummy; -+ emitted_backwards = 1; -+ } -+ -+ /* -+ * Compute a name for our current location, for error messages. -+ * (The type representation could be used, but is likely to be -+ * hard for users to comprehend, and should we move to a hashed -+ * representation would be entirely useless for this purpose.) -+ */ -+ if ((decl_file_name == NULL) || -+ (dwarf_decl_line(die, &decl_line_num) < 0)) { -+ decl_file_name = "global"; -+ decl_line_num = 0; -+ } -+ -+ id_name = dwarf_diename(die); -+ if (id_name == NULL) -+ id_name = "(unnamed type)"; -+ -+ snprintf(locerrstr, sizeof(locerrstr), "%s:%i:%s", -+ decl_file_name, decl_line_num, id_name); -+ -+ dw_ctf_trace("Working over %s:%s:%s:%lx:%x with CTF file %p\n", -+ module_name, file_name, -+ dwarf_diename(die)==NULL?"NULL":dwarf_diename(die), -+ DIEOFFSET(die), dwarf_tag(die), ctf); -+ -+ /* -+ * Only process a given node, or its children, if we know how to -+ * do so. -+ */ -+ if ((dwarf_tag(die) >= assembly_len) || -+ (assembly_tab[dwarf_tag(die)] == NULL)) { -+ pr_err("%s:%i: warning: skipping identifier " -+ "%s with unknown DWARF tag %lx.\n", -+ decl_file_name, decl_line_num, id_name, -+ (unsigned long) dwarf_tag(die)); -+ return -1; -+ } -+ -+ *skip = SKIP_CONTINUE; -+ -+ this_ctf_id = assembly_tab[dwarf_tag(die)](module_name, -+ file_name, -+ die, parent_die, -+ ctf, parent_ctf_id, -+ locerrstr, -+ overrides, -+ top_level_type, -+ skip, -+ replace ? replace : -+ &dummy); -+ dw_ctf_trace("%s: out of assembly function for tag %lx with type ID %li\n", -+ locerrstr, (unsigned long) dwarf_tag(die), -+ this_ctf_id); -+ -+ if (this_ctf_id < 0) { -+ if ((this_ctf_id == CTF_NO_ERROR_REPORTED) && -+ (ctf_errno(ctf) != 0)) -+ pr_err("%s: CTF error in assembly of item with tag %i: %s\n", -+ locerrstr, dwarf_tag(die), -+ ctf_errmsg(ctf_errno(ctf))); -+ -+ num_errors++; -+#ifdef DEBUG -+ exit(1); -+#endif -+ *skip = SKIP_ABORT; -+ } -+ -+ /* -+ * Add newly-added non-skipped top-level structure or union CTF -+ * IDs to the type table at once. This allows circular type -+ * references via pointers in structure/union member DIEs to be -+ * looked up correctly. -+ */ -+ if (top_level_type && (*skip == SKIP_CONTINUE) && -+ ((dwarf_tag(die) == DW_TAG_structure_type) || -+ (dwarf_tag(die) == DW_TAG_union_type))) { -+ struct ctf_full_id full_ctf_id = { ctf, this_ctf_id }; -+ struct ctf_full_id *ctf_id; -+ -+#ifdef DEBUG -+ strcpy(full_ctf_id.module_name, module_name); -+ strcpy(full_ctf_id.file_name, file_name); -+#endif -+ -+ ctf_id = malloc(sizeof(struct ctf_full_id)); -+ if (ctf_id == NULL) { -+ fprintf(stderr, -+ "Out of memory allocating type ID\n"); -+ exit(1); -+ } -+ -+ dw_ctf_trace(" %s: immediate addition of %s, CTF ID " -+ "%p:%li in module %s, file %s\n", __func__, -+ id, full_ctf_id.ctf_file, full_ctf_id.ctf_id, -+ module_name, file_name); -+ *ctf_id = full_ctf_id; -+ -+ g_hash_table_replace(id_to_type, intern(xstrdup(id)), -+ ctf_id); -+ } -+ -+ /* -+ * Recurse to handle contained DIEs. -+ */ -+ -+ if ((dwarf_haschildren(die)) && (*skip == SKIP_CONTINUE)) { -+ Dwarf_Die child_die; -+ ctf_id_t new_id; -+ int replace = 0; -+ -+ if (dwarf_child(die, &child_die) < 0) { -+ pr_err("%s: Cannot recurse to DWARF DIE children: %s\n", -+ locerrstr, dwarf_errmsg(dwarf_errno())); -+ exit(1); -+ } -+ -+ new_id = die_to_ctf(module_name, file_name, &child_die, -+ die, ctf, this_ctf_id, overrides, 0, -+ 0, skip, &replace, NULL); -+ if (replace) -+ this_ctf_id = new_id; -+ } -+ -+ /* -+ * If we are walking backwards over a bunch of bitfields, this -+ * is a recursive walk, not an iterative one: return. -+ */ -+ if (backwards) -+ return this_ctf_id; -+ -+ /* -+ * We are not walking backwards, but this is the final stage of -+ * a bunch of backwards emissions: walk forwards until we hit -+ * the last one again. -+ */ -+ if (emitted_backwards) -+ while (die_emit_next_backwards(&next_die, die, -+ overrides) != NULL) -+ *die = next_die; -+ -+ /* -+ * Walk siblings of non-top-level types only: the sibling walk -+ * of top-level types is done by process_file(), so that -+ * construct_ctf_id() gets a chance to put each such type in the -+ * right CTF file. -+ */ -+ } while (*skip != SKIP_ABORT && !top_level_type && -+ (sib_ret = dwarf_siblingof(die, die)) == 0); -+ -+ if (sib_ret == -1) { -+ pr_err("In module %s, failure walking the sibling list: %s\n", -+ module_name, dwarf_errmsg(dwarf_errno())); -+ exit(1); -+ } -+ -+ dw_ctf_trace("New type ID: %p:%li\n", ctf, this_ctf_id); -+ return this_ctf_id; -+} -+ -+/* -+ * Calls construct_ctf_id() and throws the ID away. Used as a process_file() -+ * callback. -+ */ -+static void construct_ctf(const char *module_name, const char *file_name, -+ Dwarf_Die *die, Dwarf_Die *parent_die, -+ void *unused __unused__) -+{ -+ construct_ctf_id(module_name, file_name, die, parent_die, NULL); -+} -+ -+/* -+ * Return the next DIE, if that DIE needs to be emitted before this one. -+ */ -+static Dwarf_Die *die_emit_next_backwards(Dwarf_Die *next, Dwarf_Die *die, -+ struct die_override *overrides) -+{ -+ if (dwarf_tag(die) == DW_TAG_member && -+ dwarf_siblingof(die, next) == 0 && -+ dwarf_tag(next) == DW_TAG_member && -+ private_dwarf_hasattr(die, DW_AT_data_member_location) && -+ private_dwarf_hasattr(next, DW_AT_data_member_location) && -+ private_dwarf_udata(die, DW_AT_data_member_location, overrides) == -+ private_dwarf_udata(next, DW_AT_data_member_location, overrides) && -+ private_dwarf_hasattr(die, DW_AT_bit_offset) && -+ private_dwarf_hasattr(next, DW_AT_bit_offset) && -+ private_dwarf_udata(die, DW_AT_bit_offset, overrides) > -+ private_dwarf_udata(next, DW_AT_bit_offset, overrides)) -+ return next; -+ return NULL; -+} -+ -+/* -+ * Look up a type through its reference: return its ctf_id, or recursively -+ * construct it if need be. -+ */ -+static ctf_id_t lookup_ctf_type(const char *module_name, const char *file_name, -+ Dwarf_Die *die, ctf_file_t *ctf, -+ struct die_override *overrides, -+ const char *locerrstr) -+{ -+ Dwarf_Die tmp; -+ Dwarf_Die *type_die = private_dwarf_type(die, &tmp); -+ Dwarf_Die cu_die; -+ struct ctf_full_id *type_ref; -+ -+ /* -+ * Pointers to functions and void are special cases: there is only one -+ * of each of these in CTF, so we can use global singletons. -+ */ -+ -+ if (type_die == NULL) -+ return ctf_void_type; -+ -+ if (dwarf_tag(type_die) == DW_TAG_subroutine_type) -+ return ctf_funcptr_type; -+ -+ /* -+ * Look up or construct CTF for this type. -+ */ -+ -+ dwarf_diecu(type_die, &cu_die, NULL, NULL); -+ -+ dw_ctf_trace(" %s: Looking up dependent type at offset %lx for type %s at module %s, file %s\n", -+ locerrstr, DIEOFFSET(type_die), -+ dwarf_diename(die) ? dwarf_diename(die) : "NULL", -+ module_name, file_name); -+ -+ type_ref = construct_ctf_id(module_name, file_name, -+ type_die, &cu_die, overrides); -+ -+ /* -+ * Pass any error back up. -+ */ -+ if (type_ref == NULL) { -+ pr_err("%s: type lookup failed.\n", locerrstr); -+ return -1; -+ } -+ -+ if ((type_ref->ctf_file != ctf) && -+ type_ref->ctf_file != lookup_ctf_file("shared_ctf")) { -+#ifdef DEBUG -+ pr_err("%s: Internal error: lookup of %s found in different file: " -+ "%s/%s versus %s/%s.\n", locerrstr, -+ dwarf_diename(die) ? dwarf_diename(die) : "(unnamed)", -+ type_ref->module_name, type_ref->file_name, -+ module_name, file_name); -+#else -+ pr_err("%s: Internal error: lookup of %s found in different file.\n", -+ locerrstr, dwarf_diename(die) ? dwarf_diename(die) : -+ "(unnamed)"); -+#endif -+ pr_err("dedup() is probably buggy.\n"); -+ exit(1); -+ } -+ -+ return type_ref->ctf_id; -+} -+ -+/* Assembly functions. */ -+ -+#define CTF_DW_ENFORCE(attribute) do \ -+ if (!private_dwarf_hasattr(die, (DW_AT_##attribute))) { \ -+ pr_err("%s: %s: %lx: skipping type, %s attribute not present.\n", \ -+ locerrstr, __func__, DIEOFFSET(die), \ -+ #attribute); \ -+ *skip = SKIP_ABORT; \ -+ return CTF_ERROR_REPORTED; \ -+ } \ -+ while (0) -+ -+#define CTF_DW_ENFORCE_NOT(attribute) do \ -+ if (private_dwarf_hasattr(die, (DW_AT_##attribute))) { \ -+ pr_err("%s: %s: %lx: skipping type, %s attribute not supported.\n", \ -+ locerrstr, __func__, DIEOFFSET(die), \ -+ #attribute); \ -+ *skip = SKIP_ABORT; \ -+ return CTF_ERROR_REPORTED; \ -+ } \ -+ while (0) -+ -+#define ROOT_TYPE(x) (x) ? CTF_ADD_ROOT : CTF_ADD_NONROOT -+ -+/* -+ * A CTF assembly filter function which excludes all types not at the global -+ * scope (i.e. whose immediate parent is not a CU DIE), and all types which -+ * reference a type which is not at the global scope (thus ruling out local type -+ * definitions for which the compiler is not consistently emitting all -+ * intermediate types at the local scope). -+ */ -+static int filter_ctf_file_scope(const char *file_name, Dwarf *dwarf, -+ Dwarf_Die *die, Dwarf_Die *parent_die) -+{ -+ Dwarf_Die type_die; -+ GHashTable *parents; -+ -+ /* -+ * A type not dependent on another is acceptable iff it is at the global -+ * scope. -+ */ -+ if (private_dwarf_type(die, &type_die) == NULL) -+ return (dwarf_tag(parent_die) == DW_TAG_compile_unit); -+ -+ /* -+ * No type we reference may have a subprogram DIE as any of its parents. -+ */ -+ parents = g_hash_table_lookup(fn_to_die_to_parent, -+ abs_file_name(file_name)); -+ -+ do { -+ Dwarf_Die parent = type_die; -+ Dwarf_Off parent_off = 0; -+ -+ do { -+ if (parent_off != 0 && -+ !dwarf_offdie(dwarf, parent_off, &parent)) -+ break; -+ if (dwarf_tag(&parent) == DW_TAG_subprogram) -+ return 0; -+ } while ((parent_off = GPOINTER_TO_UINT(g_hash_table_lookup(parents, -+ GUINT_TO_POINTER(dwarf_dieoffset(&parent))))) -+ != 0); -+ } while (private_dwarf_type(&type_die, &type_die) != NULL); -+ -+ return 1; -+} -+ -+/* -+ * A CTF assembly filter function which excludes all names not at the global -+ * scope, and all names whose names are unlikely to be interesting. (DTrace -+ * userspace contains a similar list, but the two lists need not be in sync.) -+ */ -+static int filter_ctf_uninteresting(const char *file_name __unused__, -+ Dwarf *dwarf __unused__, -+ Dwarf_Die *die, Dwarf_Die *parent_die) -+{ -+ const char *sym_name = dwarf_diename(die); -+ -+ /* -+ * 'Variables' with no name are not interesting. -+ */ -+ if (sym_name == NULL) -+ return 0; -+ -+#define strstarts(var, x) (strncmp(var, x, strlen(x)) == 0) -+ return ((dwarf_tag(parent_die) == DW_TAG_compile_unit) && -+ !((strcmp(sym_name, "__per_cpu_start") == 0) || -+ (strcmp(sym_name, "__per_cpu_end") == 0) || -+ (strcmp(sym_name, "_sdt_probes") == 0) || -+ (strstarts(sym_name, "__crc_")) || -+ (strstarts(sym_name, "__ksymtab_")) || -+ (strstarts(sym_name, "__kcrctab_")) || -+ (strstarts(sym_name, "__kstrtab_")) || -+ (strstarts(sym_name, "__param_")) || -+ (strstarts(sym_name, "__syscall_meta__")) || -+ (strstarts(sym_name, "__p_syscall_meta__")) || -+ (strstarts(sym_name, "__event_")) || -+ (strstarts(sym_name, "event_")) || -+ (strstarts(sym_name, "ftrace_event_")) || -+ (strstarts(sym_name, "types__")) || -+ (strstarts(sym_name, "args__")) || -+ (strstarts(sym_name, "__tracepoint_")) || -+ (strstarts(sym_name, "__tpstrtab_")) || -+ (strstarts(sym_name, "__tpstrtab__")) || -+ (strstarts(sym_name, "__initcall_")) || -+ (strstarts(sym_name, "__setup_")) || -+ (strstarts(sym_name, "__pci_fixup_")) || -+ (strstr(sym_name, ".") != NULL))); -+#undef strstarts -+} -+ -+/* -+ * Assemble base types. -+ */ -+static ctf_id_t assemble_ctf_base(const char *module_name, -+ const char *file_name, Dwarf_Die *die, -+ Dwarf_Die *parent_die, ctf_file_t *ctf, -+ ctf_id_t parent_ctf_id, const char *locerrstr, -+ struct die_override *overrides, -+ int top_level_type, enum skip_type *skip, -+ int *replace) -+{ -+ typedef ctf_id_t (*ctf_add_fun)(ctf_file_t *, uint_t, -+ const char *, const ctf_encoding_t *); -+ -+ const char *name = dwarf_diename(die); -+ Dwarf_Word encoding, size; -+ ctf_add_fun ctf_add_func; -+ ctf_encoding_t ctf_encoding; -+ size_t encoding_search; -+ struct die_override *bit_size_override, *bit_offset_override; -+ -+ struct dwarf_encoding_tab { -+ Dwarf_Word encoding; -+ ctf_add_fun func; -+ uint_t encoding_fixed; -+ struct type_encoding_tab *size_lookup; -+ }; -+ -+ struct type_encoding_tab float_encoding[] = { -+ {sizeof(float), CTF_FP_SINGLE }, -+ {sizeof(double), CTF_FP_DOUBLE }, -+ {sizeof(long double), CTF_FP_LDOUBLE }, -+ {0, 0} -+ }; -+ -+ struct type_encoding_tab float_cplx_encoding[] = { -+ {sizeof(float), CTF_FP_CPLX }, -+ {sizeof(double), CTF_FP_DCPLX }, -+ {sizeof(long double), CTF_FP_LDCPLX }, -+ {0, 0} -+ }; -+ -+ struct type_encoding_tab float_imagry_encoding[] = { -+ {sizeof(float), CTF_FP_IMAGRY }, -+ {sizeof(double), CTF_FP_DIMAGRY }, -+ {sizeof(long double), CTF_FP_LDIMAGRY }, -+ {0, 0} -+ }; -+ -+ struct dwarf_encoding_tab all_encodings[] = { -+ {DW_ATE_boolean, ctf_add_integer, CTF_INT_BOOL, NULL}, -+ {DW_ATE_signed, ctf_add_integer, CTF_INT_SIGNED, NULL}, -+ {DW_ATE_signed_char, ctf_add_integer, -+ CTF_INT_SIGNED | CTF_INT_CHAR, NULL}, -+ {DW_ATE_unsigned, ctf_add_integer, 0, NULL}, -+ {DW_ATE_unsigned_char, ctf_add_integer, CTF_INT_CHAR, NULL}, -+ {DW_ATE_float, ctf_add_float, 0, float_encoding}, -+ {DW_ATE_complex_float, ctf_add_float, 0, float_cplx_encoding}, -+ {DW_ATE_imaginary_float, ctf_add_float, 0, -+ float_imagry_encoding}, -+ {0, 0, 0, 0} -+ }; -+ -+ CTF_DW_ENFORCE(name); -+ CTF_DW_ENFORCE(encoding); -+ CTF_DW_ENFORCE(byte_size); -+ CTF_DW_ENFORCE_NOT(endianity); -+ -+ encoding = private_dwarf_udata(die, DW_AT_encoding, overrides); -+ size = private_dwarf_udata(die, DW_AT_byte_size, overrides); -+ -+ for (encoding_search = 0; all_encodings[encoding_search].func != 0; -+ encoding_search++) { -+ if (all_encodings[encoding_search].encoding == encoding) { -+ ctf_add_func = all_encodings[encoding_search].func; -+ if (all_encodings[encoding_search].size_lookup != NULL) -+ ctf_encoding.cte_format = -+ find_ctf_encoding(all_encodings[encoding_search].size_lookup, -+ size); -+ else -+ ctf_encoding.cte_format = -+ all_encodings[encoding_search].encoding_fixed; -+ break; -+ } -+ } -+ -+ if (all_encodings[encoding_search].func == 0) { -+ pr_err("%s: skipping type, base type %li not yet implemented.\n", -+ locerrstr, (long) encoding); -+ *skip = SKIP_ABORT; -+ return CTF_ERROR_REPORTED; -+ } -+ -+ /* -+ * Handle bitfields. Only look at overrides, since bitfields can only -+ * be members of structures in C, thus derived from the referencing DIE. -+ * Bitfields are never top-level types in C, even though they are in -+ * DWARF. -+ */ -+ bit_size_override = private_find_override(die, DW_AT_bit_size, -+ overrides); -+ bit_offset_override = private_find_override(die, DW_AT_bit_offset, -+ overrides); -+ if (bit_size_override) { -+ ctf_encoding.cte_bits = bit_size_override->value; -+ top_level_type = 0; -+ } else -+ ctf_encoding.cte_bits = size * 8; -+ -+ if (bit_offset_override) { -+#if __BYTE_ORDER == __BIG_ENDIAN -+ ctf_encoding.cte_offset = bit_offset_override->value; -+#else -+ /* -+ * The figure here counts from the left to the leftmost edge of -+ * the bitfield: we want to count from the right to the -+ * rightmost edge. -+ */ -+ ctf_encoding.cte_offset = (size * 8) - -+ bit_offset_override->value - ctf_encoding.cte_bits; -+ dw_ctf_trace("Endianizing cte_offset from %x to %x\n", -+ (unsigned int) bit_offset_override->value, -+ ctf_encoding.cte_offset); -+#endif -+ } else -+ ctf_encoding.cte_offset = 0; -+ -+#ifdef DEBUG -+ if (bit_size_override || bit_offset_override) -+ dw_ctf_trace("Bitfield overrides: bit size %i; bit offset %i\n", -+ ctf_encoding.cte_bits, ctf_encoding.cte_offset); -+#endif -+ -+ return ctf_add_func(ctf, ROOT_TYPE(top_level_type), name, -+ &ctf_encoding); -+} -+ -+/* -+ * Assemble pointer types. -+ */ -+static ctf_id_t assemble_ctf_pointer(const char *module_name, -+ const char *file_name, -+ Dwarf_Die *die, Dwarf_Die *parent_die, -+ ctf_file_t *ctf, ctf_id_t parent_ctf_id, -+ const char *locerrstr, -+ struct die_override *overrides, -+ int top_level_type, -+ enum skip_type *skip, int *replace) -+{ -+ ctf_id_t type_ref; -+ -+ type_ref = lookup_ctf_type(module_name, file_name, die, ctf, -+ overrides, locerrstr); -+ if (type_ref < 0) { -+ *skip = SKIP_ABORT; -+ return CTF_ERROR_REPORTED; -+ } -+ -+ /* -+ * Pointers to functions are all the same type in CTF: don't bother -+ * adding it over again. -+ */ -+ if (type_ref == ctf_funcptr_type) -+ return type_ref; -+ -+ return ctf_add_pointer(ctf, ROOT_TYPE(top_level_type), type_ref); -+} -+ -+/* -+ * Assemble array types. This function looks up the array type, but does not do -+ * any array construction: that is left to assemble_ctf_array_dimension(). -+ */ -+static ctf_id_t assemble_ctf_array(const char *module_name, -+ const char *file_name, Dwarf_Die *die, -+ Dwarf_Die *parent_die, ctf_file_t *ctf, -+ ctf_id_t parent_ctf_id, -+ const char *locerrstr, -+ struct die_override *overrides, -+ int top_level_type, -+ enum skip_type *skip, int *replace) -+{ -+ ctf_id_t type_ref; -+ -+ CTF_DW_ENFORCE_NOT(ordering); -+ CTF_DW_ENFORCE_NOT(bit_stride); -+ CTF_DW_ENFORCE_NOT(byte_stride); -+ -+ type_ref = lookup_ctf_type(module_name, file_name, die, ctf, -+ overrides, locerrstr); -+ if (type_ref < 0) { -+ *skip = SKIP_ABORT; -+ return CTF_ERROR_REPORTED; -+ } -+ return type_ref; -+} -+ -+/* -+ * Assemble an array dimension, wrapping an array round the parent_ctf_id and -+ * replacing it. -+ */ -+static ctf_id_t assemble_ctf_array_dimension(const char *module_name, -+ const char *file_name, -+ Dwarf_Die *die, -+ Dwarf_Die *parent_die, -+ ctf_file_t *ctf, -+ ctf_id_t parent_ctf_id, -+ const char *locerrstr, -+ struct die_override *overrides, -+ int top_level_type, -+ enum skip_type *skip, -+ int *replace) -+{ -+ ctf_arinfo_t arinfo; -+ -+ CTF_DW_ENFORCE_NOT(bit_size); -+ CTF_DW_ENFORCE_NOT(byte_size); -+ CTF_DW_ENFORCE_NOT(bit_stride); -+ CTF_DW_ENFORCE_NOT(byte_stride); -+ CTF_DW_ENFORCE_NOT(lower_bound); -+ CTF_DW_ENFORCE_NOT(threads_scaled); -+ -+ arinfo.ctr_contents = parent_ctf_id; -+ -+ arinfo.ctr_index = lookup_ctf_type(module_name, file_name, -+ die, ctf, overrides, locerrstr); -+ if (arinfo.ctr_index < 0) { -+ *skip = SKIP_ABORT; -+ return CTF_ERROR_REPORTED; -+ } -+ -+ arinfo.ctr_nelems = private_subrange_dimensions(die); -+ -+ /* -+ * For each array dimension, construct an appropriate array of the -+ * type-so-far, overriding the parent type. -+ */ -+ -+ *replace = 1; -+ return ctf_add_array(ctf, ROOT_TYPE(top_level_type), &arinfo); -+} -+ -+/* -+ * Assemble an enumeration. -+ */ -+static ctf_id_t assemble_ctf_enumeration(const char *module_name, -+ const char *file_name, -+ Dwarf_Die *die, -+ Dwarf_Die *parent_die, -+ ctf_file_t *ctf, -+ ctf_id_t parent_ctf_id, -+ const char *locerrstr, -+ struct die_override *overrides, -+ int top_level_type, -+ enum skip_type *skip, -+ int *replace) -+{ -+ const char *name = dwarf_diename(die); -+ -+ return ctf_add_enum(ctf, ROOT_TYPE(top_level_type), name); -+} -+ -+/* -+ * Assemble an enumeration value. -+ */ -+static ctf_id_t assemble_ctf_enumerator(const char *module_name, -+ const char *file_name, -+ Dwarf_Die *die, -+ Dwarf_Die *parent_die, -+ ctf_file_t *ctf, -+ ctf_id_t parent_ctf_id, -+ const char *locerrstr, -+ struct die_override *overrides, -+ int top_level_type, -+ enum skip_type *skip, -+ int *replace) -+{ -+ const char *name = dwarf_diename(die); -+ Dwarf_Word value; -+ int err; -+ -+ CTF_DW_ENFORCE(name); -+ CTF_DW_ENFORCE(const_value); -+ CTF_DW_ENFORCE_NOT(bit_stride); -+ CTF_DW_ENFORCE_NOT(byte_stride); -+ -+ value = private_dwarf_udata(die, DW_AT_const_value, overrides); -+ err = ctf_add_enumerator(ctf, parent_ctf_id, name, value); -+ -+ if (err != 0) -+ return err; -+ -+ return parent_ctf_id; -+} -+ -+/* -+ * Assemble a typedef. -+ */ -+static ctf_id_t assemble_ctf_typedef(const char *module_name, -+ const char *file_name, -+ Dwarf_Die *die, -+ Dwarf_Die *parent_die, -+ ctf_file_t *ctf, -+ ctf_id_t parent_ctf_id, -+ const char *locerrstr, -+ struct die_override *overrides, -+ int top_level_type, -+ enum skip_type *skip, -+ int *replace) -+{ -+ const char *name = dwarf_diename(die); -+ ctf_id_t type_ref; -+ -+ CTF_DW_ENFORCE(name); -+ -+ type_ref = lookup_ctf_type(module_name, file_name, die, ctf, -+ overrides, locerrstr); -+ if (type_ref < 0) { -+ *skip = SKIP_ABORT; -+ return CTF_ERROR_REPORTED; -+ } -+ -+ return ctf_add_typedef(ctf, ROOT_TYPE(top_level_type), name, type_ref); -+} -+ -+/* -+ * Assemble a const/volatile/restrict qualifier. -+ */ -+static ctf_id_t assemble_ctf_cvr_qual(const char *module_name, -+ const char *file_name, -+ Dwarf_Die *die, -+ Dwarf_Die *parent_die, -+ ctf_file_t *ctf, -+ ctf_id_t parent_ctf_id, -+ const char *locerrstr, -+ struct die_override *overrides, -+ int top_level_type, -+ enum skip_type *skip, -+ int *replace) -+{ -+ ctf_id_t (*ctf_cvr_fun)(ctf_file_t *fp, uint_t flag, ctf_id_t ref); -+ ctf_id_t type_ref; -+ -+ switch (dwarf_tag(die)) { -+ case DW_TAG_const_type: ctf_cvr_fun = ctf_add_const; break; -+ case DW_TAG_volatile_type: ctf_cvr_fun = ctf_add_volatile; break; -+ case DW_TAG_restrict_type: ctf_cvr_fun = ctf_add_restrict; break; -+ default: -+ pr_err("%s: internal error: assemble_ctf_cvr_qual() called with\n" -+ "non-const/volatile/restrict: %i\n", locerrstr, dwarf_tag(die)); -+ exit(1); -+ } -+ -+ type_ref = lookup_ctf_type(module_name, file_name, die, ctf, -+ overrides, locerrstr); -+ if (type_ref < 0) { -+ *skip = SKIP_ABORT; -+ return CTF_ERROR_REPORTED; -+ } -+ -+ return ctf_cvr_fun(ctf, ROOT_TYPE(top_level_type), type_ref); -+} -+ -+/* -+ * Assemble a structure or union type. This assembles only the type itself, not -+ * its constituent members: that is done by assemble_ctf_su_member(). -+ * -+ * We assume that if a structure or union type is discovered with more members -+ * than an earlier-discovered type, that it is compatible with that earlier type -+ * and a superset of it. -+ * -+ * FIXME: in debug mode we should not assume this. -+ */ -+static ctf_id_t assemble_ctf_struct_union(const char *module_name, -+ const char *file_name, -+ Dwarf_Die *die, -+ Dwarf_Die *parent_die, -+ ctf_file_t *ctf, -+ ctf_id_t parent_ctf_id, -+ const char *locerrstr, -+ struct die_override *overrides, -+ int top_level_type, -+ enum skip_type *skip, -+ int *replace) -+{ -+ ctf_id_t (*ctf_add_sou)(ctf_file_t *fp, uint_t flag, const char *name, -+ size_t size); -+ -+ const char *name = dwarf_diename(die); -+ int is_union = (dwarf_tag(die) == DW_TAG_union_type); -+ struct ctf_memb_count *member_count = NULL; -+ ctf_id_t id; -+ long long size; -+ -+ /* -+ * FIXME: these both need handling for DWARF4 support. -+ */ -+ CTF_DW_ENFORCE_NOT(specification); -+ CTF_DW_ENFORCE_NOT(signature); -+ -+ /* -+ * Figure out the size of the type (if possible) and force it into the -+ * CTF to ensure that struct/union padding is added appropriately. -+ * -+ * If we don't know it, force a size of zero, which is interpreted as -+ * being equivalent to a call to the unsized struct/union addition -+ * function, letting libdtrace-ctf figure out a likely size as best it -+ * can. -+ */ -+ size = private_dwarf_size(die); -+ if (size < 0) -+ size = 0; -+ -+ /* -+ * Possibly we should ignore this entire structure, if we already know -+ * of one with the same name and at least as many members. If we -+ * already know of one and it is shorter, we want to use its ID rather -+ * than creating a new one. -+ * -+ * Note; by this point, the deduplicator has long run: thus we know for -+ * sure what module a potentially-shared type will end up in, and -+ * there's no need to double-check the shared CTF repository for types. -+ * We also know that the module must exist in the per_module hash. -+ */ -+ -+ if (name != NULL) { -+ char *structized_name = NULL; -+ struct per_module *ctf_pm; -+ -+ structized_name = str_appendn(structized_name, -+ is_union ? "u " : "s ", -+ name, NULL); -+ -+ ctf_pm = g_hash_table_lookup(per_module, module_name); -+ member_count = g_hash_table_lookup(ctf_pm->member_counts, -+ structized_name); -+ -+ if (member_count) { -+ free(structized_name); -+ dw_ctf_trace("%s: already exists (with ID %li) with %zi members\n" -+ "versus current %li members\n", -+ locerrstr, member_count->ctf_id, -+ member_count->count, -+ count_dwarf_members(die)); -+ -+ if (member_count->count < count_dwarf_members(die)) -+ return member_count->ctf_id; -+ -+ *skip = SKIP_SKIP; -+ return member_count->ctf_id; -+ } -+ -+ /* -+ * Not in existence yet. Create it. -+ */ -+ member_count = malloc(sizeof(struct ctf_memb_count)); -+ if (member_count == NULL) { -+ pr_err("Out of memory allocating structure/union member count\n"); -+ exit(1); -+ } -+ member_count->count = 0; -+ g_hash_table_insert(ctf_pm->member_counts, -+ structized_name, member_count); -+ } -+ -+ dw_ctf_trace("%s: adding structure %s\n", locerrstr, name); -+ -+ if (is_union) -+ ctf_add_sou = ctf_add_union_sized; -+ else -+ ctf_add_sou = ctf_add_struct_sized; -+ -+ id = ctf_add_sou(ctf, ROOT_TYPE(top_level_type), name, size); -+ -+ if (member_count != NULL) -+ member_count->ctf_id = id; -+ -+ return id; -+} -+ -+/* -+ * Figure out the offset of this type, in bits. (This is split in two -+ * for bitfields, where the bitfield itself gets represented elsewhere, -+ * in the CTF type of the member itself.) -+ * -+ * DW_AT_data_bit_offset is the simple case. DW_AT_data_member_location -+ * is trickier, and, alas, the DWARF2 variation is the complex one. -+ */ -+static int ctf_su_offset(Dwarf_Die *die, const char *locerrstr, -+ struct die_override *overrides, ulong_t *offset, -+ ulong_t *bit_offset) -+{ -+ struct die_override *o; -+ -+ if (private_dwarf_hasattr(die, DW_AT_data_bit_offset)) -+ *offset = private_dwarf_udata(die, DW_AT_data_bit_offset, NULL); -+ else if (private_dwarf_hasattr(die, DW_AT_data_member_location)) { -+ Dwarf_Attribute location_attr; -+ -+ private_dwarf_attr(die, DW_AT_data_member_location, -+ &location_attr); -+ -+ switch (dwarf_whatform(&location_attr)) { -+ case DW_FORM_data1: -+ case DW_FORM_data2: -+ case DW_FORM_data4: -+ case DW_FORM_data8: -+ case DW_FORM_udata: -+ case DW_FORM_sdata: -+ { -+ /* -+ * Byte offset, with bit_offset of containing -+ * structure/union added, if present. -+ * -+ * (No overrides supported here, yet, due to lack of -+ * sdata overrides and the desire for consistency. -+ * We can add them if we start passing down -+ * DW_AT_data_member_location overrides.) -+ */ -+ if (dwarf_whatform(&location_attr) == DW_FORM_sdata) { -+ Dwarf_Sword location; -+ -+ dwarf_formsdata(&location_attr, &location); -+ *offset = location * 8; -+ } else { -+ Dwarf_Word location; -+ -+ dwarf_formudata(&location_attr, &location); -+ *offset = location * 8; -+ } -+ break; -+ } -+ case DW_FORM_block1: -+ case DW_FORM_block2: -+ case DW_FORM_block4: -+ { -+ Dwarf_Op *location; -+ size_t nlocs; -+ -+ /* -+ * DWARF 2 block-based data_member_location. This can -+ * be quite complicated in some situations (notably C++ -+ * virtual bases), but for normal structure members it -+ * is simple. FIXME for userspace tracing of C++. -+ * -+ * This is thoroughly specific to the forms of DWARF2 -+ * emitted by GCC. We don't need to feel guilty about -+ * this because elfutils does just the same thing. -+ */ -+ -+ if (dwarf_getlocation(&location_attr, &location, -+ &nlocs) < 0) { -+ pr_err("%s: offset not a valid location expression: %s\n", -+ locerrstr, dwarf_errmsg(dwarf_errno())); -+ return CTF_ERROR_REPORTED; -+ } -+ -+ if ((nlocs != 1) || -+ ((location[0].atom != DW_OP_plus_uconst) && -+ (location[0].atom != DW_OP_constu))) { -+ pr_err("%s: complex location lists not supported:\n" -+ "either C++ or non-GCC output: skipped\n", locerrstr); -+ return CTF_ERROR_REPORTED; -+ } -+ -+ *offset = location[0].number * 8; -+ break; -+ } -+ case DW_FORM_exprloc: -+ { -+ /* -+ * We need a full DWARF expression list interpreter to -+ * handle this. -+ */ -+ pr_err("DWARF 4 expression location lists not supported.\n"); -+ exit(1); -+ } -+ default: -+ { -+ pr_err("%s: expression location lists in form %u not supported.\n", -+ locerrstr, dwarf_whatform(&location_attr)); -+ exit(1); -+ } -+ } -+ } -+ -+ /* -+ * Handle the bit offset. -+ */ -+ if (private_dwarf_hasattr(die, DW_AT_bit_offset)) { -+ Dwarf_Attribute bit_attr; -+ Dwarf_Word bit; -+ -+ private_dwarf_attr(die, DW_AT_bit_offset, -+ &bit_attr); -+ dwarf_formudata(&bit_attr, &bit); -+ *bit_offset = bit; -+ } -+ -+ /* -+ * Handle the offset value override. It does not matter which method -+ * has been used to get the value. At this point offset is always -+ * the bit distance of the member from the structure/union start. -+ * -+ * The DW_AT_data_bit_offset override is always used to pass the offset -+ * around, so that we don't need to add special override handling for -+ * various forms of the DW_AT_data_member_location as a special case. -+ * This is safe as it is not possible to have both attributes attached -+ * to the same DIE per the DWARF4 standard, and if we have one attached -+ * as an override to a DIE that has the other, we will only ever need to -+ * use one (since no DIE can be both an unnamed struct/union and a -+ * bitfield at the same time). -+ */ -+ o = private_find_override(die, DW_AT_data_bit_offset, overrides); -+ if (o != NULL) { -+ if (o->op == DIE_OVERRIDE_REPLACE) -+ *offset = o->value; -+ else -+ *offset += o->value; -+ } -+ -+ return 0; -+} -+ -+/* -+ * Assemble a structure or union member. -+ * -+ * We only assemble a member of a given name if a member by that name does not -+ * already exist, and if the member is not blacklisted. -+ */ -+static ctf_id_t assemble_ctf_su_member(const char *module_name, -+ const char *file_name, -+ Dwarf_Die *die, -+ Dwarf_Die *parent_die, -+ ctf_file_t *ctf, -+ ctf_id_t parent_ctf_id, -+ const char *locerrstr, -+ struct die_override *overrides, -+ int top_level_type, -+ enum skip_type *skip, -+ int *replace) -+{ -+ ulong_t offset = 0; -+ ulong_t bit_offset = 0; -+ struct ctf_full_id *new_type; -+ Dwarf_Attribute type_attr; -+ Dwarf_Die type_die; -+ Dwarf_Die cu_die; -+ int err; -+ struct ctf_memb_count *member_count; -+ const char *struct_name = dwarf_diename(parent_die); -+ -+ CTF_DW_ENFORCE(type); -+ -+ /* -+ * Increment the member count of named structures. This is the number -+ * of members in the DWARF, not in the CTF: blacklisted members are -+ * counted too. -+ */ -+ if (struct_name != NULL) { -+ int is_union = (dwarf_tag(parent_die) == DW_TAG_union_type); -+ char *structized_name = NULL; -+ struct per_module *ctf_pm; -+ -+ structized_name = str_appendn(structized_name, -+ is_union ? "u " : "s ", -+ struct_name, NULL); -+ -+ ctf_pm = g_hash_table_lookup(per_module, module_name); -+ member_count = g_hash_table_lookup(ctf_pm->member_counts, -+ structized_name); -+ member_count->count++; -+ free(structized_name); -+ } -+ -+ /* -+ * If this member is blacklisted, just skip it. -+ */ -+ if (member_blacklisted(die, parent_die)) { -+ dw_ctf_trace("%s: blacklisted, skipping.\n", locerrstr); -+ return parent_ctf_id; -+ } -+ -+ /* -+ * Find the associated type so we can either add a member with that type -+ * (if it is named) or add its members directly (for unnamed types, -+ * which must be unnamed structs/unions): then figure out the member's -+ * offset. -+ */ -+ private_dwarf_attr(die, DW_AT_type, &type_attr); -+ if (dwarf_formref_die(&type_attr, &type_die) == NULL) { -+ pr_err("%s: nonexistent type reference.\n" -+ "Corrupted DWARF, cannot continue.\n", locerrstr); -+ exit(1); -+ } -+ dwarf_diecu(&type_die, &cu_die, NULL, NULL); -+ -+ err = ctf_su_offset(die, locerrstr, overrides, &offset, &bit_offset); -+ if (err < 0) { -+ *skip = SKIP_ABORT; -+ return err; -+ } -+ -+ /* -+ * If this is an unnamed struct/union, call directly back to -+ * die_to_ctf() to add this struct's members to the current structure, -+ * merging it seamlessly with its parent (excepting only the member -+ * offsets). Use DW_AT_data_bit_offset because it does not require -+ * the complexity of DW_AT_data_member_location to be faked. -+ */ -+ if (!private_dwarf_hasattr(die, DW_AT_name)) { -+ Dwarf_Die child_die; -+ int dummy = 0; -+ -+ if ((dwarf_tag(&type_die) != DW_TAG_structure_type) && -+ (dwarf_tag(&type_die) != DW_TAG_union_type)) { -+ pr_err("%s:%lx: not supported: anonymous structure member\n" -+ "not a structure or union.\n", locerrstr, -+ DIEOFFSET(die)); -+ *skip = SKIP_ABORT; -+ return CTF_ERROR_REPORTED; -+ } -+ -+ /* -+ * Anonymous structure or union with no members. Silently skip. -+ */ -+ switch (dwarf_child(&type_die, &child_die)) { -+ case -1: -+ *skip = SKIP_ABORT; -+ return CTF_ERROR_REPORTED; -+ case 1: /* No DIEs at all in this aggregate */ -+ return parent_ctf_id; -+ default: /* Child DIEs exist. */ -+ break; -+ } -+ -+ /* -+ * Add override that will adjust offset of the anonymous -+ * struct/union members during inlining. The bit_offset is -+ * ignored here as it is not expected that a nested -+ * structure/union will start on a non-byte-aligned boundary. -+ */ -+ struct die_override o[] = {{ dwarf_tag(&child_die), -+ DW_AT_data_bit_offset, -+ DIE_OVERRIDE_ADD, -+ offset, overrides }, {0}}; -+ -+ die_to_ctf(module_name, file_name, &child_die, parent_die, ctf, -+ parent_ctf_id, o, 0, 0, skip, &dummy, NULL); -+ -+ return parent_ctf_id; -+ } -+ -+ /* -+ * Get the CTF ID of this member's type, by recursive lookup. -+ * -+ * If this is a bitfield, we want to note that said type's size and -+ * bit-offset should be adjusted. -+ */ -+ if (private_dwarf_hasattr(die, DW_AT_bit_size)) { -+ struct die_override o[] = { -+ { DW_TAG_base_type, -+ DW_AT_bit_size, -+ DIE_OVERRIDE_REPLACE, -+ private_dwarf_udata(die, DW_AT_bit_size, -+ NULL), -+ NULL }, -+ { DW_TAG_base_type, -+ DW_AT_bit_offset, -+ DIE_OVERRIDE_REPLACE, -+ bit_offset, -+ overrides }, -+ {0} -+ }; -+ -+ new_type = construct_ctf_id(module_name, file_name, &type_die, -+ &cu_die, o); -+ } else { -+ if (bit_offset != 0) { -+ pr_err("%s:%s: error in member %s: No DW_AT_bit_size, but nonzero bit offset\n" -+ "of %lx in overall offset of %lx\n", locerrstr, -+ dwarf_diename(&cu_die), dwarf_diename(die), -+ bit_offset, offset); -+ return CTF_ERROR_REPORTED; -+ } -+ new_type = construct_ctf_id(module_name, file_name, &type_die, -+ &cu_die, NULL); -+ } -+ -+ if (new_type == NULL) { -+ *skip = SKIP_ABORT; -+ return CTF_ERROR_REPORTED; -+ } -+ -+ if ((new_type->ctf_file != ctf) && -+ (new_type->ctf_file != lookup_ctf_file("shared_ctf"))) { -+ pr_err("%s:%s: internal error: referenced type lookup for member %s\n" -+ "yields a different CTF file: %p versus %p\n", -+ locerrstr, dwarf_diename(&cu_die), dwarf_diename(die), -+ ctf, new_type->ctf_file); -+ pr_err("dedup() is probably buggy.\n"); -+ exit(1); -+ } -+ -+ if (ctf_add_member_offset(ctf, parent_ctf_id, dwarf_diename(die), -+ new_type->ctf_id, offset) < 0) { -+ /* -+ * If we have seen this member before, as part of another -+ * definition somewhere else, that's fine. We cannot recurse -+ * from this point, so we can just return the parent CTF ID, the -+ * ID of the containing structure. -+ */ -+ if (ctf_errno(ctf) == ECTF_DUPLICATE) -+ return parent_ctf_id; -+ -+ /* -+ * We have special handling for cases where CTF doesn't know of -+ * either this member's type or the enclosing structure: when -+ * libdtrace-ctf is old enough to need it, we try a ctf_update() -+ * in case this is recently added, but no special handling for -+ * other errors, which the caller must report. -+ */ -+ -+ if (ctf_errno(ctf) != ECTF_BADID && -+ ctf_errno(ctf) != ECTF_NOTSOU) -+ return CTF_NO_ERROR_REPORTED; -+ -+#ifndef LIBDTRACE_CTF_OMISSIBLE_CTF_UPDATE -+ ctf_file_t *shared_ctf; -+ -+ /* -+ * Try an update of the current CTF file first, to bring the -+ * type ID table up to date: if that doesn't work, try an update -+ * of the shared table. (If none is needed, this is cheap.) -+ */ -+ -+ if (ctf_update(new_type->ctf_file) < 0) { -+ pr_err("Cannot update CTF file: %s\n", -+ ctf_errmsg(ctf_errno(ctf))); -+ exit(1); -+ } -+ -+ if (ctf_add_member_offset(ctf, parent_ctf_id, -+ dwarf_diename(die), -+ new_type->ctf_id, -+ offset) == 0) -+ return parent_ctf_id; -+ -+ shared_ctf = lookup_ctf_file("shared_ctf"); -+ if (ctf_update(shared_ctf) < 0) { -+ pr_err("Cannot update shared CTF: %s\n", -+ ctf_errmsg(ctf_errno(shared_ctf))); -+ exit(1); -+ } -+ -+ if (ctf_add_member_offset(ctf, parent_ctf_id, -+ dwarf_diename(die), -+ new_type->ctf_id, -+ offset) == 0) -+ return parent_ctf_id; -+#endif -+#ifdef DEBUG -+ pr_err("%s: Internal error: %s %s:%s:%p:%i\n" -+ "on member addition to ctf_file %p.\n", -+ locerrstr, ctf_errmsg(ctf_errno(ctf)), -+ new_type->module_name, new_type->file_name, -+ new_type->ctf_file, (int) new_type->ctf_id, ctf); -+#else -+ pr_err("%s: Internal error: %s %p:%i\n" -+ "on member addition to ctf_file %p.\n", -+ locerrstr, ctf_errmsg(ctf_errno(ctf)), -+ new_type->ctf_file, (int) new_type->ctf_id, -+ ctf); -+#endif -+ return CTF_ERROR_REPORTED; -+ } -+ -+ return parent_ctf_id; -+} -+ -+/* -+ * Assemble a variable. -+ */ -+static ctf_id_t assemble_ctf_variable(const char *module_name, -+ const char *file_name, -+ Dwarf_Die *die, -+ Dwarf_Die *parent_die, -+ ctf_file_t *ctf, -+ ctf_id_t parent_ctf_id, -+ const char *locerrstr, -+ struct die_override *overrides, -+ int top_level_type, -+ enum skip_type *skip, -+ int *replace) -+{ -+ const char *name = dwarf_diename(die); -+ char *blacklist_name = NULL; -+ ctf_id_t type_ref; -+ int err; -+ -+ CTF_DW_ENFORCE(name); -+ -+ /* -+ * If blacklisted, just skip it. -+ */ -+ blacklist_name = str_appendn(blacklist_name, module_name, "`", -+ dwarf_diename(die), NULL); -+ if (g_hash_table_lookup_extended(variable_blacklist, blacklist_name, -+ NULL, NULL)) { -+ dw_ctf_trace("%s: variable %s is blacklisted for static/non-static ambiguity.\n", -+ file_name, blacklist_name); -+ free(blacklist_name); -+ return 0; -+ } -+ free(blacklist_name); -+ -+ type_ref = lookup_ctf_type(module_name, file_name, die, ctf, -+ overrides, locerrstr); -+ if (type_ref < 0) { -+ *skip = SKIP_ABORT; -+ return CTF_ERROR_REPORTED; -+ } -+ -+ /* -+ * This isn't a type: full DWARF child recursion and type-id addition is -+ * not called for. -+ */ -+ *skip = SKIP_SKIP; -+ -+ err = ctf_add_variable(ctf, name, type_ref); -+ -+ if (err == 0) -+ dw_ctf_trace("%p: Added variable %s, type %i\n", ctf, name, -+ (int)type_ref); -+ -+ /* -+ * Variable references to opaque versus non-opaque structures could only -+ * get deduplicated with yet another deduplication pass. This seems -+ * pointlessly expensive when nothing can refer to them: just skip -+ * duplicates instead. -+ */ -+ if ((err < 0) && (ctf_errno(ctf) == ECTF_DUPLICATE)) -+ return 0; -+ -+ return err; -+ -+} -+ -+/* Writeout. */ -+ -+static void write_types(char *output, int standalone) -+{ -+ GHashTableIter module_iter; -+ char *module; -+ struct per_module *per_mod; -+ ctf_file_t **ctfs; -+ const char **names; -+ size_t i = 0; -+ size_t ctf_count = g_hash_table_size(per_module); -+ -+ /* -+ * Work over all the modules and write their compressed CTF data out. -+ * Standalone modules get placed in files in the output directory named -+ * with names ending in .mod.ctf.new, and the makefile moves .ctf.new -+ * over the top of .ctf iff it has changed; built-in modules and the -+ * core kernel and shared type repository are placed into a CTF archive. -+ */ -+ if (standalone) { -+ if ((mkdir(output, 0777) < 0) && errno != EEXIST) { -+ perror("Cannot create .ctf directory"); -+ exit(1); -+ } -+ } else { -+ ctfs = calloc(ctf_count, sizeof(ctf_file_t *)); -+ names = calloc(ctf_count, sizeof(char *)); -+ if (!ctfs || !names) -+ pr_err("Out of memory in CTF writeout\n"); -+ } -+ -+ /* -+ * Write the files out (in standalone mode), or construct the arrays of -+ * module names and files to put in the archive (otherwise). -+ */ -+ g_hash_table_iter_init(&module_iter, per_module); -+ while (g_hash_table_iter_next(&module_iter, (void **) &module, -+ (void **)&per_mod)) { -+ int fd; -+ -+ dw_ctf_trace("Writing out %s\n", module); -+ -+ if (ctf_update(per_mod->ctf_file) < 0) { -+ pr_err("Cannot serialize CTF file %s: %s\n", -+ module, ctf_errmsg(ctf_errno(per_mod->ctf_file))); -+ exit(1); -+ } -+ -+ if (!standalone) { -+ names[i] = module; -+ ctfs[i] = per_mod->ctf_file; -+ i++; -+ } else { -+ char *path = NULL; -+ -+ path = str_appendn(path, output, "/", module, -+ ".mod.ctf.new", NULL); -+ -+ fd = open(path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, -+ 0666); -+ if (fd < 0) { -+ pr_err("Cannot open CTF file %s for writing: %s\n", -+ path, strerror(errno)); -+ exit(1); -+ } -+ if (ctf_compress_write(per_mod->ctf_file, fd) < 0) { -+ pr_err("Cannot write to CTF file %s: " -+ "%s\n", path, -+ ctf_errmsg(ctf_errno(per_mod->ctf_file))); -+ exit(1); -+ } -+ if (close(fd) != 0) { -+ pr_err("Cannot close CTF file %s: %s\n", -+ path, strerror(errno)); -+ exit(1); -+ } -+ free(path); -+ } -+ } -+ -+ if (!standalone) { -+ int err; -+ -+ err = ctf_arc_write(output, ctfs, ctf_count, names, 4096); -+ if (err != 0) { -+ pr_err("Cannot write to CTF archive %s: %s\n", -+ output, err < ECTF_BASE ? strerror(err) : -+ ctf_errmsg(err)); -+ exit(1); -+ } -+ free(names); -+ free(ctfs); -+ } -+} -+ -+/* Utilities. */ -+ -+/* -+ * Given a DIE that may contain a type attribute, look up the target of that -+ * attribute and return it, or NULL if none. -+ */ -+static Dwarf_Die *private_dwarf_type(Dwarf_Die *die, Dwarf_Die *target_die) -+{ -+ Dwarf_Attribute type_ref_attr; -+ -+ if (private_dwarf_attr(die, DW_AT_type, &type_ref_attr) != NULL) { -+ if (dwarf_formref_die(&type_ref_attr, target_die) == NULL) { -+ pr_err("Corrupt DWARF at offset %lx: ref with no target.\n", -+ DIEOFFSET(die)); -+ exit(1); -+ } -+ return target_die; -+ } -+ -+ return NULL; -+} -+ -+/* -+ * Check for existence of an attribute in a DIE, chasing through -+ * DW_AT_specification if need be. -+ */ -+static inline int private_dwarf_hasattr(Dwarf_Die *die, -+ unsigned int search_name) -+{ -+ int hasattr = 0; -+ Dwarf_Attribute spec_ref_attr; -+ Dwarf_Die spec_die; -+ -+ /* -+ * DW_AT_declaration is not forwarded, because non-declarations can -+ * reference declarations via DW_AT_specification, without implying that -+ * the referencing DIE is a declaration. -+ */ -+ hasattr = dwarf_hasattr(die, search_name); -+ if (hasattr || (search_name == DW_AT_declaration)) -+ return hasattr; -+ -+ if (dwarf_attr(die, DW_AT_specification, &spec_ref_attr) != NULL) { -+ if (dwarf_formref_die(&spec_ref_attr, &spec_die) == NULL) { -+ pr_err("Corrupt DWARF at offset %lx: ref with no target.\n", -+ DIEOFFSET(die)); -+ exit(1); -+ } -+ return dwarf_hasattr(&spec_die, search_name); -+ } -+ return hasattr; -+} -+ -+/* -+ * Return a DIE attribute, chasing through DW_AT_specification if need be. -+ */ -+static inline Dwarf_Attribute *private_dwarf_attr(Dwarf_Die *die, -+ unsigned int search_name, -+ Dwarf_Attribute *result) -+{ -+ Dwarf_Attribute spec_ref_attr; -+ Dwarf_Die spec_die; -+ Dwarf_Attribute *ret; -+ -+ ret = dwarf_attr(die, search_name, result); -+ if (ret != NULL || (search_name == DW_AT_declaration)) -+ return ret; -+ -+ if (dwarf_attr(die, DW_AT_specification, &spec_ref_attr) != NULL) { -+ if (dwarf_formref_die(&spec_ref_attr, &spec_die) == NULL) { -+ pr_err("Corrupt DWARF at offset %lx: ref with no target.\n", -+ DIEOFFSET(die)); -+ exit(1); -+ } -+ return dwarf_attr(&spec_die, search_name, result); -+ } -+ -+ return NULL; -+} -+ -+/* -+ * Given a DIE that contains a udata attribute, look up that attribute and -+ * return its value (optionally overridden or modified by the die_overrides). -+ */ -+static inline Dwarf_Word private_dwarf_udata(Dwarf_Die *die, int attribute, -+ struct die_override *overrides) -+{ -+ Dwarf_Attribute attr; -+ Dwarf_Word value; -+ struct die_override *override; -+ -+ override = private_find_override(die, attribute, overrides); -+ -+ if (override && override->op == DIE_OVERRIDE_REPLACE) -+ return override->value; -+ -+ private_dwarf_attr(die, attribute, &attr); -+ dwarf_formudata(&attr, &value); -+ -+ if (override) -+ value += override->value; -+ -+ return value; -+} -+ -+/* -+ * Given a DIE, return its byte size, if known and interpretable, or -1 -+ * otherwise. -+ */ -+static inline long long -+private_dwarf_size(Dwarf_Die *die) -+{ -+ Dwarf_Attribute size_attr; -+ -+ if (private_dwarf_hasattr(die, DW_AT_byte_size)) { -+ private_dwarf_attr(die, DW_AT_byte_size, &size_attr); -+ -+ switch (dwarf_whatform(&size_attr)) { -+ case DW_FORM_data1: -+ case DW_FORM_data2: -+ case DW_FORM_data4: -+ case DW_FORM_data8: -+ case DW_FORM_udata: { -+ Dwarf_Word dw_size; -+ -+ dwarf_formudata(&size_attr, &dw_size); -+ return dw_size; -+ } -+ case DW_FORM_sdata: { -+ Dwarf_Sword dw_size; -+ -+ dwarf_formsdata(&size_attr, &dw_size); -+ return dw_size; -+ } -+ } -+ } -+ -+ /* -+ * exprloc or other type we don't know how to interpret yet. -+ */ -+ return -1; -+} -+ -+/* -+ * Find an override in an override list, walking up the chained overrides if -+ * need be, until one is found. -+ */ -+static struct die_override * -+private_find_override(Dwarf_Die *die, -+ int attribute, -+ struct die_override *overrides) -+{ -+ size_t i; -+ -+ if (overrides == NULL) -+ return NULL; -+ -+ while (overrides) { -+ struct die_override *chain = NULL; -+ for (i = 0; overrides[i].tag != 0; i++) { -+ chain = overrides[i].chain; -+ if ((overrides[i].tag == dwarf_tag(die)) && -+ (overrides[i].attribute == attribute)) -+ return &overrides[i]; -+ } -+ overrides = chain; -+ } -+ -+ return NULL; -+} -+ -+/* -+ * Determine the dimensions of an array subrange, or 0 if variable. -+ */ -+static Dwarf_Word private_subrange_dimensions(Dwarf_Die *die) -+{ -+ int flexible_array = 0; -+ Dwarf_Attribute nelem_attr; -+ Dwarf_Word nelems; -+ -+ if (((private_dwarf_attr(die, DW_AT_upper_bound, -+ &nelem_attr) == NULL) && -+ (private_dwarf_attr(die, DW_AT_count, -+ &nelem_attr) == NULL)) || -+ (!private_dwarf_hasattr(die, DW_AT_type))) -+ flexible_array = 1; -+ -+ if (!flexible_array) -+ switch (dwarf_whatform(&nelem_attr)) { -+ case DW_FORM_data1: -+ case DW_FORM_data2: -+ case DW_FORM_data4: -+ case DW_FORM_data8: -+ case DW_FORM_udata: -+ break; -+ default: -+ flexible_array = 1; -+ } -+ -+ if (flexible_array) -+ return 0; -+ -+ dwarf_formudata(&nelem_attr, &nelems); -+ -+ /* -+ * Upper bounds indicate that we have one more element than that, since -+ * C starts counting at zero. -+ */ -+ if (private_dwarf_hasattr(die, DW_AT_upper_bound)) -+ nelems++; -+ -+ return nelems; -+} -+ -+/* -+ * Intern an atom in the atoms table and return it, or free it and return the -+ * existing atom if one is already interned. (Despite the type signature, this -+ * return value is constant and should not be freed.) -+ */ -+static void *intern(char *atom) -+{ -+ void *foo; -+ -+ if (!g_hash_table_lookup_extended(atoms, atom, &foo, NULL)) { -+ g_hash_table_insert(atoms, atom, NULL); -+ foo = atom; -+ } else -+ free(atom); -+ -+ return foo; -+} -+ -+/* -+ * An error checking strdup(). -+ */ -+static char *xstrdup(const char *s) -+{ -+ char *s2 = strdup(s); -+ -+ if (s2 == NULL) { -+ pr_err("%s: Out of memory\n", __func__); -+ exit(1); -+ } -+ -+ return s2; -+} -+ -+/* -+ * A string appender working on dynamic strings. -+ */ -+static char *str_append(char *s, const char *append) -+{ -+ size_t s_len = 0; -+ -+ if (append == NULL) -+ return s; -+ -+ if (s != NULL) -+ s_len = strlen(s); -+ -+ size_t append_len = strlen(append); -+ -+ s = realloc(s, s_len + append_len + 1); -+ -+ if (s == NULL) { -+ pr_err("Out of memory appending a string of length %li to one of length %li\n", -+ strlen(append), s_len); -+ exit(1); -+ } -+ -+ memcpy(s + s_len, append, append_len); -+ s[s_len+append_len] = '\0'; -+ -+ return s; -+} -+ -+/* -+ * A vararg string appender. -+ */ -+static char *str_appendn(char *s, ...) -+{ -+ va_list ap; -+ const char *append; -+ size_t len, s_len = 0; -+ -+ va_start(ap, s); -+ if (s) -+ s_len = strlen(s); -+ len = s_len; -+ -+ append = va_arg(ap, const char *); -+ while (append != NULL) { -+ len += strlen(append); -+ append = va_arg(ap, char *); -+ } -+ va_end(ap); -+ -+ s = realloc(s, len + 1); -+ if (s == NULL) { -+ pr_err("Out of memory appending a string of length %li to one of length %li\n", -+ len - s_len, s_len); -+ exit(1); -+ } -+ -+ va_start(ap, s); -+ append = va_arg(ap, const char *); -+ while (append != NULL) { -+ size_t append_len = strlen(append); -+ -+ memcpy(s + s_len, append, append_len); -+ s_len += append_len; -+ -+ append = va_arg(ap, char *); -+ } -+ s[len] = '\0'; -+ va_end(ap); -+ -+ return s; -+} -+ -+/* -+ * Filter a GList, calling a predicate on it and removing all elements for which -+ * the predicate returns true, calling the free_func on them if set. -+ */ -+static GList *list_filter(GList *list, filter_pred_fun fun, -+ GDestroyNotify free_func, void *data) -+{ -+ GList *cur = list; -+ -+ while (cur) { -+ GList *next = cur->next; -+ -+ if (fun(cur->data, data)) { -+ if (free_func) -+ free_func(cur->data); -+ list = g_list_delete_link(list, cur); -+ } -+ cur = next; -+ } -+ -+ return list; -+} -+ -+/* -+ * Figure out the (pathless, suffixless) module name for a given module file (.o -+ * or .ko), and return it in a new dynamically allocated string. -+ * -+ * Takes the object_to_module mapping into account. -+ */ -+static char *fn_to_module(const char *file_name) -+{ -+ char *module_name; -+ char *chop, *dash; -+ -+ module_name = g_hash_table_lookup(object_to_module, file_name); -+ if (module_name != NULL) -+ return xstrdup(module_name); -+ -+ chop = strrchr(file_name, '/'); -+ if (chop != NULL) -+ module_name = xstrdup(++chop); -+ else -+ module_name = xstrdup(file_name); -+ -+ chop = strrchr(module_name, '.'); -+ if (chop != NULL) -+ *chop = '\0'; -+ -+ dash = module_name; -+ while (dash != NULL) { -+ dash = strchr(dash, '-'); -+ if (dash != NULL) -+ *dash = '_'; -+ } -+ -+ return module_name; -+} -+ -+/* -+ * Determine, and cache, absolute filenames. This is called in very hot -+ * paths, notably type_id(), and must be kept fast. -+ */ -+static const char *abs_file_name(const char *file_name) -+{ -+ static GHashTable *abs_file_names; -+ const char *abs_name; -+ -+ if (abs_file_names == NULL) -+ abs_file_names = g_hash_table_new_full(g_str_hash, g_str_equal, -+ free, free); -+ -+ abs_name = g_hash_table_lookup(abs_file_names, file_name); -+ -+ if (abs_name == NULL) { -+ char abspath[PATH_MAX] = ""; -+ -+ if (realpath(file_name, abspath) == NULL) -+ strcpy(abspath, file_name); -+ g_hash_table_replace(abs_file_names, -+ xstrdup(file_name), xstrdup(abspath)); -+ -+ abs_name = g_hash_table_lookup(abs_file_names, file_name); -+ } -+ -+ return abs_name; -+} -+ -+/* -+ * Determine absolute filenames relative to some other directory. This does not -+ * need to be fast. The returned name is dynamically allocated, and must be -+ * freed by the caller. -+ */ -+static char *rel_abs_file_name(const char *file_name, const char *relative_to) -+{ -+ int dir = -1; -+ static int warned = 0; -+ char *abspath; -+ /* -+ * If we can't get this name relatively, we might as well *try* to do it -+ * absolutely: but print a warning. -+ */ -+ dir = open(".", O_RDONLY | O_DIRECTORY); -+ if (dir < 0) { -+ if (!warned) { -+ perror("Cannot open current directory"); -+ warned = 1; -+ } -+ } else { -+ if (chdir(relative_to) < 0) -+ if (!warned) { -+ pr_err("Cannot change directory to " -+ "%s: %s\n", relative_to, -+ strerror(errno)); -+ warned = 1; -+ } -+ } -+ -+ abspath = realpath(file_name, NULL); -+ if (abspath == NULL) -+ abspath = xstrdup(file_name); -+ -+ if ((dir > -1) && (fchdir(dir) < 0)) { -+ perror("Cannot return to original directory after relative realpath()"); -+ exit(1); -+ } -+ -+ close(dir); -+ -+ return abspath; -+} -+ -+/* -+ * Given a type encoding table, and a size, return the CTF encoding for that -+ * type, or 0 if none. -+ */ -+static int find_ctf_encoding(struct type_encoding_tab *type_tab, size_t size) -+{ -+ size_t i; -+ -+ for (i = 0; type_tab[i].size != 0; i++) { -+ if (type_tab[i].size == size) -+ return type_tab[i].ctf_encoding; -+ } -+ return 0; -+} -+ -+/* -+ * Count the number of members of a DWARF aggregate. -+ */ -+static long count_dwarf_members(Dwarf_Die *d) -+{ -+ const char *err; -+ Dwarf_Die die; -+ -+ switch (dwarf_child(d, &die)) { -+ case -1: -+ err = "fetch first child of aggregate"; -+ goto fail; -+ case 1: /* No DIEs at all in this aggregate */ -+ return 0; -+ default: /* Child DIEs exist. */ -+ break; -+ } -+ -+ /* -+ * We are only interested in children of type DW_TAG_member. -+ */ -+ int sib_ret; -+ long count = 0; -+ -+ do -+ if (dwarf_tag(&die) == DW_TAG_member) -+ count++; -+ while ((sib_ret = dwarf_siblingof(&die, &die)) == 0); -+ -+ if (sib_ret == -1) { -+ err = "count members"; -+ goto fail; -+ } -+ -+ return count; -+ -+ fail: -+ pr_err("Cannot %s: %s\n", err, dwarf_errmsg(dwarf_errno())); -+ exit(1); -+} -+ -+/* -+ * Free a per_module's contents. -+ */ -+static void private_per_module_free(void *per_module) -+{ -+ struct per_module *per_mod = per_module; -+ -+ ctf_close(per_mod->ctf_file); -+ g_hash_table_destroy(per_mod->member_counts); -+ free(per_module); -+} -+ -+/* -+ * Free a fn_to_die_to_parent subhash. -+ */ -+static void private_fn_die_parent_free(void *ptr) -+{ -+ g_hash_table_destroy((GHashTable *) ptr); -+} -+ -+/* -+ * Get a ctf_file out of the per_module hash for a given module. -+ */ -+static ctf_file_t *lookup_ctf_file(const char *module_name) -+{ -+ struct per_module *per_mod; -+ -+ per_mod = g_hash_table_lookup(per_module, module_name); -+ if (per_mod == NULL) -+ return NULL; -+ return per_mod->ctf_file; -+} -diff --git a/scripts/dwarf2ctf/eu_simple.c b/scripts/dwarf2ctf/eu_simple.c -new file mode 100644 -index 000000000000..49886e5e5411 ---- /dev/null -+++ b/scripts/dwarf2ctf/eu_simple.c -@@ -0,0 +1,2 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+#include "../eu_simple.c" -diff --git a/scripts/dwarf2ctf/member.blacklist b/scripts/dwarf2ctf/member.blacklist -new file mode 100644 -index 000000000000..85122def7b5f ---- /dev/null -+++ b/scripts/dwarf2ctf/member.blacklist -@@ -0,0 +1 @@ -+include/linux/netfilter/ipset/ip_set_ahash.h:ip_set_hash.next -diff --git a/scripts/eu_simple.c b/scripts/eu_simple.c -new file mode 100644 -index 000000000000..e2736f29d001 ---- /dev/null -+++ b/scripts/eu_simple.c -@@ -0,0 +1,356 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Convenience wrappers for functions in elfutils. -+ * -+ * (C) 2014, 2017 Oracle, Inc. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <errno.h> -+#include <stdio.h> -+#include <stdlib.h> -+#include <string.h> -+ -+#include <elfutils/libdwfl.h> -+#include <elfutils/version.h> -+ -+#include <eu_simple.h> -+ -+#define __unused__ __attribute__((__unused__)) -+ -+/* -+ * A version of dwfl_report_elf() that compensates for parameter changes in -+ * newer elfutils. -+ */ -+static Dwfl_Module *private_dwfl_report_elf(Dwfl *dwfl, const char *name, -+ const char *file_name, int fd, -+ GElf_Addr base) -+{ -+#if _ELFUTILS_PREREQ(0,156) -+ return dwfl_report_elf(dwfl, name, file_name, fd, base, 0); -+#else -+ return dwfl_report_elf(dwfl, name, file_name, fd, base); -+#endif -+} -+ -+/* -+ * Stub libdwfl callback, use only the ELF handle passed in. -+ */ -+static int no_debuginfo(Dwfl_Module *mod __unused__, -+ void **userdata __unused__, -+ const char *modname __unused__, -+ Dwarf_Addr base __unused__, -+ const char *file_name __unused__, -+ const char *debuglink_file __unused__, -+ GElf_Word debuglink_crc __unused__, -+ char **debuginfo_file_name __unused__) -+{ -+ return -1; -+} -+ -+/* -+ * Wrap up dwfl_new() complexities. -+ */ -+Dwfl *simple_dwfl_new(const char *file_name, Dwfl_Module **module) -+{ -+ const char *err; -+ -+ static Dwfl_Callbacks cb = { -+ .find_debuginfo = no_debuginfo, -+ .section_address = dwfl_offline_section_address -+ }; -+ Dwfl *dwfl = dwfl_begin(&cb); -+ Dwfl_Module *mod; -+ -+ if (dwfl == NULL) { -+ err = "initialize libdwfl"; -+ goto fail; -+ } -+ -+ mod = private_dwfl_report_elf(dwfl, "", file_name, -1, 0); -+ if (mod == NULL) { -+ err = "open object file with libdwfl"; -+ goto fail; -+ } -+ if (module) -+ *module = mod; -+ -+ if (dwfl_report_end(dwfl, NULL, NULL) != 0) { -+ err = "finish opening object file with libdwfl"; -+ goto fail; -+ } -+ -+ return dwfl; -+ fail: -+ fprintf(stderr, "Cannot %s for %s: %s\n", err, file_name, -+ dwfl_errmsg(dwfl_errno())); -+ exit(1); -+} -+ -+/* -+ * A variant of simple_dwfl_new() that iterates over multiple object files. -+ * (Used for thin archives.) -+ * -+ * Takes ownership of the paths, until free. -+ */ -+struct simple_dwfl_multi * -+simple_dwfl_new_multi(char **paths) -+{ -+ struct simple_dwfl_multi *multi; -+ -+ multi = malloc(sizeof(struct simple_dwfl_multi)); -+ if (multi == NULL) -+ return NULL; -+ -+ multi->paths = paths; -+ multi->i = -1; -+ multi->dwfl = NULL; -+ multi->last_die = NULL; -+ -+ return multi; -+} -+ -+/* -+ * A variant of dwfl_nextcu() that crosses file boundaries as needed, -+ * using the state in the simple_dwfl_multi. -+ */ -+Dwarf_Die * -+simple_dwfl_nextcu(struct simple_dwfl_multi *multi) -+{ -+ Dwarf_Addr junk; -+ -+ /* -+ * Switch object files as needed (and always, the first time). -+ */ -+ -+ if (multi->i >= 0) -+ multi->last_die = dwfl_nextcu(multi->dwfl, multi->last_die, -+ &junk); -+ -+ while (multi->last_die == NULL) { -+ simple_dwfl_free(multi->dwfl); -+ if (multi->paths[++multi->i] == NULL) { -+ multi->i = -1; -+ multi->dwfl = NULL; -+ multi->last_die = NULL; -+ return NULL; -+ } -+ -+ multi->dwfl = simple_dwfl_new(multi->paths[multi->i], NULL); -+ multi->last_die = dwfl_nextcu(multi->dwfl, multi->last_die, -+ &junk); -+ } -+ return multi->last_die; -+} -+ -+/* -+ * Free a simple_dwfl_new_multi: return its contained paths so the caller can -+ * free them again. (They are not changed, so the caller can just hang on to -+ * them if preferred.) -+ */ -+char ** -+simple_dwfl_free_multi(struct simple_dwfl_multi *multi) -+{ -+ char **paths = multi->paths; -+ simple_dwfl_free(multi->dwfl); -+ free(multi); -+ return paths; -+} -+ -+/* -+ * The converse of simple_dwfl_new(). -+ */ -+void simple_dwfl_free(Dwfl *dwfl) -+{ -+ if (dwfl != NULL) { -+ dwfl_report_end(dwfl, NULL, NULL); -+ dwfl_end(dwfl); -+ } -+} -+ -+ -+/* -+ * Read a modules_thick.builtin file and translate it into a stream of -+ * arguments suitable for simple_dwfl_new_multi(). -+ */ -+ -+/* -+ * Construct a modules_thick.builtin iterator. -+ */ -+struct modules_thick_iter * -+modules_thick_iter_new(const char *modules_thick_file) -+{ -+ struct modules_thick_iter *i; -+ -+ i = calloc(1, sizeof(struct modules_thick_iter)); -+ if (i == NULL) -+ return NULL; -+ -+ i->f = fopen(modules_thick_file, "r"); -+ -+ if (i->f == NULL) { -+ fprintf(stderr, "Cannot open builtin module file %s: %s\n", -+ modules_thick_file, strerror(errno)); -+ return NULL; -+ } -+ -+ return i; -+} -+ -+/* -+ * Iterate, returning a new null-terminated array of object file names, and a -+ * new dynamically-allocated module name. (The module name passed in is freed.) -+ * -+ * The array of object file names should be freed by the caller: the strings it -+ * points to are owned by the iterator, and should not be freed. -+ */ -+ -+char ** __attribute__((__nonnull__)) -+modules_thick_iter_next(struct modules_thick_iter *i, char **module_name) -+{ -+ size_t npaths = 1; -+ char **module_paths; -+ char *last_slash; -+ char *last_dot; -+ char *trailing_linefeed; -+ char *object_name = i->line; -+ char *dash; -+ int composite = 0; -+ -+ /* -+ * Read in all module entries, computing the suffixless, pathless name -+ * of the module and building the next arrayful of object file names for -+ * return. -+ * -+ * Modules can consist of multiple files: in this case, the portion -+ * before the colon is the path to the module (as before): the portion -+ * after the colon is a space-separated list of files that should be * -+ * considered part of this module. In this case, the portion before the -+ * name is an "object file" that does not actually exist: it is merged -+ * into built-in.a without ever being written out. -+ * -+ * All module names have - translated to _, to match what is done to the -+ * names of the same things when built as modules. -+ */ -+ -+ /* -+ * Reinvocation of exhausted iterator. Return NULL, once. -+ */ -+retry: -+ if (getline(&i->line, &i->line_size, i->f) < 0) { -+ if (ferror(i->f)) { -+ fprintf(stderr, "Error reading from modules_thick file:" -+ " %s\n", strerror(errno)); -+ exit(1); -+ } -+ rewind(i->f); -+ return NULL; -+ } -+ -+ if (i->line[0] == '\0') -+ goto retry; -+ -+ /* -+ * Slice the line in two at the colon, if any. If there is anything -+ * past the ': ', this is a composite module. (We allow for no colon -+ * for robustness, even though one should always be present.) -+ */ -+ if (strchr(i->line, ':') != NULL) { -+ char *name_start; -+ -+ object_name = strchr(i->line, ':'); -+ *object_name = '\0'; -+ object_name++; -+ name_start = object_name + strspn(object_name, " \n"); -+ if (*name_start != '\0') { -+ composite = 1; -+ object_name = name_start; -+ } -+ } -+ -+ /* -+ * Figure out the module name. -+ */ -+ last_slash = strrchr(i->line, '/'); -+ last_slash = (!last_slash) ? i->line : -+ last_slash + 1; -+ free(*module_name); -+ *module_name = strdup(last_slash); -+ dash = *module_name; -+ -+ while (dash != NULL) { -+ dash = strchr(dash, '-'); -+ if (dash != NULL) -+ *dash = '_'; -+ } -+ -+ last_dot = strrchr(*module_name, '.'); -+ if (last_dot != NULL) -+ *last_dot = '\0'; -+ -+ trailing_linefeed = strchr(object_name, '\n'); -+ if (trailing_linefeed != NULL) -+ *trailing_linefeed = '\0'; -+ -+ /* -+ * Multifile separator? Object file names explicitly stated: -+ * slice them up and shuffle them in. -+ * -+ * The array size may be an overestimate if any object file -+ * names start or end with spaces (very unlikely) but cannot be -+ * an underestimate. (Check for it anyway.) -+ */ -+ if (composite) { -+ char *one_object; -+ -+ for (npaths = 0, one_object = object_name; -+ one_object != NULL; -+ npaths++, one_object = strchr(one_object + 1, ' ')); -+ } -+ -+ module_paths = malloc((npaths + 1) * sizeof(char *)); -+ if (!module_paths) { -+ fprintf(stderr, "%s: out of memory on module %s\n", __func__, -+ *module_name); -+ exit(1); -+ } -+ -+ if (composite) { -+ char *one_object; -+ size_t i = 0; -+ -+ while ((one_object = strsep(&object_name, " ")) != NULL) { -+ if (i >= npaths) { -+ fprintf(stderr, "%s: num_objs overflow on module " -+ "%s: this is a bug.\n", __func__, -+ *module_name); -+ exit(1); -+ } -+ -+ module_paths[i++] = one_object; -+ } -+ } else -+ module_paths[0] = i->line; /* untransformed module name */ -+ -+ module_paths[npaths] = NULL; -+ -+ return module_paths; -+} -+ -+/* -+ * Free an iterator. Can be called while iteration is underway, so even -+ * state that is freed at the end of iteration must be freed here too. -+ */ -+void -+modules_thick_iter_free(struct modules_thick_iter *i) -+{ -+ if (i == NULL) -+ return; -+ fclose(i->f); -+ free(i->line); -+ free(i); -+} -diff --git a/scripts/eu_simple.h b/scripts/eu_simple.h -new file mode 100644 -index 000000000000..8ef9f9655077 ---- /dev/null -+++ b/scripts/eu_simple.h -@@ -0,0 +1,91 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Simplifying wrappers for functions in elfutils, and functions to -+ * feed them data. -+ * -+ * (C) 2014, 2017 Oracle, Inc. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#ifndef _LINUX_EU_SIMPLE_H -+#define _LINUX_EU_SIMPLE_H -+ -+#include <stdio.h> -+#include <stddef.h> -+#include <elfutils/libdwfl.h> -+ -+/* -+ * Iteration state for simple_dwfl_new_multi(). -+ */ -+struct simple_dwfl_multi { -+ char **paths; -+ ssize_t i; -+ Dwfl *dwfl; -+ Dwarf_Die *last_die; -+}; -+ -+/* -+ * Wrap up dwfl_new() complexities. -+ */ -+Dwfl *simple_dwfl_new(const char *file_name, Dwfl_Module **module); -+ -+/* -+ * A variant of simple_dwfl_new() that iterates over multiple object files. -+ * (Used for thin archives.) -+ * -+ * Takes ownership of the paths, until free. -+ */ -+struct simple_dwfl_multi *simple_dwfl_new_multi(char **paths); -+ -+/* -+ * A variant of dwfl_nextcu() that crosses file boundaries as needed, -+ * using the state in the simple_dwfl_multi. -+ */ -+Dwarf_Die *simple_dwfl_nextcu(struct simple_dwfl_multi *multi); -+ -+/* -+ * Free a simple_dwfl_new_multi: return its contained paths so the caller -+ * free them again. (They are not changed, so the caller can just hang on to -+ * them if preferred.) -+ */ -+char **simple_dwfl_free_multi(struct simple_dwfl_multi *multi); -+ -+/* -+ * The converse of simple_dwfl_new(). -+ */ -+void simple_dwfl_free(Dwfl *dwfl); -+ -+/* -+ * modules_thick.builtin iteration state. -+ */ -+struct modules_thick_iter { -+ FILE *f; -+ char *line; -+ size_t line_size; -+}; -+ -+/* -+ * Construct a modules_thick.builtin iterator. -+ */ -+struct modules_thick_iter * -+modules_thick_iter_new(const char *modules_thick_file); -+ -+/* -+ * Iterate, returning a new null-terminated array of object file names, and a -+ * new dynamically-allocated module name. (The module name passed in is freed.) -+ * -+ * The array of object file names should be freed by the caller: the strings it -+ * points to are owned by the iterator, and should not be freed. -+ */ -+ -+char ** __attribute__((__nonnull__)) -+modules_thick_iter_next(struct modules_thick_iter *i, char **module_name); -+ -+void -+modules_thick_iter_free(struct modules_thick_iter *i); -+ -+#endif -diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c -index a39d93e3c6ae..12445a834698 100644 ---- a/scripts/kconfig/confdata.c -+++ b/scripts/kconfig/confdata.c -@@ -710,6 +710,25 @@ static struct conf_printer header_printer_cb = - .print_comment = header_print_comment, - }; - -+/* -+ * Tristate printer -+ * -+ * This printer is used when generating the `include/config/tristate.conf' file. -+ */ -+static void -+tristate_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg) -+{ -+ -+ if (sym->type == S_TRISTATE && *value != 'n') -+ fprintf(fp, "%s%s=%c\n", CONFIG_, sym->name, (char)toupper(*value)); -+} -+ -+static struct conf_printer tristate_printer_cb = -+{ -+ .print_symbol = tristate_print_symbol, -+ .print_comment = kconfig_print_comment, -+}; -+ - static void conf_write_symbol(FILE *fp, struct symbol *sym, - struct conf_printer *printer, void *printer_arg) - { -@@ -1043,7 +1062,7 @@ int conf_write_autoconf(int overwrite) - struct symbol *sym; - const char *name; - const char *autoconf_name = conf_get_autoconfig_name(); -- FILE *out, *out_h; -+ FILE *out, *tristate, *out_h; - int i; - - if (!overwrite && is_present(autoconf_name)) -@@ -1058,6 +1077,13 @@ int conf_write_autoconf(int overwrite) - if (!out) - return 1; - -+ tristate = fopen(".tmpconfig_tristate", "w"); -+ if (!tristate) { -+ fclose(out); -+ fclose(tristate); -+ return 1; -+ } -+ - out_h = fopen(".tmpconfig.h", "w"); - if (!out_h) { - fclose(out); -@@ -1065,6 +1091,7 @@ int conf_write_autoconf(int overwrite) - } - - conf_write_heading(out, &kconfig_printer_cb, NULL); -+ conf_write_heading(tristate, &tristate_printer_cb, NULL); - conf_write_heading(out_h, &header_printer_cb, NULL); - - for_all_symbols(i, sym) { -@@ -1072,11 +1099,13 @@ int conf_write_autoconf(int overwrite) - if (!(sym->flags & SYMBOL_WRITE) || !sym->name) - continue; - -- /* write symbols to auto.conf and autoconf.h */ -+ /* write symbols to auto.conf, tristate and header files */ - conf_write_symbol(out, sym, &kconfig_printer_cb, (void *)1); -+ conf_write_symbol(tristate, sym, &tristate_printer_cb, (void *)1); - conf_write_symbol(out_h, sym, &header_printer_cb, NULL); - } - fclose(out); -+ fclose(tristate); - fclose(out_h); - - name = getenv("KCONFIG_AUTOHEADER"); -@@ -1087,6 +1116,14 @@ int conf_write_autoconf(int overwrite) - if (rename(".tmpconfig.h", name)) - return 1; - -+ name = getenv("KCONFIG_TRISTATE"); -+ if (!name) -+ name = "include/config/tristate.conf"; -+ if (make_parent_dir(name)) -+ return 1; -+ if (rename(".tmpconfig_tristate", name)) -+ return 1; -+ - if (make_parent_dir(autoconf_name)) - return 1; - /* -diff --git a/scripts/move-if-change b/scripts/move-if-change -new file mode 100755 -index 000000000000..eb745af5d972 ---- /dev/null -+++ b/scripts/move-if-change -@@ -0,0 +1,8 @@ -+#!/bin/sh -+# SPDX-License-Identifier: GPL-2.0+ -+ -+if test -r "$2" && cmp -s "$1" "$2"; then -+ rm -f "$1" -+else -+ mv -f "$1" "$2" -+fi -diff --git a/scripts/package/mkspec b/scripts/package/mkspec -index 7c477ca7dc98..e9ff22c6fb4c 100755 ---- a/scripts/package/mkspec -+++ b/scripts/package/mkspec -@@ -27,6 +27,13 @@ if grep -q CONFIG_DRM=y .config; then - PROVIDES=kernel-drm - fi - -+# set CTF when configured -+if grep -q CONFIG_CTF=y .config; then -+ C= -+else -+ C=DEL -+fi -+ - PROVIDES="$PROVIDES kernel-$KERNELRELEASE" - __KERNELRELEASE=$(echo $KERNELRELEASE | sed -e "s/-/_/g") - EXCLUDES="$RCS_TAR_IGNORE --exclude=*vmlinux* --exclude=*.mod \ -@@ -38,6 +45,7 @@ EXCLUDES="$RCS_TAR_IGNORE --exclude=*vmlinux* --exclude=*.mod \ - # Labels: - # $S: this line is enabled only when building source package - # $M: this line is enabled only when CONFIG_MODULES is enabled -+# $C: this line is enabled only when CONFIG_CTF is enabled - sed -e '/^DEL/d' -e 's/^\t*//' <<EOF - Name: kernel - Summary: The Linux Kernel -@@ -48,6 +56,8 @@ sed -e '/^DEL/d' -e 's/^\t*//' <<EOF - Vendor: The Linux Community - URL: https://www.kernel.org - $S Source: kernel-$__KERNELRELEASE.tar.gz -+$C BuildRequires: libdtrace-ctf >= 0.5.0 -+$C BuildRequires: libdtrace-ctf-devel >= 0.5.0 - Provides: $PROVIDES - %define __spec_install_post /usr/lib/rpm/brp-compress || : - %define debug_package %{nil} -@@ -74,12 +84,14 @@ $S$M AutoReqProv: no - $S$M %description -n kernel-devel - $S$M This package provides kernel headers and makefiles sufficient to build modules - $S$M against the $__KERNELRELEASE kernel package. -+$C Requires: libdtrace-ctf >= 0.5.0 - $S$M - $S %prep - $S %setup -q - $S - $S %build - $S $MAKE %{?_smp_mflags} KBUILD_BUILD_VERSION=%{release} -+$S$C $MAKE %{?_smp_mflags} ctf - $S - %install - mkdir -p %{buildroot}/boot --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/dtrace-patches/0002-kallsyms-introduce-new-proc-kallmodsyms-including-bu.patch b/sys-kernel/cairn-sources/files/5.10.13/dtrace-patches/0002-kallsyms-introduce-new-proc-kallmodsyms-including-bu.patch deleted file mode 100644 index 63777d375446..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/dtrace-patches/0002-kallsyms-introduce-new-proc-kallmodsyms-including-bu.patch +++ /dev/null @@ -1,1050 +0,0 @@ -From 6ded42dd15783a073c9a15ad4abae87bcf234c40 Mon Sep 17 00:00:00 2001 -From: Nick Alcock <nick.alcock@oracle.com> -Date: Wed, 14 Nov 2018 20:09:28 +0000 -Subject: [PATCH 02/19] kallsyms: introduce new /proc/kallmodsyms including - builtin modules too - -/proc/kallsyms is very useful for tracers and other tools that need to -map kernel symbols to addresses (sinful though it is to export such -addresses to userspace). However, for some uses it does not suffice. -We would like to be able to establish a mapping between module name and -kernel symbol that only changes when the kernel source code is changed: -if the kernel is recompiled so that some module becomes built in, it is -a desirable property for portability of tracing scripts that can include -module names if the name of this module does not change. - -i.e., as with the previous dwarf2ctf commit, we would like to report -e.g. ext4 symbols as residing in [ext4] even if ext4 happens to be built -into the kernel: it is enough that it *could* be built as a module. - -We use machinery shared with dwarf2ctf (in eu_simple.c) in conjunction -with a link map to compute the mapping from the address ranges -associated with built-in object files in vmlinux.o to module names, then -drop a list of these modules and pointers into that list into new -kallsyms sections (kallsyms_modules and kallsyms_symbol_modules). - -We also need symbol sizes to determine whether a given probe hit is -within a symbol or outside it (possibly miles outside it in a gap -between symbols). Adding that is much simpler, with only one new -section, kallsyms_sizes. - -The resulting file looks like this: - -ffffffff8b013d20 409 t pt_buffer_setup_aux -ffffffff8b014130 11f T intel_pt_interrupt -ffffffff8b014250 2d T cpu_emergency_stop_pt -ffffffff8b014280 13a t rapl_pmu_event_init [intel_rapl_perf] -ffffffff8b0143c0 bb t rapl_event_update [intel_rapl_perf] -ffffffff8b014480 10 t rapl_pmu_event_read [intel_rapl_perf] -ffffffff8b014490 a3 t rapl_cpu_offline [intel_rapl_perf] -ffffffff8b014540 24 t __rapl_event_show [intel_rapl_perf] -ffffffff8b014570 f2 t rapl_pmu_event_stop [intel_rapl_perf] - -This is emitted even if intel_rapl_perf is built into the kernel. - -As with /proc/kallsyms, non-root usage produces addresses that are -all-zero. (I am amenable to producing all-zero sizes, too, but without -the addresses this seems like pure paranoia.) - -Programs that consume /proc/kallmodsyms should note that unlike -/proc/kallsyms, kernel symbols for built-in modules may appear -interspersed with other symbols that are part of different modules or -part of no module at all. - -Signed-off-by: Nick Alcock <nick.alcock@oracle.com> -Signed-off-by: Kris Van Hees <kris.van.hees@oracle.com> -Signed-off-by: Tomas Jedlicka <tomas.jedlicka@oracle.com> -Signed-off-by: Eugene Loh <eugene.loh@oracle.com> -Signed-off-by: David Mc Lean <david.mclean@oracle.com> -Signed-off-by: Vincent Lim <vincent.lim@oracle.com> ---- - Makefile | 2 +- - include/linux/kallsyms.h | 21 +++ - include/linux/module.h | 7 +- - init/Kconfig | 10 ++ - kernel/kallsyms.c | 163 +++++++++++++-------- - kernel/module.c | 4 +- - scripts/Makefile | 10 ++ - scripts/kallsyms.c | 301 +++++++++++++++++++++++++++++++++++++-- - scripts/link-vmlinux.sh | 22 ++- - 9 files changed, 466 insertions(+), 74 deletions(-) - -diff --git a/Makefile b/Makefile -index e94e5bfc9c4f..c21d2a09c9ca 100644 ---- a/Makefile -+++ b/Makefile -@@ -1406,7 +1406,7 @@ modules.order: $(subdir-modorder) FORCE - - targets += modules.order - --ifneq (CONFIG_CTF@,'@') -+ifneq (CONFIG_CTF@CONFIG_KALLMODSYMS,'@') - - # We need to force everything to be built, since we need the .o files below. - KBUILD_BUILTIN := 1 -diff --git a/include/linux/kallsyms.h b/include/linux/kallsyms.h -index 481273f0c72d..1246b75f5c57 100644 ---- a/include/linux/kallsyms.h -+++ b/include/linux/kallsyms.h -@@ -8,6 +8,7 @@ - - #include <linux/errno.h> - #include <linux/kernel.h> -+#include <linux/module.h> - #include <linux/stddef.h> - #include <linux/mm.h> - #include <linux/module.h> -@@ -72,6 +73,24 @@ static inline void *dereference_symbol_descriptor(void *ptr) - } - - #ifdef CONFIG_KALLSYMS -+/* To avoid using get_symbol_offset for every symbol, we carry prefix along. */ -+struct kallsym_iter { -+ loff_t pos; -+ loff_t pos_arch_end; -+ loff_t pos_mod_end; -+ loff_t pos_ftrace_mod_end; -+ loff_t pos_bpf_end; -+ unsigned long value; -+ unsigned int nameoff; /* If iterating in core kernel symbols. */ -+ unsigned long size; -+ char type; -+ char name[KSYM_NAME_LEN]; -+ char module_name[MODULE_NAME_LEN]; -+ int builtin_module; -+ int exported; -+ int show_value; -+}; -+ - /* Lookup the address for a symbol. Returns 0 if not found. */ - unsigned long kallsyms_lookup_name(const char *name); - -@@ -101,6 +120,8 @@ int lookup_symbol_attrs(unsigned long addr, unsigned long *size, unsigned long * - /* How and when do we show kallsyms values? */ - extern bool kallsyms_show_value(const struct cred *cred); - -+extern void kallsyms_iter_reset(struct kallsym_iter *, loff_t); -+extern int kallsyms_iter_update(struct kallsym_iter *, loff_t); - #else /* !CONFIG_KALLSYMS */ - - static inline unsigned long kallsyms_lookup_name(const char *name) -diff --git a/include/linux/module.h b/include/linux/module.h -index 6264617bab4d..d44fe50d7c7f 100644 ---- a/include/linux/module.h -+++ b/include/linux/module.h -@@ -599,7 +599,8 @@ struct symsearch { - /* Returns 0 and fills in value, defined and namebuf, or -ERANGE if - symnum out of range. */ - int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type, -- char *name, char *module_name, int *exported); -+ char *name, char *module_name, unsigned long *size, -+ int *exported); - - /* Look for this name: can be of form module:name. */ - unsigned long module_kallsyms_lookup_name(const char *name); -@@ -780,8 +781,8 @@ static inline int lookup_module_symbol_attrs(unsigned long addr, unsigned long * - } - - static inline int module_get_kallsym(unsigned int symnum, unsigned long *value, -- char *type, char *name, -- char *module_name, int *exported) -+ char *type, char *name, char *module_name, -+ unsigned long *size, int *exported) - { - return -ERANGE; - } -diff --git a/init/Kconfig b/init/Kconfig -index 0872a5a2e759..05d377ccc0e0 100644 ---- a/init/Kconfig -+++ b/init/Kconfig -@@ -1472,6 +1472,16 @@ config POSIX_TIMERS - - If unsure say y. - -+config KALLMODSYMS -+ default y -+ bool "Enable support for /proc/kallmodsyms" if EXPERT -+ depends on KALLSYMS -+ help -+ This option enables the /proc/kallmodsyms file, which maps symbols -+ to addresses and their associated modules. This support requires -+ a fairly recent elfutils: 0.152 -- 0.172 have been tested. -+ elfutils before 0.142 will definitely not work. -+ - config PRINTK - default y - bool "Enable support for printk" if EXPERT -diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c -index fe9de067771c..7371f8f9cf74 100644 ---- a/kernel/kallsyms.c -+++ b/kernel/kallsyms.c -@@ -33,6 +33,7 @@ - */ - extern const unsigned long kallsyms_addresses[] __weak; - extern const int kallsyms_offsets[] __weak; -+extern const unsigned long kallsyms_sizes[] __weak; - extern const u8 kallsyms_names[] __weak; - - /* -@@ -47,6 +48,8 @@ __section(".rodata") __attribute__((weak)); - - extern const char kallsyms_token_table[] __weak; - extern const u16 kallsyms_token_index[] __weak; -+extern const char kallsyms_modules[] __weak; -+extern const u32 kallsyms_symbol_modules[] __weak; - - extern const unsigned int kallsyms_markers[] __weak; - -@@ -195,12 +198,24 @@ int kallsyms_on_each_symbol(int (*fn)(void *, const char *, struct module *, - return module_kallsyms_on_each_symbol(fn, data); - } - -+/* -+ * The caller passes in an address, and we return an index to the symbol -- -+ * potentially also size and offset information. -+ * But an address might map to multiple symbols because: -+ * - some symbols might have zero size -+ * - some symbols might be aliases of one another -+ * - some symbols might span (encompass) others -+ * The symbols should already be ordered so that, for a particular address, -+ * we first have the zero-size ones, then the biggest, then the smallest. -+ * So we find the index by: -+ * - finding the last symbol with the target address -+ * - backing the index up so long as both the address and size are unchanged -+ */ - static unsigned long get_symbol_pos(unsigned long addr, - unsigned long *symbolsize, - unsigned long *offset) - { -- unsigned long symbol_start = 0, symbol_end = 0; -- unsigned long i, low, high, mid; -+ unsigned long low, high, mid; - - /* This kernel should never had been booted. */ - if (!IS_ENABLED(CONFIG_KALLSYMS_BASE_RELATIVE)) -@@ -221,36 +236,17 @@ static unsigned long get_symbol_pos(unsigned long addr, - } - - /* -- * Search for the first aliased symbol. Aliased -- * symbols are symbols with the same address. -+ * Search for the first aliased symbol. - */ -- while (low && kallsyms_sym_address(low-1) == kallsyms_sym_address(low)) -+ while (low -+ && kallsyms_sym_address(low-1) == kallsyms_sym_address(low) -+ && kallsyms_sizes[low-1] == kallsyms_sizes[low]) - --low; - -- symbol_start = kallsyms_sym_address(low); -- -- /* Search for next non-aliased symbol. */ -- for (i = low + 1; i < kallsyms_num_syms; i++) { -- if (kallsyms_sym_address(i) > symbol_start) { -- symbol_end = kallsyms_sym_address(i); -- break; -- } -- } -- -- /* If we found no next symbol, we use the end of the section. */ -- if (!symbol_end) { -- if (is_kernel_inittext(addr)) -- symbol_end = (unsigned long)_einittext; -- else if (IS_ENABLED(CONFIG_KALLSYMS_ALL)) -- symbol_end = (unsigned long)_end; -- else -- symbol_end = (unsigned long)_etext; -- } -- - if (symbolsize) -- *symbolsize = symbol_end - symbol_start; -+ *symbolsize = kallsyms_sizes[low]; - if (offset) -- *offset = addr - symbol_start; -+ *offset = addr - kallsyms_sym_address(low); - - return low; - } -@@ -270,6 +266,7 @@ int kallsyms_lookup_size_offset(unsigned long addr, unsigned long *symbolsize, - return !!module_address_lookup(addr, symbolsize, offset, NULL, namebuf) || - !!__bpf_address_lookup(addr, symbolsize, offset, namebuf); - } -+EXPORT_SYMBOL_GPL(kallsyms_lookup_size_offset); - - /* - * Lookup an address -@@ -432,22 +429,6 @@ int sprint_backtrace(char *buffer, unsigned long address) - return __sprint_symbol(buffer, address, -1, 1); - } - --/* To avoid using get_symbol_offset for every symbol, we carry prefix along. */ --struct kallsym_iter { -- loff_t pos; -- loff_t pos_arch_end; -- loff_t pos_mod_end; -- loff_t pos_ftrace_mod_end; -- loff_t pos_bpf_end; -- unsigned long value; -- unsigned int nameoff; /* If iterating in core kernel symbols. */ -- char type; -- char name[KSYM_NAME_LEN]; -- char module_name[MODULE_NAME_LEN]; -- int exported; -- int show_value; --}; -- - int __weak arch_get_kallsym(unsigned int symnum, unsigned long *value, - char *type, char *name) - { -@@ -473,7 +454,9 @@ static int get_ksymbol_mod(struct kallsym_iter *iter) - int ret = module_get_kallsym(iter->pos - iter->pos_arch_end, - &iter->value, &iter->type, - iter->name, iter->module_name, -- &iter->exported); -+ &iter->size, &iter->exported); -+ iter->builtin_module = 0; -+ - if (ret < 0) { - iter->pos_mod_end = iter->pos; - return 0; -@@ -536,10 +519,22 @@ static int get_ksymbol_kprobe(struct kallsym_iter *iter) - static unsigned long get_ksymbol_core(struct kallsym_iter *iter) - { - unsigned off = iter->nameoff; -+ u32 mod_index = 0; -+ -+ if (kallsyms_symbol_modules) -+ mod_index = kallsyms_symbol_modules[iter->pos]; - -- iter->module_name[0] = '\0'; -+ if (mod_index == 0 || kallsyms_modules == NULL) { -+ iter->module_name[0] = '\0'; -+ iter->builtin_module = 0; -+ } else { -+ strcpy(iter->module_name, &kallsyms_modules[mod_index]); -+ iter->builtin_module = 1; -+ } -+ iter->exported = 0; - iter->value = kallsyms_sym_address(iter->pos); - -+ iter->size = kallsyms_sizes[iter->pos]; - iter->type = kallsyms_get_symbol_type(off); - - off = kallsyms_expand_symbol(off, iter->name, ARRAY_SIZE(iter->name)); -@@ -547,7 +542,7 @@ static unsigned long get_ksymbol_core(struct kallsym_iter *iter) - return off - iter->nameoff; - } - --static void reset_iter(struct kallsym_iter *iter, loff_t new_pos) -+void kallsyms_iter_reset(struct kallsym_iter *iter, loff_t new_pos) - { - iter->name[0] = '\0'; - iter->nameoff = get_symbol_offset(new_pos); -@@ -559,6 +554,7 @@ static void reset_iter(struct kallsym_iter *iter, loff_t new_pos) - iter->pos_bpf_end = 0; - } - } -+EXPORT_SYMBOL_GPL(kallsyms_iter_reset); - - /* - * The end position (last + 1) of each additional kallsyms section is recorded -@@ -589,7 +585,7 @@ static int update_iter_mod(struct kallsym_iter *iter, loff_t pos) - } - - /* Returns false if pos at or past end of file. */ --static int update_iter(struct kallsym_iter *iter, loff_t pos) -+int kallsyms_iter_update(struct kallsym_iter *iter, loff_t pos) - { - /* Module symbols can be accessed randomly. */ - if (pos >= kallsyms_num_syms) -@@ -597,26 +593,27 @@ static int update_iter(struct kallsym_iter *iter, loff_t pos) - - /* If we're not on the desired position, reset to new position. */ - if (pos != iter->pos) -- reset_iter(iter, pos); -+ kallsyms_iter_reset(iter, pos); - - iter->nameoff += get_ksymbol_core(iter); - iter->pos++; - - return 1; - } -+EXPORT_SYMBOL_GPL(kallsyms_iter_update); - - static void *s_next(struct seq_file *m, void *p, loff_t *pos) - { - (*pos)++; - -- if (!update_iter(m->private, *pos)) -+ if (!kallsyms_iter_update(m->private, *pos)) - return NULL; - return p; - } - - static void *s_start(struct seq_file *m, loff_t *pos) - { -- if (!update_iter(m->private, *pos)) -+ if (!kallsyms_iter_update(m->private, *pos)) - return NULL; - return m->private; - } -@@ -625,7 +622,7 @@ static void s_stop(struct seq_file *m, void *p) - { - } - --static int s_show(struct seq_file *m, void *p) -+static int s_show_internal(struct seq_file *m, void *p, int builtin_modules) - { - void *value; - struct kallsym_iter *iter = m->private; -@@ -636,7 +633,9 @@ static int s_show(struct seq_file *m, void *p) - - value = iter->show_value ? (void *)iter->value : NULL; - -- if (iter->module_name[0]) { -+ if ((iter->builtin_module == 0 && iter->module_name[0]) || -+ (iter->builtin_module != 0 && iter->module_name[0] && -+ builtin_modules != 0)) { - char type; - - /* -@@ -645,14 +644,32 @@ static int s_show(struct seq_file *m, void *p) - */ - type = iter->exported ? toupper(iter->type) : - tolower(iter->type); -- seq_printf(m, "%px %c %s\t[%s]\n", value, -- type, iter->name, iter->module_name); -- } else -+ if (builtin_modules) -+ seq_printf(m, "%px %lx %c %s\t[%s]\n", value, -+ iter->size, type, iter->name, -+ iter->module_name); -+ else -+ seq_printf(m, "%px %c %s\t[%s]\n", value, -+ type, iter->name, iter->module_name); -+ } else if (builtin_modules) -+ seq_printf(m, "%px %lx %c %s\n", value, iter->size, -+ iter->type, iter->name); -+ else - seq_printf(m, "%px %c %s\n", value, - iter->type, iter->name); - return 0; - } - -+static int s_show(struct seq_file *m, void *p) -+{ -+ return s_show_internal(m, p, 0); -+} -+ -+static int s_mod_show(struct seq_file *m, void *p) -+{ -+ return s_show_internal(m, p, 1); -+} -+ - static const struct seq_operations kallsyms_op = { - .start = s_start, - .next = s_next, -@@ -695,7 +712,15 @@ bool kallsyms_show_value(const struct cred *cred) - } - } - --static int kallsyms_open(struct inode *inode, struct file *file) -+static const struct seq_operations kallmodsyms_op = { -+ .start = s_start, -+ .next = s_next, -+ .stop = s_stop, -+ .show = s_mod_show -+}; -+ -+static int kallsyms_open_internal(struct inode *inode, struct file *file, -+ const struct seq_operations *ops) - { - /* - * We keep iterator in m->private, since normal case is to -@@ -703,10 +728,10 @@ static int kallsyms_open(struct inode *inode, struct file *file) - * using get_symbol_offset for every symbol. - */ - struct kallsym_iter *iter; -- iter = __seq_open_private(file, &kallsyms_op, sizeof(*iter)); -+ iter = __seq_open_private(file, ops, sizeof(*iter)); - if (!iter) - return -ENOMEM; -- reset_iter(iter, 0); -+ kallsyms_iter_reset(iter, 0); - - /* - * Instead of checking this on every s_show() call, cache -@@ -716,6 +741,16 @@ static int kallsyms_open(struct inode *inode, struct file *file) - return 0; - } - -+static int kallsyms_open(struct inode *inode, struct file *file) -+{ -+ return kallsyms_open_internal(inode, file, &kallsyms_op); -+} -+ -+static int kallmodsyms_open(struct inode *inode, struct file *file) -+{ -+ return kallsyms_open_internal(inode, file, &kallmodsyms_op); -+} -+ - #ifdef CONFIG_KGDB_KDB - const char *kdb_walk_kallsyms(loff_t *pos) - { -@@ -723,10 +758,10 @@ const char *kdb_walk_kallsyms(loff_t *pos) - if (*pos == 0) { - memset(&kdb_walk_kallsyms_iter, 0, - sizeof(kdb_walk_kallsyms_iter)); -- reset_iter(&kdb_walk_kallsyms_iter, 0); -+ kallsyms_iter_reset(&kdb_walk_kallsyms_iter, 0); - } - while (1) { -- if (!update_iter(&kdb_walk_kallsyms_iter, *pos)) -+ if (!kallsyms_iter_update(&kdb_walk_kallsyms_iter, *pos)) - return NULL; - ++*pos; - /* Some debugging symbols have no name. Ignore them. */ -@@ -743,9 +778,17 @@ static const struct proc_ops kallsyms_proc_ops = { - .proc_release = seq_release_private, - }; - -+static const struct proc_ops kallmodsyms_proc_ops = { -+ .proc_open = kallmodsyms_open, -+ .proc_read = seq_read, -+ .proc_lseek = seq_lseek, -+ .proc_release = seq_release_private, -+}; -+ - static int __init kallsyms_init(void) - { - proc_create("kallsyms", 0444, NULL, &kallsyms_proc_ops); -+ proc_create("kallmodsyms", 0444, NULL, &kallmodsyms_proc_ops); - return 0; - } - device_initcall(kallsyms_init); -diff --git a/kernel/module.c b/kernel/module.c -index e20499309b2a..9e471dbedc83 100644 ---- a/kernel/module.c -+++ b/kernel/module.c -@@ -4241,7 +4241,8 @@ int lookup_module_symbol_attrs(unsigned long addr, unsigned long *size, - } - - int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type, -- char *name, char *module_name, int *exported) -+ char *name, char *module_name, unsigned long *size, -+ int *exported) - { - struct module *mod; - -@@ -4260,6 +4261,7 @@ int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type, - strlcpy(name, kallsyms_symbol_name(kallsyms, symnum), KSYM_NAME_LEN); - strlcpy(module_name, mod->name, MODULE_NAME_LEN); - *exported = is_exported(name, *value, mod); -+ *size = kallsyms->symtab[symnum].st_size; - preempt_enable(); - return 0; - } -diff --git a/scripts/Makefile b/scripts/Makefile -index 041bcf48cc5c..efa1ff4dff95 100644 ---- a/scripts/Makefile -+++ b/scripts/Makefile -@@ -12,6 +12,16 @@ hostprogs-always-$(CONFIG_MODULE_SIG_FORMAT) += sign-file - hostprogs-always-$(CONFIG_SYSTEM_TRUSTED_KEYRING) += extract-cert - hostprogs-always-$(CONFIG_SYSTEM_EXTRA_CERTIFICATE) += insert-sys-cert - -+kallsyms-objs := kallsyms.o -+ -+ifeq ($(CONFIG_KALLMODSYMS),y) -+kallsyms-objs += eu_simple.o -+ -+HOSTCFLAGS_eu_simple.o := -I$(srctree)/scripts -+HOSTCFLAGS_kallsyms.o := $(shell pkg-config --cflags glib-2.0) -I$(srctree)/scripts -+HOSTLDLIBS_kallsyms := $(shell pkg-config --libs glib-2.0) -ldw -+endif -+ - HOSTCFLAGS_sorttable.o = -I$(srctree)/tools/include - HOSTCFLAGS_asn1_compiler.o = -I$(srctree)/include - HOSTLDLIBS_sign-file = -lcrypto -diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c -index 7ecd2ccba531..884ac793bdf4 100644 ---- a/scripts/kallsyms.c -+++ b/scripts/kallsyms.c -@@ -5,7 +5,10 @@ - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * -- * Usage: nm -n vmlinux | scripts/kallsyms [--all-symbols] > symbols.S -+ * Usage: nm -n -S vmlinux | scripts/kallsyms [--all-symbols] -+ * [--symbol-prefix=<prefix char>] -+ * [--builtin=modules_thick.builtin] -+ * > symbols.S - * - * Table compression uses all the unused char codes on the symbols and - * maps these to the most used substrings (tokens). For instance, it might -@@ -18,12 +21,27 @@ - * - */ - -+#define _GNU_SOURCE 1 - #include <stdbool.h> - #include <stdio.h> - #include <stdlib.h> - #include <string.h> - #include <ctype.h> - #include <limits.h> -+#include <errno.h> -+#include <unistd.h> -+ -+#include "../include/generated/autoconf.h" -+ -+#ifdef CONFIG_KALLMODSYMS -+#include <libelf.h> -+#include <dwarf.h> -+#include <elfutils/libdwfl.h> -+#include <elfutils/libdw.h> -+#include <glib.h> -+ -+#include <eu_simple.h> -+#endif - - #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) - -@@ -31,9 +49,13 @@ - - struct sym_entry { - unsigned long long addr; -+ unsigned long long size; - unsigned int len; - unsigned int start_pos; - unsigned int percpu_absolute; -+#ifdef CONFIG_KALLMODSYMS -+ unsigned int module; -+#endif - unsigned char sym[]; - }; - -@@ -67,11 +89,33 @@ static int token_profit[0x10000]; - static unsigned char best_table[256][2]; - static unsigned char best_table_len[256]; - -+#ifdef CONFIG_KALLMODSYMS -+/* -+ * The builtin module names. The "offset" points to the name as if -+ * all builtin module names were concatenated to a single string. -+ */ -+static unsigned int builtin_module_size; /* number allocated */ -+static unsigned int builtin_module_len; /* number assigned */ -+static char **builtin_modules; /* array of module names */ -+static unsigned int *builtin_module_offsets; /* offset */ -+ -+/* -+ * An ordered list of address ranges and how they map to built-in modules. -+ */ -+struct addrmap_entry { -+ unsigned long long addr; -+ unsigned long long size; -+ unsigned int module; -+}; -+static struct addrmap_entry *addrmap; -+static int addrmap_num, addrmap_alloced; -+#endif - - static void usage(void) - { - fprintf(stderr, "Usage: kallsyms [--all-symbols] " -- "[--base-relative] < in.map > out.S\n"); -+ "[--base-relative] [--builtin=modules_thick.builtin] " -+ "< in.map > out.S\n"); - exit(1); - } - -@@ -99,6 +143,8 @@ static bool is_ignored_symbol(const char *name, char type) - "kallsyms_markers", - "kallsyms_token_table", - "kallsyms_token_index", -+ "kallsyms_symbol_modules", -+ "kallsyms_modules", - /* Exclude linker generated symbols which vary between passes */ - "_SDA_BASE_", /* ppc */ - "_SDA2_BASE_", /* ppc */ -@@ -189,6 +235,20 @@ static void check_symbol_range(const char *sym, unsigned long long addr, - } - } - -+#ifdef CONFIG_KALLMODSYMS -+static int addrmap_compare(const void *keyp, const void *rangep) -+{ -+ unsigned long long addr = *((const unsigned long long *)keyp); -+ const struct addrmap_entry *range = (const struct addrmap_entry *)rangep; -+ -+ if (addr < range->addr) -+ return -1; -+ if (addr < range->addr + range->size) -+ return 0; -+ return 1; -+} -+#endif -+ - static struct sym_entry *read_symbol(FILE *in) - { - char name[500], type; -@@ -196,9 +256,14 @@ static struct sym_entry *read_symbol(FILE *in) - unsigned int len; - struct sym_entry *sym; - int rc; -- -- rc = fscanf(in, "%llx %c %499s\n", &addr, &type, name); -- if (rc != 3) { -+ unsigned long long size; -+#ifdef CONFIG_KALLMODSYMS -+ struct addrmap_entry *range; -+ unsigned int module; -+#endif -+ -+ rc = fscanf(in, "%llx %llx %c %499s\n", &addr, &size, &type, name); -+ if (rc != 4) { - if (rc != EOF && fgets(name, 500, in) == NULL) - fprintf(stderr, "Read error or end of file.\n"); - return NULL; -@@ -220,6 +285,16 @@ static struct sym_entry *read_symbol(FILE *in) - check_symbol_range(name, addr, text_ranges, ARRAY_SIZE(text_ranges)); - check_symbol_range(name, addr, &percpu_range, 1); - -+#ifdef CONFIG_KALLMODSYMS -+ /* look up the builtin module this is part of (if any) */ -+ range = (struct addrmap_entry *) bsearch(&addr, -+ addrmap, addrmap_num, sizeof(*addrmap), &addrmap_compare); -+ if (range) -+ module = builtin_module_offsets[range->module]; -+ else -+ module = 0; -+#endif -+ - /* include the type field in the symbol name, so that it gets - * compressed together */ - -@@ -236,6 +311,10 @@ static struct sym_entry *read_symbol(FILE *in) - sym->sym[0] = type; - strcpy(sym_name(sym), name); - sym->percpu_absolute = 0; -+ sym->size = size; -+#ifdef CONFIG_KALLMODSYMS -+ sym->module = module; -+#endif - - return sym; - } -@@ -445,6 +524,11 @@ static void write_src(void) - printf("\n"); - } - -+ output_label("kallsyms_sizes"); -+ for (i = 0; i < table_cnt; i++) -+ printf("\tPTR\t%#llx\n", table[i]->size); -+ printf("\n"); -+ - output_label("kallsyms_num_syms"); - printf("\t.long\t%u\n", table_cnt); - printf("\n"); -@@ -494,8 +578,22 @@ static void write_src(void) - for (i = 0; i < 256; i++) - printf("\t.short\t%d\n", best_idx[i]); - printf("\n"); --} - -+#ifdef CONFIG_KALLMODSYMS -+ output_label("kallsyms_modules"); -+ for (i = 0; i < builtin_module_len; i++) -+ printf("\t.asciz\t\"%s\"\n", builtin_modules[i]); -+ printf("\n"); -+ -+ for (i = 0; i < builtin_module_len; i++) -+ free(builtin_modules[i]); -+ -+ output_label("kallsyms_symbol_modules"); -+ for (i = 0; i < table_cnt; i++) -+ printf("\t.int\t%d\n", table[i]->module); -+ printf("\n"); -+#endif -+} - - /* table lookup compression functions */ - -@@ -697,6 +795,18 @@ static int compare_symbols(const void *a, const void *b) - if (sa->addr < sb->addr) - return -1; - -+ /* zero-size markers before nonzero-size symbols */ -+ if (sa->size > 0 && sb->size == 0) -+ return 1; -+ if (sa->size == 0 && sb->size > 0) -+ return -1; -+ -+ /* sort by size (large size preceding symbols it encompasses) */ -+ if (sa->size < sb->size) -+ return 1; -+ if (sa->size > sb->size) -+ return -1; -+ - /* sort by "weakness" type */ - wa = (sa->sym[0] == 'w') || (sa->sym[0] == 'W'); - wb = (sb->sym[0] == 'w') || (sb->sym[0] == 'W'); -@@ -756,23 +866,198 @@ static void record_relative_base(void) - } - } - -+#ifdef CONFIG_KALLMODSYMS -+/* Built-in module list computation. */ -+ -+/* -+ * Expand the builtin modules list. -+ */ -+static void expand_builtin_modules(void) -+{ -+ builtin_module_size += 50; -+ -+ builtin_modules = realloc(builtin_modules, -+ sizeof(*builtin_modules) * -+ builtin_module_size); -+ builtin_module_offsets = realloc(builtin_module_offsets, -+ sizeof(*builtin_module_offsets) * -+ builtin_module_size); -+ -+ if (!builtin_modules || !builtin_module_offsets) { -+ fprintf(stderr, "kallsyms failure: out of memory.\n"); -+ exit(EXIT_FAILURE); -+ } -+} -+ -+/* -+ * Add a single built-in module (possibly composed of many files) to the -+ * modules list. Take the offset of the current module and return it -+ * (purely for simplicity's sake in the caller). -+ */ -+static size_t add_builtin_module(const char *module_name, char **module_paths, -+ GHashTable *obj2mod, size_t offset) -+{ -+ gpointer val = GUINT_TO_POINTER(builtin_module_len); -+ -+ /* map the module's object paths to the module offset */ -+ while (*module_paths) { -+ g_hash_table_insert(obj2mod, strdup(*module_paths), val); -+ module_paths++; -+ } -+ -+ /* add the module name */ -+ if (builtin_module_size <= builtin_module_len) -+ expand_builtin_modules(); -+ builtin_modules[builtin_module_len] = strdup(module_name); -+ builtin_module_offsets[builtin_module_len] = offset; -+ builtin_module_len++; -+ -+ return (offset + strlen(module_name) + 1); -+} -+ -+/* -+ * Read the linker map. -+ */ -+static void read_linker_map(GHashTable *obj2mod) -+{ -+ unsigned long long addr, size; -+ char obj[PATH_MAX+1]; -+ FILE *f = fopen(".tmp_vmlinux.ranges", "r"); -+ -+ if (!f) { -+ fprintf(stderr, "Cannot open '.tmp_vmlinux.ranges'.\n"); -+ exit(1); -+ } -+ -+ addrmap_num = 0; -+ addrmap_alloced = 4096; -+ addrmap = malloc(sizeof(*addrmap) * addrmap_alloced); -+ if (!addrmap) -+ goto oom; -+ -+ /* -+ * For each address range (addr,size) and object, add to addrmap -+ * the range and the built-in module to which the object maps. -+ */ -+ while (fscanf(f, "%llx %llx %s\n", &addr, &size, obj) == 3) { -+ int m = GPOINTER_TO_UINT(g_hash_table_lookup(obj2mod, obj)); -+ -+ if (addr == 0 || size == 0 || m == 0) -+ continue; -+ -+ if (addrmap_num >= addrmap_alloced) { -+ addrmap_alloced *= 2; -+ addrmap = realloc(addrmap, -+ sizeof(*addrmap) * addrmap_alloced); -+ if (!addrmap) -+ goto oom; -+ } -+ -+ addrmap[addrmap_num].addr = addr; -+ addrmap[addrmap_num].size = size; -+ addrmap[addrmap_num].module = m; -+ addrmap_num++; -+ } -+ fclose(f); -+ return; -+ -+oom: -+ fprintf(stderr, "kallsyms: out of memory\n"); -+ exit(1); -+} -+ -+/* -+ * Read the list of built-in modules. Construct: -+ * - builtin_modules: array of module names -+ * - builtin_module_offsets: array of offsets to find module names -+ * - obj2mod: mapping from each object-file path to a module index -+ * (which can be used in the arrays) -+ * Finally, read the linker map. -+ */ -+static void read_modules(const char *modules_builtin) -+{ -+ struct modules_thick_iter *i; -+ size_t offset = 0; -+ char *module_name = NULL; -+ char **module_paths; -+ GHashTable *obj2mod; -+ -+ obj2mod = g_hash_table_new_full(g_str_hash, g_str_equal, free, NULL); -+ if (!obj2mod) { -+ fprintf(stderr, "kallsyms: out of memory\n"); -+ exit(1); -+ } -+ -+ /* -+ * builtin_modules[0] is a null entry signifying a symbol that cannot be -+ * modular. -+ */ -+ builtin_module_size = 50; -+ builtin_modules = malloc(sizeof(*builtin_modules) * -+ builtin_module_size); -+ builtin_module_offsets = malloc(sizeof(*builtin_module_offsets) * -+ builtin_module_size); -+ if (!builtin_modules || !builtin_module_offsets) { -+ fprintf(stderr, "kallsyms: out of memory\n"); -+ exit(1); -+ } -+ builtin_modules[0] = strdup(""); -+ builtin_module_offsets[0] = 0; -+ builtin_module_len = 1; -+ offset++; -+ -+ /* -+ * Iterate over all modules in modules_thick.builtin and add each. -+ */ -+ i = modules_thick_iter_new(modules_builtin); -+ if (i == NULL) { -+ fprintf(stderr, "Cannot iterate over builtin modules.\n"); -+ exit(1); -+ } -+ -+ while ((module_paths = modules_thick_iter_next(i, &module_name)) != NULL) { -+ offset = add_builtin_module(module_name, module_paths, -+ obj2mod, offset); -+ free(module_paths); -+ module_paths = NULL; -+ } -+ -+ free(module_name); -+ modules_thick_iter_free(i); -+ -+ /* -+ * Read linker map. -+ */ -+ read_linker_map(obj2mod); -+ -+ g_hash_table_destroy(obj2mod); -+} -+#else -+static void read_modules(const char *unused) {} -+#endif /* CONFIG_KALLMODSYMS */ -+ - int main(int argc, char **argv) - { -- if (argc >= 2) { -+ const char *modules_builtin = "modules_thick.builtin"; -+ -+ if (argc >= 1) { - int i; - for (i = 1; i < argc; i++) { -- if(strcmp(argv[i], "--all-symbols") == 0) -+ if (strcmp(argv[i], "--all-symbols") == 0) - all_symbols = 1; - else if (strcmp(argv[i], "--absolute-percpu") == 0) - absolute_percpu = 1; - else if (strcmp(argv[i], "--base-relative") == 0) - base_relative = 1; -+ else if (strncmp(argv[i], "--builtin=", 10) == 0) -+ modules_builtin = &argv[i][10]; - else - usage(); - } - } else if (argc != 1) - usage(); - -+ read_modules(modules_builtin); - read_map(stdin); - shrink_table(); - if (absolute_percpu) -diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh -index 6eded325c837..bc533252fa3c 100755 ---- a/scripts/link-vmlinux.sh -+++ b/scripts/link-vmlinux.sh -@@ -109,6 +109,7 @@ vmlinux_link() - --start-group \ - ${KBUILD_VMLINUX_LIBS} \ - --end-group \ -+ -Map=.tmp_vmlinux.map \ - ${@}" - - ${LD} ${KBUILD_LDFLAGS} ${LDFLAGS_vmlinux} \ -@@ -122,6 +123,7 @@ vmlinux_link() - -Wl,--start-group \ - ${KBUILD_VMLINUX_LIBS} \ - -Wl,--end-group \ -+ -Wl,-Map=.tmp_vmlinux.map \ - ${@}" - - ${CC} ${CFLAGS_vmlinux} \ -@@ -174,6 +176,19 @@ kallsyms() - { - local kallsymopt; - -+ # read the linker map to identify ranges of addresses: -+ # - for each *.o file, report address, size, pathname -+ # - most such lines will have four fields -+ # - but sometimes there is a line break after the first field -+ # - start reading at "Linker script and memory map" -+ # - stop reading at ".brk" -+ ${AWK} ' -+ /\.o$/ && start==1 { print $(NF-2), $(NF-1), $NF } -+ /^Linker script and memory map/ { start = 1 } -+ /^\.brk/ { exit(0) } -+ ' .tmp_vmlinux.map | sort > .tmp_vmlinux.ranges -+ -+ # get kallsyms options - if [ -n "${CONFIG_KALLSYMS_ALL}" ]; then - kallsymopt="${kallsymopt} --all-symbols" - fi -@@ -186,8 +201,13 @@ kallsyms() - kallsymopt="${kallsymopt} --base-relative" - fi - -+ # "nm -S" does not print symbol size when size is 0 -+ # Therefore use awk to regularize the data: -+ # - when there are only three fields, add an explicit "0" -+ # - when there are already four fields, pass through as is - info KSYMS ${2} -- ${NM} -n ${1} | scripts/kallsyms ${kallsymopt} > ${2} -+ ${NM} -n -S ${1} | ${AWK} 'NF==3 {print $1, 0, $2, $3}; NF==4' | \ -+ scripts/kallsyms ${kallsymopt} > ${2} - } - - # Perform one step in kallsyms generation, including temporary linking of --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/dtrace-patches/0003-waitfd-new-syscall-implementing-waitpid-over-fds.patch b/sys-kernel/cairn-sources/files/5.10.13/dtrace-patches/0003-waitfd-new-syscall-implementing-waitpid-over-fds.patch deleted file mode 100644 index b02ead6a9736..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/dtrace-patches/0003-waitfd-new-syscall-implementing-waitpid-over-fds.patch +++ /dev/null @@ -1,809 +0,0 @@ -From 7cbd018b36da6838efe3adba191adf3acd4ef9bd Mon Sep 17 00:00:00 2001 -From: Nick Alcock <nick.alcock@oracle.com> -Date: Wed, 14 Nov 2018 20:28:51 +0000 -Subject: [PATCH 03/19] waitfd: new syscall implementing waitpid() over fds - -This syscall, originally due to Casey Dahlin but significantly modified -since, is called quite like waitid(): - - fd = waitfd(P_PID, some_pid, WEXITED | WSTOPPED, 0); - -This returns a file descriptor which becomes ready whenever waitpid() -would return, and when read() returns the return value waitpid() would -have returned. (Alternatively, you can use it as a pure indication that -waitpid() is callable without hanging, and then call waitpid()). See the -example in tools/testing/selftests/waitfd/. - -The original reason for rejection of this patch back in 2009 was that it -was redundant to waitpid()ing in a separate thread and transmitting -process information to another thread that polls: but this is only the -case for the conventional child-process use of waitpid(). Other -waitpid() uses, such as ptrace() returns, are targetted on a single -thread, so without waitfd or something like it, it is impossible to have -a thread that both accepts requests for servicing from other threads -over an fd *and* manipulates the state of a ptrace()d process in -response to those requests without ugly CPU-chewing polling (accepting -requests requires blocking in poll() or select(): handling the ptraced -process requires blocking in waitpid()). - -There is one ugliness in this patch which I would appreciate suggestions -to improve (due to me, not due to Casey, don't blame him). The poll() -machinery expects to be used with files, or things enough like files -that the wake_up key contains an indication as to whether this wakeup -corresponds to a POLLIN / POLLOUT / POLLERR event on this fd. You can -override this in your poll_queue_proc, but the poll() and epoll() queue -procs both have this interpretation. - -Unfortunately, this is not true for waitfds, which wait on the the -wait_chldexit waitqueue, whose key is a pointer to the task_struct of -the task being killed. We can't do anything with this key, but we -certainly don't want the poll machinery treating it as a bitmask and -checking it against poll events! - -So we introduce a new poll_wait() analogue, poll_wait_fixed(). This is used -for poll_wait() calls which know they must wait on waitqueues whose keys are -not a typecast representation of poll events, and passes in an extra -argument to the poll_queue_proc, which if nonzero is the event which a -wakeup on this waitqueue should be considered as equivalent to. The -poll_queue_proc can then skip adding entirely if that fixed event is not -included in the set to be caught by this poll(). - -We also add a new poll_table_entry.fixed_key. The poll_queue_proc can -record the fixed key it is passed in here, and reuse it at wakeup time to -track that a nonzero fixed key was passed in to poll_wait_fixed() and that -the key should be ignored in preference to fixed_key. - -With this in place, you can say, e.g. (as waitfd does) - - poll_wait_fixed(file, ¤t->signal->wait_chldexit, wait, - POLLIN); - -and the key passed to wakeups on the wait_chldexit waitqueue will be -ignored: the fd will always be treated as having raised POLLIN, waking -up poll()s and epoll()s that have specified that event. (Obviously, a -poll function that calls this should return the same value from the poll -function as was passed to poll_wait_fixed(), or, as usual, zero if this -was a spurious wakeup.) - -I do not like this scheme: it's sufficiently arcane that I had to go -back to my old commit messages to figure out what it was doing and -why. But I don't see another way to cause poll() to return on -appropriate activity on waitqueues that do not actually correspond to -files. (I do wonder how signalfd works. It doesn't seem to need any of -this and I don't understand why not. I would be overjoyed to remove the -whole invasive poll_wait_fixed() mess, but I'm not sure what to replace -it with.) - -Signed-off-by: Nick Alcock <nick.alcock@oracle.com> -Signed-off-by: Kris Van Hees <kris.van.hees@oracle.com> -Signed-off-by: Tomas Jedlicka <tomas.jedlicka@oracle.com> -Signed-off-by: Eugene Loh <eugene.loh@oracle.com> -Signed-off-by: David Mc Lean <david.mclean@oracle.com> -Signed-off-by: Vincent Lim <vincent.lim@oracle.com> ---- - arch/x86/entry/syscalls/syscall_32.tbl | 3 + - arch/x86/entry/syscalls/syscall_64.tbl | 3 + - drivers/vfio/virqfd.c | 3 +- - drivers/vhost/vhost.c | 2 +- - fs/Makefile | 1 + - fs/aio.c | 2 +- - fs/eventpoll.c | 22 +++- - fs/io_uring.c | 5 +- - fs/select.c | 21 +++- - fs/waitfd.c | 130 ++++++++++++++++++++++++ - include/linux/poll.h | 14 ++- - include/linux/syscalls.h | 3 + - include/uapi/asm-generic/unistd.h | 5 +- - init/Kconfig | 16 +++ - kernel/exit.c | 13 ++- - kernel/sys_ni.c | 1 + - mm/memcontrol.c | 2 +- - net/9p/trans_fd.c | 3 +- - tools/testing/selftests/waitfd/Makefile | 28 +++++ - tools/testing/selftests/waitfd/waitfd.c | 116 +++++++++++++++++++++ - virt/kvm/eventfd.c | 2 +- - 21 files changed, 376 insertions(+), 19 deletions(-) - create mode 100644 fs/waitfd.c - create mode 100644 tools/testing/selftests/waitfd/Makefile - create mode 100644 tools/testing/selftests/waitfd/waitfd.c - -diff --git a/arch/x86/entry/syscalls/syscall_32.tbl b/arch/x86/entry/syscalls/syscall_32.tbl -index 0d0667a9fbd7..5605708e4c31 100644 ---- a/arch/x86/entry/syscalls/syscall_32.tbl -+++ b/arch/x86/entry/syscalls/syscall_32.tbl -@@ -445,3 +445,6 @@ - 438 i386 pidfd_getfd sys_pidfd_getfd - 439 i386 faccessat2 sys_faccessat2 - 440 i386 process_madvise sys_process_madvise -+# This one is a temporary number, designed for no clashes. -+# Nothing but DTrace should use it. -+473 i386 waitfd sys_waitfd -diff --git a/arch/x86/entry/syscalls/syscall_64.tbl b/arch/x86/entry/syscalls/syscall_64.tbl -index 379819244b91..4f4e0585c65f 100644 ---- a/arch/x86/entry/syscalls/syscall_64.tbl -+++ b/arch/x86/entry/syscalls/syscall_64.tbl -@@ -362,6 +362,9 @@ - 438 common pidfd_getfd sys_pidfd_getfd - 439 common faccessat2 sys_faccessat2 - 440 common process_madvise sys_process_madvise -+# This one is a temporary number, designed for no clashes. -+# Nothing but DTrace should use it. -+473 common waitfd sys_waitfd - - # - # Due to a historical design error, certain syscalls are numbered differently -diff --git a/drivers/vfio/virqfd.c b/drivers/vfio/virqfd.c -index 997cb5d0a657..6bfafa889af2 100644 ---- a/drivers/vfio/virqfd.c -+++ b/drivers/vfio/virqfd.c -@@ -76,7 +76,8 @@ static int virqfd_wakeup(wait_queue_entry_t *wait, unsigned mode, int sync, void - } - - static void virqfd_ptable_queue_proc(struct file *file, -- wait_queue_head_t *wqh, poll_table *pt) -+ wait_queue_head_t *wqh, poll_table *pt, -+ unsigned long unused) - { - struct virqfd *virqfd = container_of(pt, struct virqfd, pt); - add_wait_queue(wqh, &virqfd->wait); -diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c -index a262e12c6dc2..31128cadd1b2 100644 ---- a/drivers/vhost/vhost.c -+++ b/drivers/vhost/vhost.c -@@ -152,7 +152,7 @@ static void vhost_flush_work(struct vhost_work *work) - } - - static void vhost_poll_func(struct file *file, wait_queue_head_t *wqh, -- poll_table *pt) -+ poll_table *pt, unsigned long unused) - { - struct vhost_poll *poll; - -diff --git a/fs/Makefile b/fs/Makefile -index 999d1a23f036..ad5fc1399484 100644 ---- a/fs/Makefile -+++ b/fs/Makefile -@@ -31,6 +31,7 @@ obj-$(CONFIG_SIGNALFD) += signalfd.o - obj-$(CONFIG_TIMERFD) += timerfd.o - obj-$(CONFIG_EVENTFD) += eventfd.o - obj-$(CONFIG_USERFAULTFD) += userfaultfd.o -+obj-$(CONFIG_WAITFD) += waitfd.o - obj-$(CONFIG_AIO) += aio.o - obj-$(CONFIG_IO_URING) += io_uring.o - obj-$(CONFIG_IO_WQ) += io-wq.o -diff --git a/fs/aio.c b/fs/aio.c -index 6a21d8919409..3485fe7913ef 100644 ---- a/fs/aio.c -+++ b/fs/aio.c -@@ -1718,7 +1718,7 @@ struct aio_poll_table { - - static void - aio_poll_queue_proc(struct file *file, struct wait_queue_head *head, -- struct poll_table_struct *p) -+ struct poll_table_struct *p, unsigned long fixed_event) - { - struct aio_poll_table *pt = container_of(p, struct aio_poll_table, pt); - -diff --git a/fs/eventpoll.c b/fs/eventpoll.c -index 117b1c395ae4..e3c9f4ea9ec6 100644 ---- a/fs/eventpoll.c -+++ b/fs/eventpoll.c -@@ -157,6 +157,9 @@ struct epitem { - /* Number of active wait queue attached to poll operations */ - int nwait; - -+ /* fd always raises this fixed event. */ -+ unsigned long fixed_event; -+ - /* List containing poll wait queues */ - struct list_head pwqlist; - -@@ -867,7 +870,7 @@ static int ep_eventpoll_release(struct inode *inode, struct file *file) - static __poll_t ep_read_events_proc(struct eventpoll *ep, struct list_head *head, - void *priv); - static void ep_ptable_queue_proc(struct file *file, wait_queue_head_t *whead, -- poll_table *pt); -+ poll_table *pt, unsigned long fixed_event); - - /* - * Differs from ep_eventpoll_poll() in that internal callers already have -@@ -1283,6 +1286,13 @@ static int ep_poll_callback(wait_queue_entry_t *wait, unsigned mode, int sync, v - if (!(epi->event.events & EPOLLEXCLUSIVE)) - ewake = 1; - -+ /* -+ * If this fd type has a hardwired event which should override the key -+ * (e.g. if it is waiting on a non-file waitqueue), jam it in here. -+ */ -+ if (epi->fixed_event) -+ key = (void *)epi->fixed_event; -+ - if (pollflags & POLLFREE) { - /* - * If we race with ep_remove_wait_queue() it can miss -@@ -1307,11 +1317,17 @@ static int ep_poll_callback(wait_queue_entry_t *wait, unsigned mode, int sync, v - * target file wakeup lists. - */ - static void ep_ptable_queue_proc(struct file *file, wait_queue_head_t *whead, -- poll_table *pt) -+ poll_table *pt, unsigned long fixed_event) - { - struct epitem *epi = ep_item_from_epqueue(pt); - struct eppoll_entry *pwq; - -+ if (fixed_event & !(epi->event.events & fixed_event)) -+ return; -+ -+ if (fixed_event) -+ epi->fixed_event = fixed_event; -+ - if (epi->nwait >= 0 && (pwq = kmem_cache_alloc(pwq_cache, GFP_KERNEL))) { - init_waitqueue_func_entry(&pwq->wait, ep_poll_callback); - pwq->whead = whead; -@@ -1512,6 +1528,7 @@ static int ep_insert(struct eventpoll *ep, const struct epoll_event *event, - ep_set_ffd(&epi->ffd, tfile, fd); - epi->event = *event; - epi->nwait = 0; -+ epi->fixed_event = 0; - epi->next = EP_UNACTIVE_PTR; - if (epi->event.events & EPOLLWAKEUP) { - error = ep_create_wakeup_source(epi); -@@ -2410,7 +2427,6 @@ static int __init eventpoll_init(void) - * We can have many thousands of epitems, so prevent this from - * using an extra cache line on 64-bit (and smaller) CPUs - */ -- BUILD_BUG_ON(sizeof(void *) <= 8 && sizeof(struct epitem) > 128); - - /* Allocates slab cache used to allocate "struct epitem" items */ - epi_cache = kmem_cache_create("eventpoll_epi", sizeof(struct epitem), -diff --git a/fs/io_uring.c b/fs/io_uring.c -index fd12d9327ee5..0d0162ab5301 100644 ---- a/fs/io_uring.c -+++ b/fs/io_uring.c -@@ -5109,7 +5109,8 @@ static void __io_queue_proc(struct io_poll_iocb *poll, struct io_poll_table *pt, - } - - static void io_async_queue_proc(struct file *file, struct wait_queue_head *head, -- struct poll_table_struct *p) -+ struct poll_table_struct *p, -+ unsigned long fixed_event) - { - struct io_poll_table *pt = container_of(p, struct io_poll_table, pt); - struct async_poll *apoll = pt->req->apoll; -@@ -5405,7 +5406,7 @@ static int io_poll_wake(struct wait_queue_entry *wait, unsigned mode, int sync, - } - - static void io_poll_queue_proc(struct file *file, struct wait_queue_head *head, -- struct poll_table_struct *p) -+ struct poll_table_struct *p, unsigned long fixed_event) - { - struct io_poll_table *pt = container_of(p, struct io_poll_table, pt); - -diff --git a/fs/select.c b/fs/select.c -index 37aaa8317f3a..ec91d05beb7d 100644 ---- a/fs/select.c -+++ b/fs/select.c -@@ -116,7 +116,7 @@ struct poll_table_page { - * poll table. - */ - static void __pollwait(struct file *filp, wait_queue_head_t *wait_address, -- poll_table *p); -+ poll_table *p, unsigned long fixed_event); - - void poll_initwait(struct poll_wqueues *pwq) - { -@@ -212,6 +212,14 @@ static int pollwake(wait_queue_entry_t *wait, unsigned mode, int sync, void *key - struct poll_table_entry *entry; - - entry = container_of(wait, struct poll_table_entry, wait); -+ -+ /* -+ * If this fd type has a hardwired key which should override the key -+ * (e.g. if it is waiting on a non-file waitqueue), jam it in here. -+ */ -+ if (entry->fixed_key) -+ key = (void *)entry->fixed_key; -+ - if (key && !(key_to_poll(key) & entry->key)) - return 0; - return __pollwake(wait, mode, sync, key); -@@ -219,15 +227,22 @@ static int pollwake(wait_queue_entry_t *wait, unsigned mode, int sync, void *key - - /* Add a new entry */ - static void __pollwait(struct file *filp, wait_queue_head_t *wait_address, -- poll_table *p) -+ poll_table *p, unsigned long fixed_event) - { - struct poll_wqueues *pwq = container_of(p, struct poll_wqueues, pt); -- struct poll_table_entry *entry = poll_get_entry(pwq); -+ struct poll_table_entry *entry; -+ -+ if (fixed_event && !(p->_key & fixed_event)) -+ return; -+ -+ entry = poll_get_entry(pwq); - if (!entry) - return; -+ - entry->filp = get_file(filp); - entry->wait_address = wait_address; - entry->key = p->_key; -+ entry->fixed_key = fixed_event; - init_waitqueue_func_entry(&entry->wait, pollwake); - entry->wait.private = pwq; - add_wait_queue(wait_address, &entry->wait); -diff --git a/fs/waitfd.c b/fs/waitfd.c -new file mode 100644 -index 000000000000..311f84d7b85f ---- /dev/null -+++ b/fs/waitfd.c -@@ -0,0 +1,130 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * fs/waitfd.c -+ * -+ * Copyright (C) 2008 Red Hat, Casey Dahlin <cdahlin@redhat.com> -+ * -+ * Largely derived from fs/signalfd.c -+ */ -+ -+#include <linux/file.h> -+#include <linux/poll.h> -+#include <linux/init.h> -+#include <linux/fs.h> -+#include <linux/sched.h> -+#include <linux/slab.h> -+#include <linux/kernel.h> -+#include <linux/signal.h> -+#include <linux/list.h> -+#include <linux/anon_inodes.h> -+#include <linux/syscalls.h> -+ -+long kernel_wait4(pid_t upid, int __user *stat_addr, -+ int options, struct rusage __user *ru); -+ -+struct waitfd_ctx { -+ int options; -+ pid_t upid; -+}; -+ -+static int waitfd_release(struct inode *inode, struct file *file) -+{ -+ kfree(file->private_data); -+ return 0; -+} -+ -+static unsigned int waitfd_poll(struct file *file, poll_table *wait) -+{ -+ struct waitfd_ctx *ctx = file->private_data; -+ long value; -+ -+ poll_wait_fixed(file, ¤t->signal->wait_chldexit, wait, -+ POLLIN); -+ -+ value = kernel_wait4(ctx->upid, NULL, ctx->options | WNOHANG | WNOWAIT, -+ NULL); -+ if (value > 0 || value == -ECHILD) -+ return POLLIN | POLLRDNORM; -+ -+ return 0; -+} -+ -+/* -+ * Returns a multiple of the size of a stat_addr, or a negative error code. The -+ * "count" parameter must be at least sizeof(int). -+ */ -+static ssize_t waitfd_read(struct file *file, char __user *buf, size_t count, -+ loff_t *ppos) -+{ -+ struct waitfd_ctx *ctx = file->private_data; -+ int __user *stat_addr = (int *)buf; -+ int flags = ctx->options; -+ ssize_t ret, total = 0; -+ -+ count /= sizeof(int); -+ if (!count) -+ return -EINVAL; -+ -+ if (file->f_flags & O_NONBLOCK) -+ flags |= WNOHANG; -+ -+ do { -+ ret = kernel_wait4(ctx->upid, stat_addr, flags, NULL); -+ if (ret == 0) -+ ret = -EAGAIN; -+ if (ret == -ECHILD) -+ ret = 0; -+ if (ret <= 0) -+ break; -+ -+ stat_addr++; -+ total += sizeof(int); -+ } while (--count); -+ -+ return total ? total : ret; -+} -+ -+static const struct file_operations waitfd_fops = { -+ .release = waitfd_release, -+ .poll = waitfd_poll, -+ .read = waitfd_read, -+ .llseek = noop_llseek, -+}; -+ -+SYSCALL_DEFINE4(waitfd, int __maybe_unused, which, pid_t, upid, int, options, -+ int __maybe_unused, flags) -+{ -+ int ufd; -+ struct waitfd_ctx *ctx; -+ -+ /* -+ * Options validation from kernel_wait4(), minus WNOWAIT, which is -+ * only used by our polling implementation. If WEXITED or WSTOPPED -+ * are provided, silently remove them (for backward compatibility with -+ * older callers). -+ */ -+ options &= ~(WEXITED | WSTOPPED); -+ if (options & ~(WNOHANG|WUNTRACED|WCONTINUED| -+ __WNOTHREAD|__WCLONE|__WALL)) -+ return -EINVAL; -+ -+ ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); -+ if (!ctx) -+ return -ENOMEM; -+ -+ ctx->options = options; -+ ctx->upid = upid; -+ -+ ufd = anon_inode_getfd("[waitfd]", &waitfd_fops, ctx, -+ O_RDWR | flags | ((options & WNOHANG) ? -+ O_NONBLOCK | 0 : 0)); -+ /* -+ * Use the fd's nonblocking state from now on, since that can change. -+ */ -+ ctx->options &= ~WNOHANG; -+ -+ if (ufd < 0) -+ kfree(ctx); -+ -+ return ufd; -+} -diff --git a/include/linux/poll.h b/include/linux/poll.h -index 1cdc32b1f1b0..1c06718f39bc 100644 ---- a/include/linux/poll.h -+++ b/include/linux/poll.h -@@ -34,7 +34,8 @@ struct poll_table_struct; - /* - * structures and helpers for f_op->poll implementations - */ --typedef void (*poll_queue_proc)(struct file *, wait_queue_head_t *, struct poll_table_struct *); -+typedef void (*poll_queue_proc)(struct file *, wait_queue_head_t *, -+ struct poll_table_struct *, unsigned long fixed_event); - - /* - * Do not touch the structure directly, use the access functions -@@ -48,7 +49,15 @@ typedef struct poll_table_struct { - static inline void poll_wait(struct file * filp, wait_queue_head_t * wait_address, poll_table *p) - { - if (p && p->_qproc && wait_address) -- p->_qproc(filp, wait_address, p); -+ p->_qproc(filp, wait_address, p, 0); -+} -+ -+static inline void poll_wait_fixed(struct file *filp, -+ wait_queue_head_t *wait_address, poll_table *p, -+ unsigned long fixed_event) -+{ -+ if (p && p->_qproc && wait_address) -+ p->_qproc(filp, wait_address, p, fixed_event); - } - - /* -@@ -93,6 +102,7 @@ static inline __poll_t vfs_poll(struct file *file, struct poll_table_struct *pt) - struct poll_table_entry { - struct file *filp; - __poll_t key; -+ unsigned long fixed_key; - wait_queue_entry_t wait; - wait_queue_head_t *wait_address; - }; -diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h -index aea0ce9f3b74..0db3a09986d7 100644 ---- a/include/linux/syscalls.h -+++ b/include/linux/syscalls.h -@@ -1366,6 +1366,9 @@ long ksys_old_shmctl(int shmid, int cmd, struct shmid_ds __user *buf); - long compat_ksys_semtimedop(int semid, struct sembuf __user *tsems, - unsigned int nsops, - const struct old_timespec32 __user *timeout); -+#ifdef CONFIG_DTRACE -+asmlinkage long sys_waitfd(int which, pid_t upid, int options, int flags); -+#endif - - int __sys_getsockopt(int fd, int level, int optname, char __user *optval, - int __user *optlen); -diff --git a/include/uapi/asm-generic/unistd.h b/include/uapi/asm-generic/unistd.h -index 2056318988f7..58238d6fbbcb 100644 ---- a/include/uapi/asm-generic/unistd.h -+++ b/include/uapi/asm-generic/unistd.h -@@ -860,8 +860,11 @@ __SYSCALL(__NR_faccessat2, sys_faccessat2) - #define __NR_process_madvise 440 - __SYSCALL(__NR_process_madvise, sys_process_madvise) - -+#define __NR_waitfd 473 -+__SYSCALL(__NR_waitfd, sys_waitfd) -+ - #undef __NR_syscalls --#define __NR_syscalls 441 -+#define __NR_syscalls 474 - - /* - * 32 bit systems traditionally used different -diff --git a/init/Kconfig b/init/Kconfig -index 05d377ccc0e0..5a86bbbf43e0 100644 ---- a/init/Kconfig -+++ b/init/Kconfig -@@ -1562,6 +1562,22 @@ config EPOLL - Disabling this option will cause the kernel to be built without - support for epoll family of system calls. - -+config WAITFD -+ bool "Enable waitfd() system call" if EXPERT -+ select ANON_INODES -+ default n -+ help -+ Enable the waitfd() system call that allows receiving child state -+ changes from a file descriptor. This permits use of poll() to -+ monitor waitpid() output simultaneously with other fd state changes, -+ even if the waitpid() output is coming from thread-targetted sources -+ such as ptrace(). -+ -+ Note: this system call is not upstream: its syscall number is not -+ finalized, so the call itself should only be used with caution. -+ -+ If unsure, say N. -+ - config SIGNALFD - bool "Enable signalfd() system call" if EXPERT - default y -diff --git a/kernel/exit.c b/kernel/exit.c -index d13d67fc5f4e..5c5859a9ba75 100644 ---- a/kernel/exit.c -+++ b/kernel/exit.c -@@ -1586,7 +1586,10 @@ long kernel_wait4(pid_t upid, int __user *stat_addr, int options, - enum pid_type type; - long ret; - -- if (options & ~(WNOHANG|WUNTRACED|WCONTINUED| -+ /* -+ * As for wait4(), except that waitfd() additionally needs WNOWAIT. -+ */ -+ if (options & ~(WNOHANG|WNOWAIT|WUNTRACED|WCONTINUED| - __WNOTHREAD|__WCLONE|__WALL)) - return -EINVAL; - -@@ -1641,7 +1644,13 @@ SYSCALL_DEFINE4(wait4, pid_t, upid, int __user *, stat_addr, - int, options, struct rusage __user *, ru) - { - struct rusage r; -- long err = kernel_wait4(upid, stat_addr, options, ru ? &r : NULL); -+ long err; -+ -+ if (options & ~(WNOHANG|WUNTRACED|WCONTINUED| -+ __WNOTHREAD|__WCLONE|__WALL)) -+ return -EINVAL; -+ -+ err = kernel_wait4(upid, stat_addr, options, ru ? &r : NULL); - - if (err > 0) { - if (ru && copy_to_user(ru, &r, sizeof(struct rusage))) -diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c -index f27ac94d5fa7..53900d50a8af 100644 ---- a/kernel/sys_ni.c -+++ b/kernel/sys_ni.c -@@ -391,6 +391,7 @@ COND_SYSCALL(subpage_prot); - * include/uapi/asm-generic/unistd.h and wanted by >= 1 arch - */ - -+COND_SYSCALL(waitfd); - /* __ARCH_WANT_SYSCALL_NO_FLAGS */ - COND_SYSCALL(epoll_create); - COND_SYSCALL(inotify_init); -diff --git a/mm/memcontrol.c b/mm/memcontrol.c -index 8fc23d53f550..a5d4a1d4f868 100644 ---- a/mm/memcontrol.c -+++ b/mm/memcontrol.c -@@ -4839,7 +4839,7 @@ static int memcg_event_wake(wait_queue_entry_t *wait, unsigned mode, - } - - static void memcg_event_ptable_queue_proc(struct file *file, -- wait_queue_head_t *wqh, poll_table *pt) -+ wait_queue_head_t *wqh, poll_table *pt, unsigned long unused) - { - struct mem_cgroup_event *event = - container_of(pt, struct mem_cgroup_event, pt); -diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c -index 8f528e783a6c..d4890a86c0ce 100644 ---- a/net/9p/trans_fd.c -+++ b/net/9p/trans_fd.c -@@ -545,7 +545,8 @@ static int p9_pollwake(wait_queue_entry_t *wait, unsigned int mode, int sync, vo - */ - - static void --p9_pollwait(struct file *filp, wait_queue_head_t *wait_address, poll_table *p) -+p9_pollwait(struct file *filp, wait_queue_head_t *wait_address, poll_table *p, -+ unsigned long unused) - { - struct p9_conn *m = container_of(p, struct p9_conn, pt); - struct p9_poll_wait *pwait = NULL; -diff --git a/tools/testing/selftests/waitfd/Makefile b/tools/testing/selftests/waitfd/Makefile -new file mode 100644 -index 000000000000..f85c80b54f05 ---- /dev/null -+++ b/tools/testing/selftests/waitfd/Makefile -@@ -0,0 +1,28 @@ -+uname_M := $(shell uname -m 2>/dev/null || echo not) -+ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/) -+ifeq ($(ARCH),i386) -+ ARCH := X86 -+ CFLAGS := -DCONFIG_X86_32 -D__i386__ -+endif -+ifeq ($(ARCH),x86_64) -+ ARCH := X86 -+ CFLAGS := -DCONFIG_X86_64 -D__x86_64__ -+endif -+ -+CFLAGS += -I../../../../arch/x86/include/generated/ -+CFLAGS += -I../../../../include/ -+CFLAGS += -I../../../../usr/include/ -+CFLAGS += -I../../../../arch/x86/include/ -+ -+all: -+ifeq ($(ARCH),X86) -+ gcc $(CFLAGS) waitfd.c -o waitfd -+else -+ echo "Not an x86 target, can't build waitfd selftest" -+endif -+ -+run_tests: all -+ @./waitfd || echo "waitfd: [FAIL]" -+ -+clean: -+ rm -fr ./waitfd -diff --git a/tools/testing/selftests/waitfd/waitfd.c b/tools/testing/selftests/waitfd/waitfd.c -new file mode 100644 -index 000000000000..2df60bbdbb35 ---- /dev/null -+++ b/tools/testing/selftests/waitfd/waitfd.c -@@ -0,0 +1,116 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* waitfd testcase. */ -+ -+#define _GNU_SOURCE 1 -+#include <linux/unistd.h> -+#include <sys/syscall.h> -+#include <sys/ptrace.h> -+#include <sys/types.h> -+#include <sys/wait.h> -+#include <errno.h> -+#include <stdio.h> -+#include <stdlib.h> -+#include <unistd.h> -+#include <signal.h> -+#include <string.h> -+#include <poll.h> -+ -+int waitfd(int which, pid_t upid, int options, int flags) -+{ -+ return syscall(__NR_waitfd, which, upid, options, flags); -+} -+ -+void sleeper(void) -+{ -+ sleep(10); -+ exit(0); -+} -+ -+int main (void) -+{ -+ pid_t die_pid, ptrace_pid; -+ int die_fd, ptrace_fd; -+ int status; -+ struct pollfd pfd[2]; -+ int procs_left = 2; -+ -+ memset(pfd, 0, sizeof(pfd)); -+ -+ /* -+ * Fork off two children, one of which waits for a ptrace(). -+ * Both just sleep after that. Make sure we can use __WNOTHREAD, -+ * __WALL, and WUNTRACED without getting an -EINVAL. -+ */ -+ -+ die_pid = fork(); -+ -+ if (die_pid == 0) -+ sleeper(); -+ -+ ptrace_pid = fork(); -+ if (ptrace_pid == 0) { -+ ptrace(PTRACE_TRACEME, 0, 0, 0); -+ sleeper(); -+ } -+ -+ die_fd = waitfd(P_PID, die_pid, 0, 0); -+ ptrace_fd = waitfd(P_PID, ptrace_pid, __WNOTHREAD | __WALL | WUNTRACED, 0); -+ -+ if (die_fd < 0 || ptrace_fd < 0) { -+ perror("Cannot waitfd()"); -+ exit(1); -+ } -+ -+ pfd[0].fd = die_fd; -+ pfd[0].events = POLLIN; -+ pfd[1].fd = ptrace_fd; -+ pfd[1].events = POLLIN; -+ -+ /* -+ * Hit the ptrace PID with a signal -+ */ -+ kill(ptrace_pid, SIGABRT); -+ -+ while (procs_left > 0) { -+ ssize_t bytes; -+ -+ if (poll(pfd, 2, -1) < 0) -+ perror ("poll() failed"); -+ -+ if (pfd[0].revents != 0) { -+ bytes = read(die_fd, &status, sizeof(int)); -+ if (bytes < sizeof(int)) { -+ fprintf(stderr, "Only read %zi bytes\n", bytes); -+ exit(1); -+ } -+ -+ printf("die_fd returned %i via waitfd read: revents are %x\n", -+ status, pfd[0].revents); -+ pfd[0].fd *= -1; -+ procs_left--; -+ } -+ -+ if (pfd[1].revents != 0) { -+ pid_t check_pid; -+ status = 0; -+ check_pid = waitpid(ptrace_pid, &status, __WNOTHREAD | -+ __WALL | WUNTRACED | WNOHANG); -+ if (check_pid < 0) { -+ fprintf(stderr, "waitpid() failed: %s\n", -+ strerror(errno)); -+ exit(1); -+ } -+ if (check_pid != ptrace_pid) { -+ fprintf(stderr, "waitfd() said PID %i was ready, but waitpid() says it isn't: %i\n", -+ ptrace_pid, check_pid); -+ exit(1); -+ } -+ printf("ptrace_fd returned status %i via waitpid; revents are %x\n", -+ status, pfd[1].revents); -+ pfd[1].fd *= -1; -+ procs_left--; -+ } -+ } -+ -+ return 0; -+} -diff --git a/virt/kvm/eventfd.c b/virt/kvm/eventfd.c -index c2323c27a28b..8da91bb7015c 100644 ---- a/virt/kvm/eventfd.c -+++ b/virt/kvm/eventfd.c -@@ -232,7 +232,7 @@ irqfd_wakeup(wait_queue_entry_t *wait, unsigned mode, int sync, void *key) - - static void - irqfd_ptable_queue_proc(struct file *file, wait_queue_head_t *wqh, -- poll_table *pt) -+ poll_table *pt, unsigned long unused) - { - struct kvm_kernel_irqfd *irqfd = - container_of(pt, struct kvm_kernel_irqfd, pt); --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/dtrace-patches/0004-dtrace-core-and-x86.patch b/sys-kernel/cairn-sources/files/5.10.13/dtrace-patches/0004-dtrace-core-and-x86.patch deleted file mode 100644 index 1d4614df0d62..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/dtrace-patches/0004-dtrace-core-and-x86.patch +++ /dev/null @@ -1,8052 +0,0 @@ -From 6b71ecc990f6b40c944f31ec14a75032e4e09235 Mon Sep 17 00:00:00 2001 -From: Kris Van Hees <kris.van.hees@oracle.com> -Date: Mon, 19 Nov 2018 22:21:36 +0000 -Subject: [PATCH 04/19] dtrace: core and x86 - -This implements DTrace's core kernel (linked-in) components, -including platform-dependent portions for x86. (Most of this -machinery is not used until the next commit.) - -Signed-off-by: Nick Alcock <nick.alcock@oracle.com> -Signed-off-by: Kris Van Hees <kris.van.hees@oracle.com> -Signed-off-by: Tomas Jedlicka <tomas.jedlicka@oracle.com> -Signed-off-by: Eugene Loh <eugene.loh@oracle.com> -Signed-off-by: David Mc Lean <david.mclean@oracle.com> -Signed-off-by: Vincent Lim <vincent.lim@oracle.com> ---- - Makefile | 7 +- - arch/x86/Kconfig | 3 + - arch/x86/include/asm/dtrace_arch.h | 28 + - arch/x86/include/asm/dtrace_cpuinfo.h | 14 + - arch/x86/include/asm/dtrace_util.h | 16 + - arch/x86/kernel/dtrace_util.c | 244 ++++ - arch/x86/mm/fault.c | 28 +- - fs/exec.c | 5 + - include/asm-generic/qrwlock.h | 24 + - include/dtrace/dtrace_impl.h | 1236 +++++++++++++++++ - include/dtrace/dtrace_impl_defines.h | 173 +++ - include/dtrace/provider.h | 971 +++++++++++++ - include/dtrace/provider_defines.h | 41 + - include/dtrace/types.h | 131 ++ - include/linux/cpuhotplug.h | 1 + - include/linux/cyclic.h | 49 + - include/linux/dtrace/cpu_defines.h | 61 + - include/linux/dtrace_cpu.h | 53 + - include/linux/dtrace_cpu_defines.h | 2 + - include/linux/dtrace_os.h | 120 ++ - include/linux/dtrace_psinfo.h | 59 + - include/linux/dtrace_task.h | 38 + - include/linux/dtrace_task_impl.h | 28 + - include/linux/dtrace_types.h | 13 + - include/linux/ktime.h | 8 + - include/linux/module.h | 3 + - include/linux/mutex.h | 16 + - include/linux/rwlock.h | 7 + - include/linux/sched.h | 4 + - include/linux/spinlock_up.h | 5 + - include/uapi/linux/dtrace/Kbuild | 35 + - include/uapi/linux/dtrace/actions.h | 14 + - include/uapi/linux/dtrace/actions_defines.h | 181 +++ - include/uapi/linux/dtrace/arg.h | 42 + - include/uapi/linux/dtrace/arg_defines.h | 21 + - include/uapi/linux/dtrace/buffer.h | 43 + - include/uapi/linux/dtrace/buffer_defines.h | 21 + - include/uapi/linux/dtrace/conf.h | 35 + - include/uapi/linux/dtrace/conf_defines.h | 21 + - include/uapi/linux/dtrace/cpu_defines.h | 17 + - include/uapi/linux/dtrace/dif.h | 60 + - include/uapi/linux/dtrace/dif_defines.h | 288 ++++ - include/uapi/linux/dtrace/difo.h | 57 + - include/uapi/linux/dtrace/difo_defines.h | 21 + - include/uapi/linux/dtrace/dof.h | 196 +++ - include/uapi/linux/dtrace/dof_defines.h | 192 +++ - include/uapi/linux/dtrace/dtrace.h | 33 + - include/uapi/linux/dtrace/enabling.h | 76 + - include/uapi/linux/dtrace/enabling_defines.h | 25 + - include/uapi/linux/dtrace/fasttrap.h | 56 + - include/uapi/linux/dtrace/fasttrap_defines.h | 25 + - include/uapi/linux/dtrace/fasttrap_ioctl.h | 19 + - include/uapi/linux/dtrace/faults.h | 20 + - include/uapi/linux/dtrace/faults_defines.h | 39 + - include/uapi/linux/dtrace/helpers.h | 101 ++ - include/uapi/linux/dtrace/helpers_defines.h | 21 + - include/uapi/linux/dtrace/ioctl.h | 47 + - include/uapi/linux/dtrace/metadesc.h | 81 ++ - include/uapi/linux/dtrace/metadesc_defines.h | 24 + - include/uapi/linux/dtrace/options.h | 20 + - include/uapi/linux/dtrace/options_defines.h | 72 + - include/uapi/linux/dtrace/stability.h | 52 + - include/uapi/linux/dtrace/stability_defines.h | 53 + - include/uapi/linux/dtrace/status.h | 50 + - include/uapi/linux/dtrace/universal.h | 47 + - init/Kconfig | 2 + - init/main.c | 10 + - kernel/Makefile | 1 + - kernel/dtrace/Kconfig | 54 + - kernel/dtrace/Makefile | 12 + - kernel/dtrace/cyclic.c | 526 +++++++ - kernel/dtrace/dtrace_cpu.c | 61 + - kernel/dtrace/dtrace_os.c | 332 +++++ - kernel/dtrace/dtrace_psinfo.c | 212 +++ - kernel/dtrace/dtrace_task.c | 237 ++++ - kernel/exit.c | 4 + - kernel/fork.c | 23 + - kernel/module.c | 14 + - kernel/sched/core.c | 10 + - kernel/sched/sched.h | 4 + - kernel/time/timekeeping.c | 2 + - scripts/coccinelle/dtrace/enum-elision.cocci | 29 + - .../coccinelle/dtrace/typedef-elision.cocci | 83 ++ - scripts/package/mkspec | 1 + - 84 files changed, 7106 insertions(+), 4 deletions(-) - create mode 100644 arch/x86/include/asm/dtrace_arch.h - create mode 100644 arch/x86/include/asm/dtrace_cpuinfo.h - create mode 100644 arch/x86/include/asm/dtrace_util.h - create mode 100644 arch/x86/kernel/dtrace_util.c - create mode 100644 include/dtrace/dtrace_impl.h - create mode 100644 include/dtrace/dtrace_impl_defines.h - create mode 100644 include/dtrace/provider.h - create mode 100644 include/dtrace/provider_defines.h - create mode 100644 include/dtrace/types.h - create mode 100644 include/linux/cyclic.h - create mode 100644 include/linux/dtrace/cpu_defines.h - create mode 100644 include/linux/dtrace_cpu.h - create mode 100644 include/linux/dtrace_cpu_defines.h - create mode 100644 include/linux/dtrace_os.h - create mode 100644 include/linux/dtrace_psinfo.h - create mode 100644 include/linux/dtrace_task.h - create mode 100644 include/linux/dtrace_task_impl.h - create mode 100644 include/linux/dtrace_types.h - create mode 100644 include/uapi/linux/dtrace/Kbuild - create mode 100644 include/uapi/linux/dtrace/actions.h - create mode 100644 include/uapi/linux/dtrace/actions_defines.h - create mode 100644 include/uapi/linux/dtrace/arg.h - create mode 100644 include/uapi/linux/dtrace/arg_defines.h - create mode 100644 include/uapi/linux/dtrace/buffer.h - create mode 100644 include/uapi/linux/dtrace/buffer_defines.h - create mode 100644 include/uapi/linux/dtrace/conf.h - create mode 100644 include/uapi/linux/dtrace/conf_defines.h - create mode 100644 include/uapi/linux/dtrace/cpu_defines.h - create mode 100644 include/uapi/linux/dtrace/dif.h - create mode 100644 include/uapi/linux/dtrace/dif_defines.h - create mode 100644 include/uapi/linux/dtrace/difo.h - create mode 100644 include/uapi/linux/dtrace/difo_defines.h - create mode 100644 include/uapi/linux/dtrace/dof.h - create mode 100644 include/uapi/linux/dtrace/dof_defines.h - create mode 100644 include/uapi/linux/dtrace/dtrace.h - create mode 100644 include/uapi/linux/dtrace/enabling.h - create mode 100644 include/uapi/linux/dtrace/enabling_defines.h - create mode 100644 include/uapi/linux/dtrace/fasttrap.h - create mode 100644 include/uapi/linux/dtrace/fasttrap_defines.h - create mode 100644 include/uapi/linux/dtrace/fasttrap_ioctl.h - create mode 100644 include/uapi/linux/dtrace/faults.h - create mode 100644 include/uapi/linux/dtrace/faults_defines.h - create mode 100644 include/uapi/linux/dtrace/helpers.h - create mode 100644 include/uapi/linux/dtrace/helpers_defines.h - create mode 100644 include/uapi/linux/dtrace/ioctl.h - create mode 100644 include/uapi/linux/dtrace/metadesc.h - create mode 100644 include/uapi/linux/dtrace/metadesc_defines.h - create mode 100644 include/uapi/linux/dtrace/options.h - create mode 100644 include/uapi/linux/dtrace/options_defines.h - create mode 100644 include/uapi/linux/dtrace/stability.h - create mode 100644 include/uapi/linux/dtrace/stability_defines.h - create mode 100644 include/uapi/linux/dtrace/status.h - create mode 100644 include/uapi/linux/dtrace/universal.h - create mode 100644 kernel/dtrace/Kconfig - create mode 100644 kernel/dtrace/Makefile - create mode 100644 kernel/dtrace/cyclic.c - create mode 100644 kernel/dtrace/dtrace_cpu.c - create mode 100644 kernel/dtrace/dtrace_os.c - create mode 100644 kernel/dtrace/dtrace_psinfo.c - create mode 100644 kernel/dtrace/dtrace_task.c - create mode 100644 scripts/coccinelle/dtrace/enum-elision.cocci - create mode 100644 scripts/coccinelle/dtrace/typedef-elision.cocci - -diff --git a/Makefile b/Makefile -index c21d2a09c9ca..fb9393fa10f0 100644 ---- a/Makefile -+++ b/Makefile -@@ -1106,15 +1106,15 @@ core-y += kernel/ certs/ mm/ fs/ ipc/ security/ crypto/ block/ - - vmlinux-dirs := $(patsubst %/,%,$(filter %/, \ - $(core-y) $(core-m) $(drivers-y) $(drivers-m) \ -- $(libs-y) $(libs-m))) -+ $(libs-y) $(libs-m) $(dtrace-y) $(dtrace-m))) - - vmlinux-alldirs := $(sort $(vmlinux-dirs) Documentation \ - $(patsubst %/,%,$(filter %/, $(core-) \ -- $(drivers-) $(libs-)))) -+ $(drivers-) $(libs-) $(dtrace-)))) - - subdir-modorder := $(addsuffix modules.order,$(filter %/, \ - $(core-y) $(core-m) $(libs-y) $(libs-m) \ -- $(drivers-y) $(drivers-m))) -+ $(drivers-y) $(drivers-m) $(dtrace-y) $(dtrace-m))) - - build-dirs := $(vmlinux-dirs) - clean-dirs := $(vmlinux-alldirs) -@@ -1129,6 +1129,7 @@ else - KBUILD_VMLINUX_LIBS := $(patsubst %/,%/lib.a, $(libs-y)) - endif - KBUILD_VMLINUX_OBJS += $(patsubst %/,%/built-in.a, $(drivers-y)) -+KBUILD_VMLINUX_OBJS += $(patsubst %/,%/built-in.a, $(dtrace-y)) - - export KBUILD_VMLINUX_OBJS KBUILD_VMLINUX_LIBS - export KBUILD_LDS := arch/$(SRCARCH)/kernel/vmlinux.lds -diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig -index 3a5ecb1039bf..372e81191f8e 100644 ---- a/arch/x86/Kconfig -+++ b/arch/x86/Kconfig -@@ -371,6 +371,9 @@ config PGTABLE_LEVELS - default 3 if X86_PAE - default 2 - -+config ARCH_SUPPORTS_DTRACE -+ def_bool y if X86_64 -+ - config CC_HAS_SANE_STACKPROTECTOR - bool - default $(success,$(srctree)/scripts/gcc-x86_64-has-stack-protector.sh $(CC)) if 64BIT -diff --git a/arch/x86/include/asm/dtrace_arch.h b/arch/x86/include/asm/dtrace_arch.h -new file mode 100644 -index 000000000000..74e27f08a873 ---- /dev/null -+++ b/arch/x86/include/asm/dtrace_arch.h -@@ -0,0 +1,28 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+ -+/* -+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+#ifndef _X86_DTRACE_ARCH_H -+#define _X86_DTRACE_ARCH_H -+ -+/* Number of arguments stored inside the mstate. */ -+#define DTRACE_MSTATE_ARGS_MAX 6 -+ -+typedef uint8_t asm_instr_t; -+ -+typedef int (*prov_exit_f)(void); -+ -+/* -+ * Structure to hold DTrace specific information about modules (including the -+ * core kernel module). Note that each module (and the main kernel) already -+ * has one field that relates to probing: -+ * - pdata: pointer to a dtrace_module struct (for DTrace) -+ */ -+struct dtrace_module { -+ int enabled_cnt; -+ prov_exit_f prov_exit; /* Called with module_mutex held */ -+}; -+ -+#endif /* _X86_DTRACE_ARCH_H */ -diff --git a/arch/x86/include/asm/dtrace_cpuinfo.h b/arch/x86/include/asm/dtrace_cpuinfo.h -new file mode 100644 -index 000000000000..47024e169ec4 ---- /dev/null -+++ b/arch/x86/include/asm/dtrace_cpuinfo.h -@@ -0,0 +1,14 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+ -+/* Copyright (C) 2013-2014 Oracle, Inc. */ -+ -+#ifndef _ASM_X86_DTRACE_CPUINFO_H_ -+#define _ASM_X86_DTRACE_CPUINFO_H_ -+ -+#include <asm/processor.h> -+ -+typedef struct cpuinfo_x86 cpuinfo_arch_t; -+ -+#define dtrace_cpuinfo_chip(ci) ((ci)->phys_proc_id) -+ -+#endif /* _ASM_X86_DTRACE_CPUINFO_H_ */ -diff --git a/arch/x86/include/asm/dtrace_util.h b/arch/x86/include/asm/dtrace_util.h -new file mode 100644 -index 000000000000..4d9843bbc95b ---- /dev/null -+++ b/arch/x86/include/asm/dtrace_util.h -@@ -0,0 +1,16 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+#ifndef _X86_DTRACE_UTIL_H -+#define _X86_DTRACE_UTIL_H -+ -+#ifndef __ASSEMBLY__ -+ -+#include <asm/dtrace_arch.h> -+#include <asm/ptrace.h> -+ -+#endif -+ -+#endif /* _X86_DTRACE_UTIL_H */ -diff --git a/arch/x86/kernel/dtrace_util.c b/arch/x86/kernel/dtrace_util.c -new file mode 100644 -index 000000000000..d3d552c062f7 ---- /dev/null -+++ b/arch/x86/kernel/dtrace_util.c -@@ -0,0 +1,244 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_util.c -+ * DESCRIPTION: Dynamic Tracing: Architecture utility functions -+ * -+ * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+#include <linux/dtrace_cpu.h> -+#include <linux/dtrace_os.h> -+#include <linux/dtrace_task_impl.h> -+#include <linux/kdebug.h> -+#include <linux/mm.h> -+#include <linux/module.h> -+#include <linux/memory.h> -+#include <linux/notifier.h> -+#include <linux/ptrace.h> -+#include <linux/sched.h> -+#include <linux/slab.h> -+#include <linux/uaccess.h> -+#include <linux/sched/task_stack.h> -+#include <asm/insn.h> -+#include <asm/pgtable.h> -+#include <asm/ptrace.h> -+#include <asm/text-patching.h> -+#include <asm/dtrace_arch.h> -+#include <asm/dtrace_util.h> -+ -+int dtrace_instr_size(const asm_instr_t *addr) -+{ -+ struct insn insn; -+ -+ kernel_insn_init(&insn, addr, MAX_INSN_SIZE); -+ insn_get_length(&insn); -+ -+ return insn_complete(&insn) ? insn.length : -1; -+} -+EXPORT_SYMBOL(dtrace_instr_size); -+ -+/* -+ * Move the instruction pointer forward to the next instruction, effectiely -+ * skipping the current one. -+ */ -+static void dtrace_skip_instruction(struct pt_regs *regs) -+{ -+ int delta; -+ -+ delta = dtrace_instr_size((asm_instr_t *)regs->ip); -+ BUG_ON(delta <= 0); -+ -+ regs->ip += delta; -+} -+ -+void dtrace_handle_badaddr(struct pt_regs *regs) -+{ -+ unsigned long addr = read_cr2(); -+ -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); -+ this_cpu_core->cpuc_dtrace_illval = addr; -+ -+ dtrace_skip_instruction(regs); -+} -+ -+/* -+ * Trap notification handler. -+ */ -+int dtrace_die_notifier(struct notifier_block *nb, unsigned long val, -+ void *args) -+{ -+ struct die_args *dargs = args; -+ -+ switch (val) { -+ case DIE_PAGE_FAULT: { -+ if (!DTRACE_CPUFLAG_ISSET(CPU_DTRACE_NOFAULT)) -+ return NOTIFY_DONE; -+ -+ dtrace_handle_badaddr(dargs->regs); -+ -+ return NOTIFY_OK | NOTIFY_STOP_MASK; -+ } -+ case DIE_GPF: { -+ if (!DTRACE_CPUFLAG_ISSET(CPU_DTRACE_NOFAULT)) -+ return NOTIFY_DONE; -+ -+ dtrace_handle_badaddr(dargs->regs); -+ -+ return NOTIFY_OK | NOTIFY_STOP_MASK; -+ } -+ /* fallthrough */ -+ default: -+ return NOTIFY_DONE; -+ } -+} -+ -+static inline int dtrace_bad_address(void *addr) -+{ -+ unsigned long dummy; -+ -+ return get_kernel_nofault(dummy, (unsigned long *)addr); -+} -+ -+static int dtrace_user_addr_is_exec(uintptr_t addr) -+{ -+ struct mm_struct *mm = current->mm; -+ pgd_t *pgd; -+ -+#if CONFIG_PGTABLE_LEVELS > 3 -+ p4d_t *p4d; -+#endif -+ -+ pud_t *pud; -+ pmd_t *pmd; -+ pte_t *pte; -+ unsigned long flags; -+ int ret = 0; -+ -+ if (mm == NULL) -+ return 0; -+ -+ addr &= PAGE_MASK; -+ -+ local_irq_save(flags); -+ -+ pgd = pgd_offset(mm, addr); -+ if (dtrace_bad_address(pgd)) -+ goto out; -+ if (pgd_none(*pgd) || !pgd_present(*pgd)) -+ goto out; -+ -+#if CONFIG_PGTABLE_LEVELS > 3 -+ p4d = p4d_offset(pgd, addr); -+ if (dtrace_bad_address(p4d)) -+ goto out; -+ if (p4d_none(*p4d) || !p4d_present(*p4d)) -+ goto out; -+ -+ pud = pud_offset(p4d, addr); -+#else -+ pud = pud_offset(pgd, addr); -+#endif -+ -+ if (dtrace_bad_address(pud)) -+ goto out; -+ if (pud_none(*pud) || !pud_present(*pud)) -+ goto out; -+ if (unlikely(pud_large(*pud))) { -+ pte = (pte_t *)pud; -+ if (dtrace_bad_address(pte)) -+ goto out; -+ -+ ret = pte_exec(*pte); -+ goto out; -+ } -+ -+ pmd = pmd_offset(pud, addr); -+ if (dtrace_bad_address(pmd)) -+ goto out; -+ if (pmd_none(*pmd)) -+ goto out; -+ if (unlikely(pmd_large(*pmd) || !pmd_present(*pmd))) { -+ pte = (pte_t *)pmd; -+ if (dtrace_bad_address(pte)) -+ goto out; -+ -+ ret = pte_exec(*pte); -+ goto out; -+ } -+ -+ pte = pte_offset_map(pmd, addr); -+ if (dtrace_bad_address(pte)) -+ goto out; -+ if (pte_protnone(*pte)) -+ goto out; -+ if ((pte_flags(*pte) & (_PAGE_PRESENT|_PAGE_USER|_PAGE_SPECIAL)) != -+ (_PAGE_PRESENT|_PAGE_USER)) -+ goto out; -+ -+ ret = pte_exec(*pte); -+ -+out: -+ local_irq_restore(flags); -+ -+ return ret; -+} -+ -+void dtrace_user_stacktrace(struct stacktrace_state *st) -+{ -+ struct pt_regs *regs = current_pt_regs(); -+ uint64_t *pcs = st->pcs; -+ int limit = st->limit; -+ unsigned long *bos; -+ unsigned long *sp = (unsigned long *)user_stack_pointer(regs); -+ int ret; -+ -+ if (!user_mode(regs)) -+ goto out; -+ -+ if (current->dt_task == NULL) -+ goto out; -+ -+ bos = current->dt_task->dt_ustack; -+ -+ st->depth = 1; -+ if (pcs) -+ *pcs++ = (uint64_t)instruction_pointer(regs); -+ limit--; -+ -+ if (!limit) -+ goto out; -+ -+ while (sp <= bos && limit) { -+ unsigned long pc; -+ -+ pagefault_disable(); -+ ret = __copy_from_user_inatomic(&pc, sp, sizeof(pc)); -+ pagefault_enable(); -+ -+ if (ret) -+ break; -+ -+ if (dtrace_user_addr_is_exec(pc)) { -+ if (pcs) -+ *pcs++ = pc; -+ limit--; -+ st->depth++; -+ } -+ -+ sp++; -+ } -+ -+out: -+ if (pcs) { -+ while (limit--) -+ *pcs++ = 0; -+ } -+} -+ -+void dtrace_mod_pdata_init(struct dtrace_module *pdata) -+{ -+} -+ -+void dtrace_mod_pdata_cleanup(struct dtrace_module *pdata) -+{ -+} -diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c -index 82bf37a5c9ec..5b16183100d0 100644 ---- a/arch/x86/mm/fault.c -+++ b/arch/x86/mm/fault.c -@@ -18,6 +18,7 @@ - #include <linux/uaccess.h> /* faulthandler_disabled() */ - #include <linux/efi.h> /* efi_recover_from_page_fault()*/ - #include <linux/mm_types.h> -+#include <linux/dtrace_os.h> /* dtrace_no_pf */ - - #include <asm/cpufeature.h> /* boot_cpu_has, ... */ - #include <asm/traps.h> /* dotraplinkage, ... */ -@@ -680,6 +681,16 @@ no_context(struct pt_regs *regs, unsigned long error_code, - (((unsigned long)tsk->stack - 1 - address < PAGE_SIZE) || - address - ((unsigned long)tsk->stack + THREAD_SIZE) < PAGE_SIZE)) { - unsigned long stack = __this_cpu_ist_top_va(DF) - sizeof(void *); -+ -+ /* -+ * Allow for the possibility that we know what we are doing and -+ * ignore this fault. E.g. the address may come from a source -+ * we cannot trust and it is OK if we cannot access it. -+ */ -+ if (notify_die(DIE_PAGE_FAULT, "page fault", regs, error_code, -+ 14, SIGKILL) == NOTIFY_STOP) -+ return; -+ - /* - * We're likely to be running with very little stack space - * left. It's plausible that we'd hit this condition but -@@ -728,8 +739,13 @@ no_context(struct pt_regs *regs, unsigned long error_code, - oops: - /* - * Oops. The kernel tried to access some bad page. We'll have to -- * terminate things with extreme prejudice: -+ * terminate things with extreme prejudice, unless a notifier decides -+ * to let this one slide. - */ -+ if (notify_die(DIE_PAGE_FAULT, "page fault", regs, error_code, 14, -+ SIGKILL) == NOTIFY_STOP) -+ return; -+ - flags = oops_begin(); - - show_fault_oops(regs, error_code, address); -@@ -1223,10 +1239,20 @@ void do_user_addr_fault(struct pt_regs *regs, - tsk = current; - mm = tsk->mm; - -+ /* -+ * From here on, we know this must be a fault in userspace. -+ */ -+ - /* kprobes don't want to hook the spurious faults: */ - if (unlikely(kprobe_page_fault(regs, X86_TRAP_PF))) - return; - -+ /* -+ * DTrace doesn't want to either. -+ */ -+ if (unlikely(dtrace_no_pf(regs))) -+ return; -+ - /* - * Reserved bits are never expected to be set on - * entries in the user portion of the page tables. -diff --git a/fs/exec.c b/fs/exec.c -index ca89e0e3ef10..4340b2803004 100644 ---- a/fs/exec.c -+++ b/fs/exec.c -@@ -64,6 +64,7 @@ - #include <linux/compat.h> - #include <linux/vmalloc.h> - #include <linux/io_uring.h> -+#include <linux/dtrace_os.h> - - #include <linux/uaccess.h> - #include <asm/mmu_context.h> -@@ -1822,6 +1823,10 @@ static int bprm_execve(struct linux_binprm *bprm, - goto out; - - /* execve succeeded */ -+ -+ /* Update DTrace per-task data. */ -+ dtrace_task_exec(current); -+ - current->fs->in_exec = 0; - current->in_execve = 0; - rseq_execve(current); -diff --git a/include/asm-generic/qrwlock.h b/include/asm-generic/qrwlock.h -index 3aefde23dcea..addbb3c7d953 100644 ---- a/include/asm-generic/qrwlock.h -+++ b/include/asm-generic/qrwlock.h -@@ -30,6 +30,26 @@ - extern void queued_read_lock_slowpath(struct qrwlock *lock); - extern void queued_write_lock_slowpath(struct qrwlock *lock); - -+#ifdef CONFIG_DTRACE -+/** -+ * queued_peek_read_can_lock -- would read_trylock() be likely to succeed? -+ * @lock: Pointer to queue rwlock structure -+ */ -+static inline int queued_peek_read_can_lock(struct qrwlock *lock) -+{ -+ return !(atomic_read(&lock->cnts) & _QW_WMASK); -+} -+ -+/** -+ * queued_peek_write_can_lock -- would write_trylock() be likely to succeed? -+ * @lock: Pointer to queue rwlock structure -+ */ -+static inline int queued_peek_write_can_lock(struct qrwlock *lock) -+{ -+ return !atomic_read(&lock->cnts); -+} -+#endif /* CONFIG_DTRACE */ -+ - /** - * queued_read_trylock - try to acquire read lock of a queue rwlock - * @lock : Pointer to queue rwlock structure -@@ -120,6 +140,10 @@ static inline void queued_write_unlock(struct qrwlock *lock) - * Remapping rwlock architecture specific functions to the corresponding - * queue rwlock functions. - */ -+#ifdef CONFIG_DTRACE -+#define arch_peek_read_can_lock(l) queued_peek_read_can_lock(l) -+#define arch_peek_write_can_lock(l) queued_peek_write_can_lock(l) -+#endif /* CONFIG_DTRACE */ - #define arch_read_lock(l) queued_read_lock(l) - #define arch_write_lock(l) queued_write_lock(l) - #define arch_read_trylock(l) queued_read_trylock(l) -diff --git a/include/dtrace/dtrace_impl.h b/include/dtrace/dtrace_impl.h -new file mode 100644 -index 000000000000..2420103c765c ---- /dev/null -+++ b/include/dtrace/dtrace_impl.h -@@ -0,0 +1,1236 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Dynamic Tracing for Linux - Implementation -+ * -+ * Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_IMPL_H -+#define _LINUX_DTRACE_IMPL_H -+ -+#include <linux/cyclic.h> -+#include <linux/idr.h> -+ -+#include <linux/dtrace/universal.h> -+#include <linux/dtrace/dif.h> -+#include <linux/dtrace/difo_defines.h> -+#include <linux/dtrace/metadesc.h> -+#include <linux/dtrace/stability.h> -+#include <linux/dtrace/helpers.h> -+#include <dtrace/types.h> -+#include <dtrace/provider.h> -+#include <dtrace/dtrace_impl_defines.h> -+ -+struct dtrace_provider { -+ struct dtrace_pattr dtpv_attr; -+ struct dtrace_ppriv dtpv_priv; -+ struct dtrace_pops dtpv_pops; -+ char *dtpv_name; -+ void *dtpv_arg; -+ uint_t dtpv_defunct; -+ struct dtrace_provider *dtpv_next; -+}; -+ -+struct dtrace_predicate { -+ struct dtrace_difo *dtp_difo; -+ dtrace_cacheid_t dtp_cacheid; -+ int dtp_refcnt; -+}; -+ -+struct dtrace_statvar { -+ uint64_t dtsv_data; -+ size_t dtsv_size; -+ int dtsv_refcnt; -+ struct dtrace_difv dtsv_var; -+}; -+ -+struct dtrace_action { -+ dtrace_actkind_t dta_kind; -+ uint16_t dta_intuple; -+ uint32_t dta_refcnt; -+ struct dtrace_difo *dta_difo; -+ struct dtrace_recdesc dta_rec; -+ struct dtrace_action *dta_prev; -+ struct dtrace_action *dta_next; -+}; -+ -+struct dtrace_ecb; -+ -+struct dtrace_probe { -+ dtrace_id_t dtpr_id; -+ struct dtrace_ecb *dtpr_ecb; -+ struct dtrace_ecb *dtpr_ecb_last; -+ void *dtpr_arg; -+ dtrace_cacheid_t dtpr_predcache; -+ int dtpr_aframes; -+ struct dtrace_provider *dtpr_provider; -+ char *dtpr_mod; -+ char *dtpr_func; -+ char *dtpr_name; -+ struct dtrace_probe *dtpr_nextmod; -+ struct dtrace_probe *dtpr_prevmod; -+ struct dtrace_probe *dtpr_nextfunc; -+ struct dtrace_probe *dtpr_prevfunc; -+ struct dtrace_probe *dtpr_nextname; -+ struct dtrace_probe *dtpr_prevname; -+ dtrace_genid_t dtpr_gen; -+}; -+ -+struct dtrace_state; -+ -+struct dtrace_ecb { -+ dtrace_epid_t dte_epid; -+ uint32_t dte_alignment; -+ size_t dte_needed; -+ size_t dte_size; -+ struct dtrace_predicate *dte_predicate; -+ struct dtrace_action *dte_action; -+ struct dtrace_ecb *dte_next; -+ struct dtrace_state *dte_state; -+ uint32_t dte_cond; -+ struct dtrace_probe *dte_probe; -+ struct dtrace_action *dte_action_last; -+ uint64_t dte_uarg; -+}; -+ -+struct dtrace_key { -+ uint64_t dttk_value; -+ uint64_t dttk_size; -+}; -+ -+struct dtrace_tuple { -+ uint32_t dtt_nkeys; -+ uint32_t dtt_pad; -+ struct dtrace_key dtt_key[1]; -+}; -+ -+struct dtrace_dynvar { -+ uint64_t dtdv_hashval; -+ struct dtrace_dynvar *dtdv_next; -+ void *dtdv_data; -+ struct dtrace_tuple dtdv_tuple; -+}; -+ -+struct dtrace_dstate_percpu { -+ struct dtrace_dynvar *dtdsc_free; -+ struct dtrace_dynvar *dtdsc_dirty; -+ struct dtrace_dynvar *dtdsc_rinsing; -+ struct dtrace_dynvar *dtdsc_clean; -+ uint64_t dtdsc_drops; -+ uint64_t dtdsc_dirty_drops; -+ uint64_t dtdsc_rinsing_drops; -+#ifdef CONFIG_64BIT -+ uint64_t dtdsc_pad; -+#else -+ uint64_t dtdsc_pad[2]; -+#endif -+}; -+ -+struct dtrace_dynhash { -+ struct dtrace_dynvar *dtdh_chain; -+ uintptr_t dtdh_lock; -+#ifdef CONFIG_64BIT -+ uintptr_t dtdh_pad[6]; -+#else -+ uintptr_t dtdh_pad[14]; -+#endif -+}; -+ -+struct dtrace_dstate { -+ void *dtds_base; -+ size_t dtds_size; -+ size_t dtds_hashsize; -+ size_t dtds_chunksize; -+ struct dtrace_dynhash *dtds_hash; -+ enum dtrace_dstate_state dtds_state; -+ struct dtrace_dstate_percpu *dtds_percpu; -+}; -+ -+struct dtrace_vstate { -+ struct dtrace_state *dtvs_state; -+ struct dtrace_statvar **dtvs_globals; -+ int dtvs_nglobals; -+ struct dtrace_difv *dtvs_tlocals; -+ int dtvs_ntlocals; -+ struct dtrace_statvar **dtvs_locals; -+ int dtvs_nlocals; -+ struct dtrace_dstate dtvs_dynvars; -+}; -+ -+/* -+ * DTrace Machine State -+ * -+ * In the process of processing a fired probe, DTrace needs to track and/or -+ * cache some per-CPU state associated with that particular firing. This is -+ * state that is always discarded after the probe firing has completed, and -+ * much of it is not specific to any DTrace consumer, remaining valid across -+ * all ECBs. This state is tracked in the dtrace_mstate structure. -+ */ -+ -+struct dtrace_mstate { -+ uintptr_t dtms_scratch_base; -+ uintptr_t dtms_scratch_ptr; -+ size_t dtms_scratch_size; -+ uint32_t dtms_present; -+ uint64_t dtms_arg[7]; -+ dtrace_epid_t dtms_epid; -+ ktime_t dtms_timestamp; -+ int dtms_stackdepth; -+ int dtms_ustackdepth; -+ struct dtrace_probe *dtms_probe; -+ uintptr_t dtms_caller; -+ uint64_t dtms_ucaller; -+ int dtms_ipl; -+ int dtms_fltoffs; -+ uintptr_t dtms_strtok; -+ uint32_t dtms_access; -+ struct dtrace_difo *dtms_difo; -+}; -+ -+struct dtrace_buffer { -+ uint64_t dtb_offset; -+ uint64_t dtb_size; -+ uint32_t dtb_flags; -+ uint32_t dtb_drops; -+ caddr_t dtb_tomax; -+ caddr_t dtb_xamot; -+ uint32_t dtb_xamot_flags; -+ uint32_t dtb_xamot_drops; -+ uint64_t dtb_xamot_offset; -+ uint32_t dtb_errors; -+ uint32_t dtb_xamot_errors; -+#ifndef CONFIG_64BIT -+ uint64_t dtb_pad1; -+#endif -+}; -+ -+struct dtrace_speculation { -+ enum dtrace_speculation_state dtsp_state; -+ int dtsp_cleaning; -+ struct dtrace_buffer *dtsp_buffer; -+}; -+ -+struct dtrace_aggregation { -+ struct dtrace_action dtag_action; -+ dtrace_aggid_t dtag_id; -+ struct dtrace_ecb *dtag_ecb; -+ struct dtrace_action *dtag_first; -+ uint32_t dtag_base; -+ uint8_t dtag_hasarg; -+ uint64_t dtag_initial; -+ void (*dtag_aggregate)(uint64_t *, uint64_t, uint64_t); -+}; -+ -+struct dtrace_cred { -+ const struct cred *dcr_cred; -+ uint8_t dcr_destructive; -+ uint8_t dcr_visible; -+ uint16_t dcr_action; -+}; -+ -+struct dtrace_state { -+ dev_t dts_dev; -+ int dts_necbs; -+ struct dtrace_ecb **dts_ecbs; -+ dtrace_epid_t dts_epid; -+ size_t dts_needed; -+ struct dtrace_state *dts_anon; -+ enum dtrace_activity dts_activity; -+ struct dtrace_vstate dts_vstate; -+ struct dtrace_buffer *dts_buffer; -+ struct dtrace_buffer *dts_aggbuffer; -+ struct dtrace_speculation *dts_speculations; -+ int dts_nspeculations; -+ struct idr dts_agg_idr; -+ int dts_naggs; -+ uint64_t dts_errors; -+ uint32_t dts_speculations_busy; -+ uint32_t dts_speculations_unavail; -+ uint32_t dts_stkstroverflows; -+ uint32_t dts_dblerrors; -+ uint32_t dts_reserve; -+ cyclic_id_t dts_cleaner; -+ cyclic_id_t dts_deadman; -+ ktime_t dts_laststatus; -+ ktime_t dts_alive; -+ char dts_speculates; -+ char dts_destructive; -+ int dts_nformats; -+ char **dts_formats; -+ dtrace_optval_t dts_options[DTRACEOPT_MAX]; -+ struct dtrace_cred dts_cred; -+ size_t dts_nretained; -+}; -+ -+struct dtrace_enabling { -+ struct dtrace_ecbdesc **dten_desc; -+ int dten_ndesc; -+ int dten_maxdesc; -+ struct dtrace_vstate *dten_vstate; -+ dtrace_genid_t dten_probegen; -+ struct dtrace_ecbdesc *dten_current; -+ int dten_error; -+ int dten_primed; -+ struct dtrace_enabling *dten_prev; -+ struct dtrace_enabling *dten_next; -+}; -+ -+typedef int dtrace_probekey_f(const char *, const char *, int); -+ -+struct dtrace_probekey { -+ const char *dtpk_prov; -+ dtrace_probekey_f *dtpk_pmatch; -+ const char *dtpk_mod; -+ dtrace_probekey_f *dtpk_mmatch; -+ const char *dtpk_func; -+ dtrace_probekey_f *dtpk_fmatch; -+ const char *dtpk_name; -+ dtrace_probekey_f *dtpk_nmatch; -+ dtrace_id_t dtpk_id; -+}; -+ -+struct dtrace_hashbucket { -+ struct dtrace_hashbucket *dthb_next; -+ struct dtrace_probe *dthb_chain; -+ int dthb_len; -+}; -+ -+struct dtrace_hash { -+ struct dtrace_hashbucket **dth_tab; -+ int dth_size; -+ int dth_mask; -+ int dth_nbuckets; -+ uintptr_t dth_nextoffs; -+ uintptr_t dth_prevoffs; -+ uintptr_t dth_stroffs; -+}; -+ -+/* -+ * DTrace supports safe loads from probe context; if the address turns out to -+ * be invalid, a bit will be set by the kernel indicating that DTrace -+ * encountered a memory error, and DTrace will propagate the error to the user -+ * accordingly. However, there may exist some regions of memory in which an -+ * arbitrary load can change system state, and from which it is impossible to -+ * recover from such a load after it has been attempted. Examples of this may -+ * include memory in which programmable I/O registers are mapped (for which a -+ * read may have some implications for the device) or (in the specific case of -+ * UltraSPARC-I and -II) the virtual address hole. The platform is required -+ * to make DTrace aware of these toxic ranges; DTrace will then check that -+ * target addresses are not in a toxic range before attempting to issue a -+ * safe load. -+ */ -+struct dtrace_toxrange { -+ uintptr_t dtt_base; -+ uintptr_t dtt_limit; -+}; -+ -+/* -+ * DTrace Helper Implementation -+ * -+ * A description of the helper architecture may be found in <linux/dtrace.h>. -+ * Each process contains a pointer to its helpers in its dtrace_helpers -+ * member. This is a pointer to a dtrace_helpers structure, which contains an -+ * array of pointers to dtrace_helper structures, helper variable state (shared -+ * among a process's helpers) and a generation count. (The generation count is -+ * used to provide an identifier when a helper is added so that it may be -+ * subsequently removed.) The dtrace_helper structure is self-explanatory, -+ * containing pointers to the objects needed to execute the helper. Note that -+ * helpers are _duplicated_ across fork(2), and destroyed on exec(2). No more -+ * than dtrace_helpers_max are allowed per-process. -+ */ -+struct dtrace_helper_action { -+ int dtha_generation; /* helper action generation */ -+ int dtha_nactions; /* number of actions */ -+ struct dtrace_difo *dtha_predicate; /* helper action predicate */ -+ struct dtrace_difo **dtha_actions; /* array of actions */ -+ struct dtrace_helper_action *dtha_next; /* next helper action */ -+}; -+ -+struct dtrace_helper_provider { -+ int dthp_generation; /* helper provider generation */ -+ uint32_t dthp_ref; /* reference count */ -+ struct dof_helper dthp_prov; /* DOF w/ provider and probes */ -+}; -+ -+struct dtrace_helpers { -+ struct dtrace_helper_action **dthps_actions; /* helper actions array */ -+ struct dtrace_vstate dthps_vstate; /* helper action var. state */ -+ struct dtrace_helper_provider **dthps_provs; /* providers array */ -+ uint_t dthps_nprovs; /* count of providers */ -+ uint_t dthps_maxprovs; /* provider array size */ -+ int dthps_generation; /* current generation */ -+ pid_t dthps_pid; /* pid of associated proc */ -+ int dthps_deferred; /* helper in deferred list */ -+ struct dtrace_helpers *dthps_next; /* next pointer */ -+ struct dtrace_helpers *dthps_prev; /* prev pointer */ -+}; -+ -+/* -+ * DTrace Helper Action Tracing -+ * -+ * Debugging helper actions can be arduous. To ease the development and -+ * debugging of helpers, DTrace contains a tracing-framework-within-a-tracing- -+ * framework: helper tracing. If dtrace_helptrace_enabled is non-zero (which -+ * it is by default on DEBUG kernels), all helper activity will be traced to a -+ * global, in-kernel ring buffer. Each entry includes a pointer to the specific -+ * helper, the location within the helper, and a trace of all local variables. -+ * The ring buffer may be displayed in a human-readable format with the -+ * ::dtrace_helptrace mdb(1) dcmd. -+ */ -+struct dtrace_helptrace { -+ struct dtrace_helper_action *dtht_helper; /* helper action */ -+ int dtht_where; /* where in helper action */ -+ int dtht_nlocals; /* number of locals */ -+ int dtht_fault; /* type of fault (if any) */ -+ int dtht_fltoffs; /* DIF offset */ -+ uint64_t dtht_illval; /* faulting value */ -+ uint64_t dtht_locals[1]; /* local variables */ -+}; -+ -+extern struct mutex dtrace_lock; -+extern struct mutex dtrace_provider_lock; -+extern struct mutex dtrace_meta_lock; -+ -+extern dtrace_genid_t dtrace_probegen; -+extern struct kmem_cache *dtrace_probe_cachep; -+ -+extern struct dtrace_pops dtrace_provider_ops; -+ -+extern int dtrace_opens; -+extern int dtrace_err_verbose; -+ -+extern struct dtrace_toxrange *dtrace_toxrange; -+extern int dtrace_toxranges; -+ -+extern void dtrace_nullop(void); -+extern int dtrace_enable_nullop(void); -+extern int dtrace_istoxic(uintptr_t, size_t); -+ -+/* -+ * DTrace Probe Context Functions -+ */ -+ -+extern void dtrace_panic(const char *, ...); -+extern int dtrace_assfail(const char *, const char *, int); -+extern void dtrace_aggregate_min(uint64_t *, uint64_t, uint64_t); -+extern void dtrace_aggregate_max(uint64_t *, uint64_t, uint64_t); -+extern void dtrace_aggregate_quantize(uint64_t *, uint64_t, uint64_t); -+extern void dtrace_aggregate_lquantize(uint64_t *, uint64_t, uint64_t); -+extern void dtrace_aggregate_llquantize(uint64_t *, uint64_t, uint64_t); -+extern void dtrace_aggregate_avg(uint64_t *, uint64_t, uint64_t); -+extern void dtrace_aggregate_stddev(uint64_t *, uint64_t, uint64_t); -+extern void dtrace_aggregate_count(uint64_t *, uint64_t, uint64_t); -+extern void dtrace_aggregate_sum(uint64_t *, uint64_t, uint64_t); -+extern void dtrace_aggregate(struct dtrace_aggregation *, -+ struct dtrace_buffer *, -+ intptr_t, struct dtrace_buffer *, uint64_t, -+ uint64_t); -+ -+/* -+ * DTrace Probe Hashing Functions -+ */ -+ -+extern struct dtrace_hash *dtrace_hash_create(uintptr_t, uintptr_t, uintptr_t); -+extern void dtrace_hash_destroy(struct dtrace_hash *); -+extern int dtrace_hash_add(struct dtrace_hash *, struct dtrace_probe *); -+extern struct dtrace_probe *dtrace_hash_lookup(struct dtrace_hash *, -+ struct dtrace_probe *); -+extern int dtrace_hash_collisions(struct dtrace_hash *, struct dtrace_probe *); -+extern void dtrace_hash_remove(struct dtrace_hash *, struct dtrace_probe *); -+ -+/* -+ * DTrace Speculation Functions -+ */ -+extern int dtrace_speculation(struct dtrace_state *); -+extern void dtrace_speculation_commit(struct dtrace_state *, processorid_t, -+ dtrace_specid_t); -+extern void dtrace_speculation_discard(struct dtrace_state *, processorid_t, -+ dtrace_specid_t); -+extern void dtrace_speculation_clean(struct dtrace_state *); -+extern struct dtrace_buffer *dtrace_speculation_buffer(struct dtrace_state *, -+ processorid_t, -+ dtrace_specid_t); -+ -+/* -+ * DTrace Non-Probe Context Utility Functions -+ */ -+ -+/* -+ * DTrace Matching Functions -+ */ -+extern struct dtrace_hash *dtrace_bymod; -+extern struct dtrace_hash *dtrace_byfunc; -+extern struct dtrace_hash *dtrace_byname; -+ -+extern int dtrace_match_priv(const struct dtrace_probe *, uint32_t, kuid_t); -+extern int dtrace_match_probe(const struct dtrace_probe *, -+ const struct dtrace_probekey *, uint32_t, -+ kuid_t); -+extern int dtrace_match_glob(const char *, const char *, int); -+extern int dtrace_match_string(const char *, const char *, int); -+extern int dtrace_match_nul(const char *, const char *, int); -+extern int dtrace_match_nonzero(const char *, const char *, int); -+extern int dtrace_match(const struct dtrace_probekey *, uint32_t, kuid_t, -+ int (*matched)(struct dtrace_probe *, void *), void *); -+extern void dtrace_probekey(const struct dtrace_probedesc *, -+ struct dtrace_probekey *); -+ -+/* -+ * DTrace Provider-to-Framework API Functions -+ */ -+ -+extern struct dtrace_provider *dtrace_provider; -+extern struct dtrace_meta *dtrace_meta_pid; -+extern struct dtrace_helpers *dtrace_deferred_pid; -+ -+/* -+ * DTrace Privilege Check Functions -+ */ -+extern int dtrace_priv_proc_destructive(struct dtrace_state *); -+extern int dtrace_priv_proc_control(struct dtrace_state *); -+extern int dtrace_priv_proc(struct dtrace_state *); -+extern int dtrace_priv_kernel(struct dtrace_state *); -+ -+/* -+ * DTrace Probe Management Functions -+ */ -+ -+extern int dtrace_probe_enable(const struct dtrace_probedesc *, -+ struct dtrace_enabling *); -+extern void dtrace_probe_description(const struct dtrace_probe *, -+ struct dtrace_probedesc *); -+extern void dtrace_probe_provide(struct dtrace_probedesc *, -+ struct dtrace_provider *); -+extern int dtrace_probe_init(void); -+extern void dtrace_probe_exit(void); -+extern void dtrace_probe_remove_id(dtrace_id_t); -+extern struct dtrace_probe *dtrace_probe_lookup_id(dtrace_id_t); -+extern struct dtrace_probe *dtrace_probe_get_next(dtrace_id_t *); -+extern int dtrace_probe_for_each(int (*)(int, void *, void *), void *); -+ -+/* -+ * DTrace Kernel Hooks -+ */ -+extern void (*dtrace_modload)(struct module *); -+extern void (*dtrace_modunload)(struct module *); -+ -+extern uint8_t dtrace_load8(uintptr_t); -+extern uint16_t dtrace_load16(uintptr_t); -+extern uint32_t dtrace_load32(uintptr_t); -+extern uint64_t dtrace_load64(uintptr_t); -+#ifdef CONFIG_64BIT -+#define dtrace_loadptr dtrace_load64 -+#else -+#define dtrace_loadptr dtrace_load32 -+#endif -+ -+ -+extern void dtrace_bzero(void *, size_t); -+ -+extern int dtrace_vcanload(void *, struct dtrace_diftype *, -+ struct dtrace_mstate *, -+ struct dtrace_vstate *); -+extern int dtrace_canload(uintptr_t, size_t, struct dtrace_mstate *, -+ struct dtrace_vstate *); -+ -+extern int dtrace_difo_validate(struct dtrace_difo *, struct dtrace_vstate *, -+ uint_t, const struct cred *); -+extern int dtrace_difo_validate_helper(struct dtrace_difo *); -+extern int dtrace_difo_cacheable(struct dtrace_difo *); -+extern void dtrace_difo_hold(struct dtrace_difo *); -+extern void dtrace_difo_init(struct dtrace_difo *, struct dtrace_vstate *); -+extern struct dtrace_difo *dtrace_difo_duplicate(struct dtrace_difo *, -+ struct dtrace_vstate *); -+extern void dtrace_difo_release(struct dtrace_difo *, struct dtrace_vstate *); -+ -+extern uint64_t dtrace_vtime_references; -+ -+extern uint64_t dtrace_dif_emulate(struct dtrace_difo *, -+ struct dtrace_mstate *, -+ struct dtrace_vstate *, -+ struct dtrace_state *); -+ -+/* -+ * DTrace Format Functions -+ */ -+extern uint16_t dtrace_format_add(struct dtrace_state *, char *); -+extern void dtrace_format_remove(struct dtrace_state *, uint16_t); -+extern void dtrace_format_destroy(struct dtrace_state *); -+ -+/* -+ * DTrace Predicate Functions -+ */ -+extern struct dtrace_predicate *dtrace_predicate_create(struct dtrace_difo *); -+extern void dtrace_predicate_hold(struct dtrace_predicate *); -+extern void dtrace_predicate_release(struct dtrace_predicate *, -+ struct dtrace_vstate *); -+ -+/* -+ * DTrace Action Description Functions -+ */ -+extern struct dtrace_actdesc *dtrace_actdesc_create(dtrace_actkind_t, uint32_t, -+ uint64_t, uint64_t); -+extern void dtrace_actdesc_hold(struct dtrace_actdesc *); -+extern void dtrace_actdesc_release(struct dtrace_actdesc *, -+ struct dtrace_vstate *); -+ -+/* -+ * DTrace Helper Functions -+ */ -+extern void dtrace_helpers_destroy(struct task_struct *); -+extern void dtrace_helpers_duplicate(struct task_struct *, -+ struct task_struct *); -+extern uint64_t dtrace_helper(int, struct dtrace_mstate *, -+ struct dtrace_state *, -+ uint64_t, uint64_t); -+ -+/* -+ * DTrace ECB Functions -+ */ -+extern struct dtrace_ecb *dtrace_ecb_create_cache; -+ -+extern int dtrace_ecb_create_enable(struct dtrace_probe *, void *); -+extern void dtrace_ecb_disable(struct dtrace_ecb *); -+extern void dtrace_ecb_destroy(struct dtrace_ecb *); -+extern void dtrace_ecb_resize(struct dtrace_ecb *); -+extern int dtrace_ecb_enable(struct dtrace_ecb *); -+extern struct dtrace_ecb *dtrace_epid2ecb(struct dtrace_state *, -+ dtrace_epid_t); -+extern struct dtrace_aggregation *dtrace_aggid2agg(struct dtrace_state *, -+ dtrace_aggid_t); -+ -+/* -+ * DTrace Buffer Functions -+ * -+ * DTrace Buffers -+ * -+ * Principal buffers, aggregation buffers, and speculative buffers are all -+ * managed with the dtrace_buffer structure. By default, this structure -+ * includes twin data buffers -- dtb_tomax and dtb_xamot -- that serve as the -+ * active and passive buffers, respectively. For speculative buffers, -+ * dtb_xamot will be NULL; for "ring" and "fill" buffers, dtb_xamot will point -+ * to a scratch buffer. For all buffer types, the dtrace_buffer structure is -+ * always allocated on a per-CPU basis; a single dtrace_buffer structure is -+ * never shared among CPUs. (That is, there is never true sharing of the -+ * dtrace_buffer structure; to prevent false sharing of the structure, it must -+ * always be aligned to the coherence granularity -- generally 64 bytes.) -+ * -+ * One of the critical design decisions of DTrace is that a given ECB always -+ * stores the same quantity and type of data. This is done to assure that the -+ * only metadata required for an ECB's traced data is the EPID. That is, from -+ * the EPID, the consumer can determine the data layout. (The data buffer -+ * layout is shown schematically below.) By assuring that one can determine -+ * data layout from the EPID, the metadata stream can be separated from the -+ * data stream -- simplifying the data stream enormously. -+ * -+ * base of data buffer ---> +------+--------------------+------+ -+ * | EPID | data | EPID | -+ * +------+--------+------+----+------+ -+ * | data | EPID | data | -+ * +---------------+------+-----------+ -+ * | data, cont. | -+ * +------+--------------------+------+ -+ * | EPID | data | | -+ * +------+--------------------+ | -+ * | || | -+ * | || | -+ * | \/ | -+ * : : -+ * . . -+ * . . -+ * . . -+ * : : -+ * | | -+ * limit of data buffer ---> +----------------------------------+ -+ * -+ * When evaluating an ECB, dtrace_probe() determines if the ECB's needs of the -+ * principal buffer (both scratch and payload) exceed the available space. If -+ * the ECB's needs exceed available space (and if the principal buffer policy -+ * is the default "switch" policy), the ECB is dropped, the buffer's drop count -+ * is incremented, and processing advances to the next ECB. If the ECB's needs -+ * can be met with the available space, the ECB is processed, but the offset in -+ * the principal buffer is only advanced if the ECB completes processing -+ * without error. -+ * -+ * When a buffer is to be switched (either because the buffer is the principal -+ * buffer with a "switch" policy or because it is an aggregation buffer), a -+ * cross call is issued to the CPU associated with the buffer. In the cross -+ * call context, interrupts are disabled, and the active and the inactive -+ * buffers are atomically switched. This involves switching the data pointers, -+ * copying the various state fields (offset, drops, errors, etc.) into their -+ * inactive equivalents, and clearing the state fields. Because interrupts are -+ * disabled during this procedure, the switch is guaranteed to appear atomic to -+ * dtrace_probe(). -+ * -+ * DTrace Ring Buffering -+ * -+ * To process a ring buffer correctly, one must know the oldest valid record. -+ * Processing starts at the oldest record in the buffer and continues until -+ * the end of the buffer is reached. Processing then resumes starting with -+ * the record stored at offset 0 in the buffer, and continues until the -+ * youngest record is processed. If trace records are of a fixed-length, -+ * determining the oldest record is trivial: -+ * -+ * - If the ring buffer has not wrapped, the oldest record is the record -+ * stored at offset 0. -+ * -+ * - If the ring buffer has wrapped, the oldest record is the record stored -+ * at the current offset. -+ * -+ * With variable length records, however, just knowing the current offset -+ * doesn't suffice for determining the oldest valid record: assuming that one -+ * allows for arbitrary data, one has no way of searching forward from the -+ * current offset to find the oldest valid record. (That is, one has no way -+ * of separating data from metadata.) It would be possible to simply refuse to -+ * process any data in the ring buffer between the current offset and the -+ * limit, but this leaves (potentially) an enormous amount of otherwise valid -+ * data unprocessed. -+ * -+ * To effect ring buffering, we track two offsets in the buffer: the current -+ * offset and the _wrapped_ offset. If a request is made to reserve some -+ * amount of data, and the buffer has wrapped, the wrapped offset is -+ * incremented until the wrapped offset minus the current offset is greater -+ * than or equal to the reserve request. This is done by repeatedly looking -+ * up the ECB corresponding to the EPID at the current wrapped offset, and -+ * incrementing the wrapped offset by the size of the data payload -+ * corresponding to that ECB. If this offset is greater than or equal to the -+ * limit of the data buffer, the wrapped offset is set to 0. Thus, the -+ * current offset effectively "chases" the wrapped offset around the buffer. -+ * Schematically: -+ * -+ * base of data buffer ---> +------+--------------------+------+ -+ * | EPID | data | EPID | -+ * +------+--------+------+----+------+ -+ * | data | EPID | data | -+ * +---------------+------+-----------+ -+ * | data, cont. | -+ * +------+---------------------------+ -+ * | EPID | data | -+ * current offset ---> +------+---------------------------+ -+ * | invalid data | -+ * wrapped offset ---> +------+--------------------+------+ -+ * | EPID | data | EPID | -+ * +------+--------+------+----+------+ -+ * | data | EPID | data | -+ * +---------------+------+-----------+ -+ * : : -+ * . . -+ * . ... valid data ... . -+ * . . -+ * : : -+ * +------+-------------+------+------+ -+ * | EPID | data | EPID | data | -+ * +------+------------++------+------+ -+ * | data, cont. | leftover | -+ * limit of data buffer ---> +-------------------+--------------+ -+ * -+ * If the amount of requested buffer space exceeds the amount of space -+ * available between the current offset and the end of the buffer: -+ * -+ * (1) all words in the data buffer between the current offset and the limit -+ * of the data buffer (marked "leftover", above) are set to -+ * DTRACE_EPIDNONE -+ * -+ * (2) the wrapped offset is set to zero -+ * -+ * (3) the iteration process described above occurs until the wrapped offset -+ * is greater than the amount of desired space. -+ * -+ * The wrapped offset is implemented by (re-)using the inactive offset. -+ * In a "switch" buffer policy, the inactive offset stores the offset in -+ * the inactive buffer; in a "ring" buffer policy, it stores the wrapped -+ * offset. -+ * -+ * DTrace Scratch Buffering -+ * -+ * Some ECBs may wish to allocate dynamically-sized temporary scratch memory. -+ * To accommodate such requests easily, scratch memory may be allocated in -+ * the buffer beyond the current offset plus the needed memory of the current -+ * ECB. If there isn't sufficient room in the buffer for the requested amount -+ * of scratch space, the allocation fails and an error is generated. Scratch -+ * memory is tracked in the dtrace_mstate_t and is automatically freed when -+ * the ECB ceases processing. Note that ring buffers cannot allocate their -+ * scratch from the principal buffer -- lest they needlessly overwrite older, -+ * valid data. Ring buffers therefore have their own dedicated scratch buffer -+ * from which scratch is allocated. -+ */ -+ -+extern void dtrace_buffer_switch(struct dtrace_buffer *); -+extern void dtrace_buffer_activate(struct dtrace_state *); -+extern int dtrace_buffer_alloc(struct dtrace_buffer *, size_t, int, -+ processorid_t); -+extern void dtrace_buffer_drop(struct dtrace_buffer *); -+extern intptr_t dtrace_buffer_reserve(struct dtrace_buffer *, size_t, size_t, -+ struct dtrace_state *, -+ struct dtrace_mstate *); -+extern void dtrace_buffer_polish(struct dtrace_buffer *); -+extern void dtrace_buffer_free(struct dtrace_buffer *); -+ -+/* -+ * DTrace framework/probe data synchronization -+ * ------------------------------------------- -+ * -+ * The dtrace_sync() facility is used to synchronize global DTrace framework -+ * data with DTrace probe context. The framework updates data and then calls -+ * dtrace_sync(). dtrace_sync() loops until it observes all CPUs have been out -+ * of probe context at least once. This ensures all consumers are using the -+ * updated data. -+ * -+ * DTrace probes have several requirements. First DTrace probe context cannot -+ * block. DTrace probes execute with interrupts disabled. Locks cannot be -+ * acquired in DTrace probe context. A second requirement is that DTrace -+ * probes need to be as high performance as possible to minimize the effect of -+ * enabled probes. -+ * -+ * DTrace framework data changes have their own requirements. DTrace data -+ * changes/syncs are extremely infrequent compared to DTrace probe firings. -+ * Probes can be in commonly executed code. A good trade-off is to favor -+ * DTrace probe context performance over DTrace sync performance. -+ * -+ * To meet the above requirements, the DTrace data synchronization algorithm -+ * is lock-less. The DTrace probe path is wait-free. The DTrace probe path -+ * is memory-barrier-free in the common case to minimize probe effect. -+ * dtrace_probe has been made membar free in the common case by adding a read -+ * in dtrace_probe and adding an additional write and membar to dtrace_sync(). -+ * -+ * A simple algorithm is to have dtrace_probe set a flag for its CPU when -+ * entering DTrace probe context and clear the flag when it exits DTrace probe -+ * context. A producer of DTrace framework data checks the flag to detect and -+ * synchronize with probe context. Unfortunately memory ordering issues -+ * complicate the implementation. Memory barriers are required in probe -+ * context for this simple approach to work. -+ * -+ * A simple implementation to sync with one CPU that works with any memory -+ * ordering model is: -+ * -+ * DTrace probe: -+ * 1. CPU->in_probe_context = B_TRUE; -+ * 2. dtrace_membar_enter()// membar #StoreLoad|#StoreStore -+ * 3. access framework shared data// critical section -+ * 4. dtrace_membar_exit()// membar #LoadStore|#StoreStore -+ * 5. CPU->in_probe_context = B_FALSE; -+ * -+ * DTrace framework dtrace_sync: -+ * 0. update framework shared data -+ * 1. dtrace_membar_enter()// membar #StoreLoad|#StoreStore -+ * 2. while (CPU->in_probe_context == B_TRUE) -+ * 3. spin -+ * 4. dtrace_membar_exit()// membar #LoadStore|#StoreStore -+ * 5. produce shared dtrace data -+ * -+ * A note on memory ordering -+ * ------------------------- -+ * -+ * dtrace_membar_enter() guarantees later loads cannot complete before earlier -+ * stores, and it guarantees later stores cannot complete before earlier stores. -+ * dtrace_membar_enter() is, in SPARC parlance, a membar #StoreLoad|#StoreStore. -+ * -+ * dtrace_membar_exit() guarantees later stores cannot complete before earlier -+ * loads, and it guarantees later stores cannot complete before earlier stores. -+ * dtrace_membar_exit() is, in SPARC parlance, a membar #LoadStore|#StoreStore. -+ * -+ * Please see the SPARC and Intel processor guides on memory ordering. -+ * All sun4v and Fujitsu processors are TSO (Total Store Order). Modern -+ * supported Intel and AMD processors have similar load and store ordering -+ * to SPARC. All processors currently supported by Solaris have these memory -+ * ordering properties: -+ * 1) Loads are ordered with respect to earlier loads. -+ * 2) Stores are ordered with respect to earlier stores. -+ * 3a) SPARC Atomic load-store behaves as if it were followed by a -+ * MEMBAR #LoadLoad, #LoadStore, and #StoreStore. -+ * 3b) X86 Atomic operations serialize load and store. -+ * 4) Stores cannot bypass earlier loads. -+ * -+ * The above implementation details allow the membars to be simplified thus: -+ * A) dtrace_membar_enter() can be reduced to "membar #StoreLoad" on sparc. -+ * See property number 4 above. -+ * Since dtrace_membar_enter() is an atomic operation on x86, it cannot be -+ * reduced further. -+ * B) dtrace_membar_exit() becomes a NOP on both SPARC and x86. -+ * See properties 2 and 4. -+ * -+ * -+ * Elimination of membar #StoreLoad from dtrace probe context -+ * ---------------------------------------------------------- -+ * -+ * Furthermore it is possible to eliminate all memory barriers from the common -+ * dtrace_probe() entry case. The only membar needed in dtrace_probe is there -+ * to prevent Loads of global DTrace framework data from passing the Store to -+ * the "in_probe_context" flag (i.e. the dtrace_membar_enter()). -+ * A Load at the beginning of the algorithm is also ordered with these later -+ * Loads and Stores: the membar #StoreLoad can be replaced with a early Load of -+ * a "sync_request" flag and a conditional branch on the flag value. -+ * -+ * dtrace_sync() first Stores to the "sync_request" flag, and dtrace_probe() -+ * starts by Loading the flag. This Load in dtrace_probe() of "sync_request" -+ * is ordered with its later Store to the "in_probe_context" flag and -+ * dtrace_probe's later Loads of DTrace framework data. dtrace_probe() only -+ * needs a membar #StoreLoad iff the "sync_request" flag is set. -+ * -+ * Optimized Synchronization Algorithm -+ * ----------------------------------- -+ * -+ * DTrace probe: -+ * + 1a. request_flag = CPU->sync_request // Load -+ * 1b. CPU->in_probe_context = B_TRUE // Store -+ * + 2. if request_flag > 0 -+ * dtrace_membar_enter() // membar #StoreLoad -+ * 3. access framework shared data // critical section -+ * - -+ * 5. CPU->in_probe_context = B_FALSE // Store -+ * -+ * DTrace framework dtrace_sync: -+ * + 1a. atomically add 1 to CPU->sync_request // Store and -+ * 1b. dtrace_membar_enter() // membar #StoreLoad -+ * 2. while (CPU->in_probe_context == B_TRUE) // Load -+ * 3. spin -+ * + 4a. atomically subtract 1 from CPU->sync_request // Load + Store -+ * - -+ * 5. produce shared dtrace data -+ * -+ * This algorithm has been proven correct by analysis of all interleaving -+ * scenarios of the above operations with the hardware memory ordering -+ * described above. -+ * -+ * The Load and store of the flag pair is very inexpensive. The cacheline with -+ * the flag pair is never accessed by a different CPU except by dtrace_sync. -+ * dtrace_sync is very uncommon compared to typical probe firings. The removal -+ * of membars from DTrace probe context at the expense of a Load and Store and -+ * a conditional branch is a good performance win. -+ * -+ * As implemented there is one pair of flags per CPU. The flags are in one -+ * cacheline; they could be split into two cachelines if dtrace_sync was more -+ * common. dtrace_sync loops over all NCPU sets of flags. dtrace_sync lazily -+ * only does one dtrace_membar_enter() (step 1b) after setting all NCPU -+ * sync_request flags. -+ * -+ * Sample aliasing could cause dtrace_sync() to always sample a CPU's -+ * in_probe_context flag when the CPU is in probe context even if the CPU -+ * left and returned to probe context one or more times since the last sample. -+ * cpuc_in_probe_ctxt is implemented as an even/odd counter instead of a -+ * boolean flag. cpuc_in_probe_ctxt is odd when in probe context and even -+ * when not in probe context. Probe context increments cpuc_in_probe_ctxt when -+ * entering and exiting. dtrace_probe() handles re-entry by not increment the -+ * counter for re-enterant entry and exit. -+ */ -+ -+/* -+ * dtrace_membar_exit() is a NOP on current SPARC and X86 hardware. -+ * It is defined as an inline asm statement to prevent the C optimizer from -+ * moving C statements around the membar. -+ */ -+#define dtrace_membar_exit() \ -+ __asm__ __volatile__("" ::: "memory") -+ -+/* -+ * dtrace_membar_enter() does not need an explicit membar #StoreStore because -+ * modern SPARC hardware is TSO: stores are ordered with other stores. -+ */ -+#define dtrace_membar_enter() \ -+ mb() -+ -+#define dtrace_safe_smt_pause() \ -+ cpu_relax() -+ -+/* -+ * Used by dtrace_probe() to flag entry to the the critical section. -+ * dtrace_probe() context may be consuming DTrace framework data. -+ * -+ * cpuc_in_probe_ctxt is odd when in probe context and even when not in -+ * probe context. The flag must not be incremented when re-entering from -+ * probe context. -+ */ -+#define DTRACE_SYNC_ENTER_CRITICAL(cookie, re_entry) \ -+{ \ -+ uint64_t requests; \ -+ uint64_t count; \ -+ \ -+ preempt_disable(); \ -+ local_irq_save(cookie); \ -+ \ -+ requests = atomic64_read(&this_cpu_core->cpuc_sync_requests); \ -+ \ -+ /* Increment flag iff it is even */ \ -+ count = atomic64_read(&this_cpu_core->cpuc_in_probe_ctx); \ -+ re_entry = count & 0x1; \ -+ atomic64_set(&this_cpu_core->cpuc_in_probe_ctx, count | 0x1); \ -+ ASSERT(DTRACE_SYNC_IN_CRITICAL(smp_processor_id())); \ -+ \ -+ /* \ -+ * Later Loads are ordered with respect to the Load of \ -+ * cpuc_sync_requests. The Load is also guaranteed to complete \ -+ * before the store to cpuc_in_probe_ctxt. Thus a member_enter \ -+ * is only needed when requests is not 0. This is very \ -+ * uncommon. \ -+ */ \ -+ if (requests > 0) { \ -+ dtrace_membar_enter(); \ -+ } \ -+} -+ -+/* -+ * Used by dtrace_probe() to flag exit from the critical section. -+ * dtrace_probe context is no longer using DTrace framework data. -+ */ -+#define DTRACE_SYNC_EXIT_CRITICAL(cookie, re_entry) \ -+{ \ -+ dtrace_membar_exit(); \ -+ ASSERT((re_entry | 0x1) == 0x1); \ -+ \ -+ /* \ -+ * flag must not be incremented when returning to probe context.\ -+ */ \ -+ atomic64_add(~re_entry & 0x1, &this_cpu_core->cpuc_in_probe_ctx); \ -+ ASSERT(re_entry == \ -+ (atomic64_read(&this_cpu_core->cpuc_in_probe_ctx) & 0x1)); \ -+ local_irq_restore(cookie); \ -+ preempt_enable(); \ -+} -+ -+/* -+ * Used by dtrace_sync to inform dtrace_probe it needs to synchronize with -+ * dtrace_sync. dtrace_probe consumes the cpuc_sync_requests flag to determine -+ * if it needs a membar_enter. Not called from probe context. -+ * -+ * cpuc_sync_requests must be updated atomically by dtrace_sync because there -+ * may be multiple dtrace_sync operations executing at the same time. -+ * cpuc_sync_requests is a simple count of the number of concurrent -+ * dtrace_sync requests. -+ */ -+#define DTRACE_SYNC_START(cpuid) \ -+{ \ -+ atomic64_add(1, &(per_cpu_core(cpuid))->cpuc_sync_requests); \ -+ ASSERT(atomic64_read(&per_cpu_core(cpuid)->cpuc_sync_requests) > 0); \ -+} -+ -+/* -+ * Used by dtrace_sync to flag dtrace_probe that it no longer needs to -+ * synchronize with dtrace_sync. Not called from probe context. -+ */ -+#define DTRACE_SYNC_END(cpuid) \ -+{ \ -+ atomic64_add(-1, &(per_cpu_core(cpuid))->cpuc_sync_requests); \ -+ ASSERT(atomic64_read(&per_cpu_core(cpuid)->cpuc_sync_requests) >= 0); \ -+} -+ -+/* -+ * The next two macros are used by dtrace_sync to check if the target CPU is in -+ * DTrace probe context. cpuc_in_probe_ctxt is a monotonically increasing -+ * count which dtrace_probe() increments when entering and exiting probe -+ * context. The flag is odd when in probe context, and even when not in probe -+ * context. -+ */ -+#define DTRACE_SYNC_IN_CRITICAL(cpuid) \ -+ (atomic64_read(&per_cpu_core(cpuid)->cpuc_in_probe_ctx) & 0x1) -+ -+/* -+ * Used to check if the target CPU left and then entered probe context again. -+ */ -+#define DTRACE_SYNC_CRITICAL_COUNT(cpuid) \ -+ (atomic64_read(&per_cpu_core(cpuid)->cpuc_in_probe_ctx)) -+ -+/* -+ * The next three macros are bitmap operations used by dtrace_sync to keep track -+ * of which CPUs it still needs to synchronize with. -+ */ -+#define DTRACE_SYNC_OUTSTANDING(cpuid, bitmap) \ -+ (cpumask_test_cpu(cpuid, bitmap) == 1) -+ -+#define DTRACE_SYNC_NEEDED(cpuid, bitmap) \ -+ cpumask_set_cpu(cpuid, bitmap) -+ -+#define DTRACE_SYNC_DONE(cpuid, bitmap) \ -+ cpumask_clear_cpu(cpuid, bitmap) -+ -+extern uint64_t dtrace_sync_sample_count; -+extern void dtrace_sync(void); -+ -+/* -+ * DTrace Enabling Functions -+ */ -+extern struct dtrace_enabling *dtrace_retained; -+extern dtrace_genid_t dtrace_retained_gen; -+ -+extern struct dtrace_enabling *dtrace_enabling_create(struct dtrace_vstate *); -+extern void dtrace_enabling_add(struct dtrace_enabling *, -+ struct dtrace_ecbdesc *); -+extern void dtrace_enabling_dump(struct dtrace_enabling *); -+extern void dtrace_enabling_destroy(struct dtrace_enabling *); -+extern int dtrace_enabling_retain(struct dtrace_enabling *); -+extern int dtrace_enabling_replicate(struct dtrace_state *, -+ struct dtrace_probedesc *, -+ struct dtrace_probedesc *); -+extern void dtrace_enabling_retract(struct dtrace_state *); -+extern int dtrace_enabling_match(struct dtrace_enabling *, int *); -+extern void dtrace_enabling_matchall(void); -+extern void dtrace_enabling_prime(struct dtrace_state *); -+extern void dtrace_enabling_provide(struct dtrace_provider *); -+ -+/* -+ * DOF functions -+ */ -+extern void dtrace_dof_error(struct dof_hdr *, const char *); -+extern struct dof_hdr *dtrace_dof_create(struct dtrace_state *); -+extern struct dof_hdr *dtrace_dof_copyin(void __user *, int *); -+extern struct dof_hdr *dtrace_dof_property(const char *); -+extern void dtrace_dof_destroy(struct dof_hdr *); -+extern int dtrace_dof_slurp(struct dof_hdr *, struct dtrace_vstate *, -+ const struct cred *, struct dtrace_enabling **, -+ uint64_t, int); -+extern int dtrace_dof_options(struct dof_hdr *, struct dtrace_state *); -+extern void dtrace_helper_provide(struct dof_helper *dhp, pid_t pid); -+extern int dtrace_helper_slurp(struct dof_hdr *, struct dof_helper *); -+extern int dtrace_helper_destroygen(int); -+ -+/* -+ * DTrace Anonymous Enabling Functions -+ */ -+struct dtrace_anon { -+ struct dtrace_state *dta_state; -+ struct dtrace_enabling *dta_enabling; -+ processorid_t dta_beganon; -+}; -+ -+extern struct dtrace_anon dtrace_anon; -+ -+extern struct dtrace_state *dtrace_anon_grab(void); -+extern void dtrace_anon_property(void); -+ -+/* -+ * DTrace Consumer State Functions -+ */ -+extern struct kmem_cache *dtrace_state_cachep; -+extern size_t dtrace_strsize_default; -+ -+extern ktime_t dtrace_deadman_timeout; -+extern int dtrace_destructive_disallow; -+ -+extern dtrace_id_t dtrace_probeid_begin; -+extern dtrace_id_t dtrace_probeid_end; -+extern dtrace_id_t dtrace_probeid_error; -+ -+extern struct dtrace_dynvar dtrace_dynhash_sink; -+ -+extern struct user_namespace *init_user_namespace; -+ -+extern int dtrace_dstate_init(struct dtrace_dstate *, size_t); -+extern void dtrace_dstate_fini(struct dtrace_dstate *); -+extern void dtrace_vstate_fini(struct dtrace_vstate *); -+extern struct dtrace_state *dtrace_state_create(struct file *); -+extern int dtrace_state_go(struct dtrace_state *, processorid_t *); -+extern int dtrace_state_stop(struct dtrace_state *, processorid_t *); -+extern int dtrace_state_option(struct dtrace_state *, dtrace_optid_t, -+ dtrace_optval_t); -+extern void dtrace_state_destroy(struct dtrace_state *); -+ -+/* -+ * DTrace Utility Functions -+ */ -+extern int dtrace_isglob(const char *); -+extern int dtrace_gmatch(const char *, const char *); -+extern void *dtrace_vzalloc(unsigned long); -+extern void *dtrace_vzalloc_try(unsigned long); -+extern char *dtrace_strdup(const char *); -+extern int dtrace_strncmp(char *, char *, size_t); -+extern size_t dtrace_strlen(const char *, size_t); -+extern int dtrace_badattr(const struct dtrace_attribute *); -+extern int dtrace_badname(const char *); -+extern void dtrace_cred2priv(const struct cred *, uint32_t *, kuid_t *); -+ -+extern void ctf_forceload(void); -+ -+#define dtrace_membar_producer() smp_wmb() -+#define dtrace_membar_consumer() smp_rmb() -+ -+typedef unsigned long dtrace_icookie_t; -+ -+extern struct mutex cpu_lock; -+ -+extern void dtrace_toxic_ranges(void (*)(uintptr_t, uintptr_t)); -+extern void dtrace_vpanic(const char *, va_list); -+extern int dtrace_getipl(void); -+ -+extern dtrace_icookie_t dtrace_interrupt_disable(void); -+extern void dtrace_interrupt_enable(dtrace_icookie_t); -+ -+typedef void (*dtrace_xcall_t)(void *); -+ -+extern void dtrace_xcall(processorid_t, dtrace_xcall_t, void *); -+ -+extern uintptr_t dtrace_fulword(void *); -+extern uint8_t dtrace_fuword8(void *); -+extern uint16_t dtrace_fuword16(void *); -+extern uint32_t dtrace_fuword32(void *); -+extern uint64_t dtrace_fuword64(void *); -+ -+extern void dtrace_probe_error(struct dtrace_state *, dtrace_epid_t, int, int, -+ int, uintptr_t); -+ -+extern void dtrace_getpcstack(uint64_t *, int, int, uint32_t *); -+extern void dtrace_getupcstack(uint64_t *, int); -+extern unsigned long dtrace_getufpstack(uint64_t *, uint64_t *, int); -+extern uintptr_t dtrace_getfp(void); -+extern uint64_t dtrace_getarg(int, int); -+extern int dtrace_getstackdepth(struct dtrace_mstate *, int); -+extern int dtrace_getustackdepth(void); -+extern ulong_t dtrace_getreg(struct task_struct *, uint_t); -+extern void dtrace_copyin(uintptr_t, uintptr_t, size_t, -+ volatile uint16_t *); -+extern void dtrace_copyout(uintptr_t, uintptr_t, size_t, -+ volatile uint16_t *); -+extern void dtrace_copyinstr(uintptr_t, uintptr_t, size_t, -+ volatile uint16_t *); -+extern void dtrace_copyoutstr(uintptr_t, uintptr_t, size_t, -+ volatile uint16_t *); -+ -+/* -+ * Plaforms that support a fast path to obtain the caller implement the -+ * dtrace_caller() function. -+ * -+ * The first argument is the number of frames that should be skipped when -+ * looking for a caller address. The 2nd argument is a dummy argument that -+ * is necessary for SPARC. -+ * -+ * On x86 this is effectively a NOP. -+ * -+ * On SPARC it is possible to retrieve the caller address from the register -+ * windows without flushing them to the stack. This involves performing -+ * explicit rotation of the register windows. Modification of the windowing -+ * mechanism state alters all %i, %o, and %l registers so we are can only use -+ * %g registers to store temporary data. -+ * -+ * On Linux a lot of %g registers are already allocated for specific purposes. -+ * Saving temporaries to the stack would be a violation of the fast path code -+ * logic. Therefore, the function prototype declares a 2nd argument that serves -+ * as a temporary value. A compiler will not expect that the value in %o1 -+ * will survive the call and therefore dtrace_caller() can use %o1 as a -+ * temporary register. -+ */ -+extern uintptr_t dtrace_caller(int, int); -+ -+extern void dtrace_copyin_arch(uintptr_t, uintptr_t, size_t, -+ volatile uint16_t *); -+extern void dtrace_copyinstr_arch(uintptr_t, uintptr_t, size_t, -+ volatile uint16_t *); -+ -+extern void pdata_init(struct dtrace_module *, struct module *); -+extern void pdata_cleanup(struct dtrace_module *, struct module *); -+ -+extern void debug_enter(char *); -+ -+#endif /* _LINUX_DTRACE_IMPL_H */ -diff --git a/include/dtrace/dtrace_impl_defines.h b/include/dtrace/dtrace_impl_defines.h -new file mode 100644 -index 000000000000..19b57f6188a0 ---- /dev/null -+++ b/include/dtrace/dtrace_impl_defines.h -@@ -0,0 +1,173 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Dynamic Tracing for Linux - Implementation Defines -+ * -+ * Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_IMPL_DEFINES_H -+#define _LINUX_DTRACE_IMPL_DEFINES_H -+ -+#include <linux/dtrace/universal.h> -+#include <linux/preempt.h> -+#include <asm/ptrace.h> -+ -+typedef typeof(instruction_pointer((struct pt_regs *)0)) pc_t; -+ -+enum dtrace_activity { -+ DTRACE_ACTIVITY_INACTIVE = 0, -+ DTRACE_ACTIVITY_WARMUP, -+ DTRACE_ACTIVITY_ACTIVE, -+ DTRACE_ACTIVITY_DRAINING, -+ DTRACE_ACTIVITY_COOLDOWN, -+ DTRACE_ACTIVITY_STOPPED, -+ DTRACE_ACTIVITY_KILLED -+}; -+ -+enum dtrace_dstate_state { -+ DTRACE_DSTATE_CLEAN = 0, -+ DTRACE_DSTATE_EMPTY, -+ DTRACE_DSTATE_DIRTY, -+ DTRACE_DSTATE_RINSING -+}; -+ -+enum dtrace_dynvar_op { -+ DTRACE_DYNVAR_ALLOC, -+ DTRACE_DYNVAR_NOALLOC, -+ DTRACE_DYNVAR_DEALLOC -+}; -+ -+#define DTRACE_MSTATE_ARGS 0x00000001 -+#define DTRACE_MSTATE_PROBE 0x00000002 -+#define DTRACE_MSTATE_EPID 0x00000004 -+#define DTRACE_MSTATE_TIMESTAMP 0x00000008 -+#define DTRACE_MSTATE_STACKDEPTH 0x00000010 -+#define DTRACE_MSTATE_CALLER 0x00000020 -+#define DTRACE_MSTATE_IPL 0x00000040 -+#define DTRACE_MSTATE_FLTOFFS 0x00000080 -+#define DTRACE_MSTATE_USTACKDEPTH 0x00000100 -+#define DTRACE_MSTATE_UCALLER 0x00000200 -+ -+#define DTRACE_PROBEKEY_MAXDEPTH 8 -+ -+enum dtrace_speculation_state { -+ DTRACESPEC_INACTIVE = 0, -+ DTRACESPEC_ACTIVE, -+ DTRACESPEC_ACTIVEONE, -+ DTRACESPEC_ACTIVEMANY, -+ DTRACESPEC_COMMITTING, -+ DTRACESPEC_COMMITTINGMANY, -+ DTRACESPEC_DISCARDING -+}; -+ -+#define DTRACE_HELPER_ACTION_USTACK 0 -+#define DTRACE_NHELPER_ACTIONS 1 -+ -+#define DTRACE_HELPTRACE_NEXT (-1) -+#define DTRACE_HELPTRACE_DONE (-2) -+#define DTRACE_HELPTRACE_ERR (-3) -+ -+#undef ASSERT -+#ifdef CONFIG_DT_DEBUG -+# define ASSERT(x) ((void)((x) || dtrace_assfail(#x, __FILE__, __LINE__))) -+#else -+# define ASSERT(x) ((void)0) -+#endif -+ -+/* -+ * DTrace Probe Hashing -+ */ -+ -+#define DTRACE_HASHNEXT(hash, probe) \ -+ (struct dtrace_probe **)((uintptr_t)(probe) + (hash)->dth_nextoffs) -+#define DTRACE_HASHPREV(hash, probe) \ -+ (struct dtrace_probe **)((uintptr_t)(probe) + (hash)->dth_prevoffs) -+ -+/* -+ * DTrace Probe Management -+ */ -+#define DTRACE_ANCHORED(probe) ((probe)->dtpr_func[0] != '\0') -+#define DTRACE_FLAGS2FLT(flags) \ -+ (((flags) & CPU_DTRACE_BADADDR) ? DTRACEFLT_BADADDR : \ -+ ((flags) & CPU_DTRACE_ILLOP) ? DTRACEFLT_ILLOP : \ -+ ((flags) & CPU_DTRACE_DIVZERO) ? DTRACEFLT_DIVZERO : \ -+ ((flags) & CPU_DTRACE_KPRIV) ? DTRACEFLT_KPRIV : \ -+ ((flags) & CPU_DTRACE_UPRIV) ? DTRACEFLT_UPRIV : \ -+ ((flags) & CPU_DTRACE_TUPOFLOW) ? DTRACEFLT_TUPOFLOW : \ -+ ((flags) & CPU_DTRACE_BADALIGN) ? DTRACEFLT_BADALIGN : \ -+ ((flags) & CPU_DTRACE_NOSCRATCH) ? DTRACEFLT_NOSCRATCH : \ -+ ((flags) & CPU_DTRACE_BADSTACK) ? DTRACEFLT_BADSTACK : \ -+ DTRACEFLT_UNKNOWN) -+ -+/* -+ * Test whether alloc_sz bytes will fit in the scratch region. We isolate -+ * alloc_sz on the righthand side of the comparison in order to avoid overflow -+ * or underflow in the comparison with it. This is simpler than the INRANGE -+ * check above, because we know that the dtms_scratch_ptr is valid in the -+ * range. Allocations of size zero are allowed. -+ */ -+#define DTRACE_INSCRATCH(mstate, alloc_sz) \ -+ ((mstate)->dtms_scratch_base + (mstate)->dtms_scratch_size - \ -+ (mstate)->dtms_scratch_ptr >= (alloc_sz)) -+ -+/* -+ * Buffering. -+ */ -+ -+#define DTRACEBUF_RING 0x0001 /* bufpolicy set to "ring" */ -+#define DTRACEBUF_FILL 0x0002 /* bufpolicy set to "fill" */ -+#define DTRACEBUF_NOSWITCH 0x0004 /* do not switch buffer */ -+#define DTRACEBUF_WRAPPED 0x0008 /* ring buffer has wrapped */ -+#define DTRACEBUF_DROPPED 0x0010 /* drops occurred */ -+#define DTRACEBUF_ERROR 0x0020 /* errors occurred */ -+#define DTRACEBUF_FULL 0x0040 /* "fill" buffer is full */ -+#define DTRACEBUF_CONSUMED 0x0080 /* buffer has been consumed */ -+#define DTRACEBUF_INACTIVE 0x0100 /* buffer is not yet active */ -+ -+#define DTRACE_STORE(type, tomax, offset, what) \ -+ do { \ -+ *((type *)((uintptr_t)(tomax) + (uintptr_t)(offset))) = (type)(what); \ -+ } while (0) -+ -+#define KERNELBASE (uintptr_t)_text -+ -+#ifdef CONFIG_DT_DEBUG_MUTEX -+# define real_mutex_lock(x) mutex_lock(x) -+# define real_mutex_unlock(x) mutex_unlock(x) -+ -+# define mutex_lock(x) do { \ -+ pr_debug("mutex_lock(%s) at %s::%d for %p (PID %d)\n", \ -+ __stringify(x), \ -+ __FILE__, __LINE__, current, \ -+ current ? current->pid : -1); \ -+ real_mutex_lock(x); \ -+ } while (0) -+# define mutex_unlock(x) do { \ -+ pr_debug("mutex_unlock(%s) at %s::%d for %p (PID %d)\n", \ -+ __stringify(x), \ -+ __FILE__, __LINE__, current, \ -+ current ? current->pid : -1); \ -+ real_mutex_unlock(x); \ -+ } while (0) -+#endif -+ -+#define MUTEX_HELD(lock) mutex_owned(lock) -+ -+#define PDATA(mp) ((struct dtrace_module *)mp->pdata) -+ -+#endif /* _LINUX_DTRACE_IMPL_DEFINES_H */ -diff --git a/include/dtrace/provider.h b/include/dtrace/provider.h -new file mode 100644 -index 000000000000..9eeb147f0363 ---- /dev/null -+++ b/include/dtrace/provider.h -@@ -0,0 +1,971 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Dynamic Tracing for Linux - Provider API -+ * -+ * Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _DTRACE_PROVIDER_H -+#define _DTRACE_PROVIDER_H -+ -+/* -+ * The following functions are implemented by the DTrace framework and are -+ * used to implement separate in-kernel DTrace providers. -+ * -+ * The provider API has two halves: the API that the providers consume from -+ * DTrace, and the API that providers make available to DTrace. -+ * -+ * 1 Framework-to-Provider API -+ * -+ * 1.1 Overview -+ * -+ * The Framework-to-Provider API is represented by the dtrace_pops structure -+ * that the provider passes to the framework when registering itself. This -+ * structure consists of the following members: -+ * -+ * dtps_provide() <-- Provide all probes, all modules -+ * dtps_provide_module() <-- Provide all probes in specified module -+ * dtps_enable() <-- Enable specified probe -+ * dtps_disable() <-- Disable specified probe -+ * dtps_suspend() <-- Suspend specified probe -+ * dtps_resume() <-- Resume specified probe -+ * dtps_getargdesc() <-- Get the argument description for args[X] -+ * dtps_getargval() <-- Get the value for an argX or args[X] variable -+ * dtps_usermode() <-- Find out if the probe was fired in user mode -+ * dtps_destroy() <-- Destroy all state associated with this probe -+ * dtps_destroy_module() <-- Destroy per-module data -+ * -+ * 1.2 void dtps_provide(void *arg, const struct dtrace_probedesc *spec) -+ * -+ * 1.2.1 Overview -+ * -+ * Called to indicate that the provider should provide all probes. If the -+ * specified description is non-NULL, dtps_provide() is being called because -+ * no probe matched a specified probe -- if the provider has the ability to -+ * create custom probes, it may wish to create a probe that matches the -+ * specified description. -+ * -+ * 1.2.2 Arguments and notes -+ * -+ * The first argument is the cookie as passed to dtrace_register(). The -+ * second argument is a pointer to a probe description that the provider may -+ * wish to consider when creating custom probes. The provider is expected to -+ * call back into the DTrace framework via dtrace_probe_create() to create -+ * any necessary probes. dtps_provide() may be called even if the provider -+ * has made available all probes; the provider should check the return value -+ * of dtrace_probe_create() to handle this case. Note that the provider need -+ * not implement both dtps_provide() and dtps_provide_module(); see -+ * "Arguments and Notes" for dtrace_register(), below. -+ * -+ * 1.2.3 Return value -+ * -+ * None. -+ * -+ * 1.2.4 Caller's context -+ * -+ * dtps_provide() is typically called from open() or ioctl() context, but may -+ * be called from other contexts as well. The DTrace framework is locked in -+ * such a way that providers may not register or unregister. This means that -+ * the provider may not call any DTrace API that affects its registration with -+ * the framework, including dtrace_register(), dtrace_unregister(), -+ * dtrace_invalidate(), and dtrace_condense(). However, the context is such -+ * that the provider may (and indeed, is expected to) call probe-related -+ * DTrace routines, including dtrace_probe_create(), dtrace_probe_lookup(), -+ * and dtrace_probe_arg(). -+ * -+ * 1.3 void dtps_provide_module(void *arg, struct modctl *mp) -+ * -+ * 1.3.1 Overview -+ * -+ * Called to indicate that the provider should provide all probes in the -+ * specified module. -+ * -+ * 1.3.2 Arguments and notes -+ * -+ * The first argument is the cookie as passed to dtrace_register(). The -+ * second argument is a pointer to a modctl structure that indicates the -+ * module for which probes should be created. -+ * -+ * 1.3.3 Return value -+ * -+ * None. -+ * -+ * 1.3.4 Caller's context -+ * -+ * dtps_provide_module() may be called from open() or ioctl() context, but -+ * may also be called from a module loading context. mod_lock is held, and -+ * the DTrace framework is locked in such a way that providers may not -+ * register or unregister. This means that the provider may not call any -+ * DTrace API that affects its registration with the framework, including -+ * dtrace_register(), dtrace_unregister(), dtrace_invalidate(), and -+ * dtrace_condense(). However, the context is such that the provider may (and -+ * indeed, is expected to) call probe-related DTrace routines, including -+ * dtrace_probe_create(), dtrace_probe_lookup(), and dtrace_probe_arg(). Note -+ * that the provider need not implement both dtps_provide() and -+ * dtps_provide_module(); see "Arguments and Notes" for dtrace_register(), -+ * below. -+ * -+ * 1.4 int dtps_enable(void *arg, dtrace_id_t id, void *parg) -+ * -+ * 1.4.1 Overview -+ * -+ * Called to enable the specified probe. -+ * -+ * 1.4.2 Arguments and notes -+ * -+ * The first argument is the cookie as passed to dtrace_register(). The -+ * second argument is the identifier of the probe to be enabled. The third -+ * argument is the probe argument as passed to dtrace_probe_create(). -+ * dtps_enable() will be called when a probe transitions from not being -+ * enabled at all to having one or more ECB. The number of ECBs associated -+ * with the probe may change without subsequent calls into the provider. -+ * When the number of ECBs drops to zero, the provider will be explicitly -+ * told to disable the probe via dtps_disable(). dtrace_probe() should never -+ * be called for a probe identifier that hasn't been explicitly enabled via -+ * dtps_enable(). -+ * -+ * 1.4.3 Return value -+ * -+ * On success, dtps_enable() should return 0. On failure, -1 should be -+ * returned. -+ * -+ * 1.4.4 Caller's context -+ * -+ * The DTrace framework is locked in such a way that it may not be called -+ * back into at all. cpu_lock is held. mod_lock is not held and may not -+ * be acquired. -+ * -+ * 1.5 void dtps_disable(void *arg, dtrace_id_t id, void *parg) -+ * -+ * 1.5.1 Overview -+ * -+ * Called to disable the specified probe. -+ * -+ * 1.5.2 Arguments and notes -+ * -+ * The first argument is the cookie as passed to dtrace_register(). The -+ * second argument is the identifier of the probe to be disabled. The third -+ * argument is the probe argument as passed to dtrace_probe_create(). -+ * dtps_disable() will be called when a probe transitions from being enabled -+ * to having zero ECBs. dtrace_probe() should never be called for a probe -+ * identifier that has been explicitly enabled via dtps_disable(). -+ * -+ * 1.5.3 Return value -+ * -+ * None. -+ * -+ * 1.5.4 Caller's context -+ * -+ * The DTrace framework is locked in such a way that it may not be called -+ * back into at all. cpu_lock is held. mod_lock is not held and may not -+ * be acquired. -+ * -+ * 1.6 void dtps_suspend(void *arg, dtrace_id_t id, void *parg) -+ * -+ * 1.6.1 Overview -+ * -+ * Called to suspend the specified enabled probe. This entry point is for -+ * providers that may need to suspend some or all of their probes when CPUs -+ * are being powered on or when the boot monitor is being entered for a -+ * prolonged period of time. -+ * -+ * 1.6.2 Arguments and notes -+ * -+ * The first argument is the cookie as passed to dtrace_register(). The -+ * second argument is the identifier of the probe to be suspended. The -+ * third argument is the probe argument as passed to dtrace_probe_create(). -+ * dtps_suspend will only be called on an enabled probe. Providers that -+ * provide a dtps_suspend entry point will want to take roughly the action -+ * that it takes for dtps_disable. -+ * -+ * 1.6.3 Return value -+ * -+ * None. -+ * -+ * 1.6.4 Caller's context -+ * -+ * Interrupts are disabled. The DTrace framework is in a state such that the -+ * specified probe cannot be disabled or destroyed for the duration of -+ * dtps_suspend(). As interrupts are disabled, the provider is afforded -+ * little latitude; the provider is expected to do no more than a store to -+ * memory. -+ * -+ * 1.7 void dtps_resume(void *arg, dtrace_id_t id, void *parg) -+ * -+ * 1.7.1 Overview -+ * -+ * Called to resume the specified enabled probe. This entry point is for -+ * providers that may need to resume some or all of their probes after the -+ * completion of an event that induced a call to dtps_suspend(). -+ * -+ * 1.7.2 Arguments and notes -+ * -+ * The first argument is the cookie as passed to dtrace_register(). The -+ * second argument is the identifier of the probe to be resumed. The -+ * third argument is the probe argument as passed to dtrace_probe_create(). -+ * dtps_resume will only be called on an enabled probe. Providers that -+ * provide a dtps_resume entry point will want to take roughly the action -+ * that it takes for dtps_enable. -+ * -+ * 1.7.3 Return value -+ * -+ * None. -+ * -+ * 1.7.4 Caller's context -+ * -+ * Interrupts are disabled. The DTrace framework is in a state such that the -+ * specified probe cannot be disabled or destroyed for the duration of -+ * dtps_resume(). As interrupts are disabled, the provider is afforded -+ * little latitude; the provider is expected to do no more than a store to -+ * memory. -+ * -+ * 1.8 void dtps_getargdesc(void *arg, dtrace_id_t id, void *parg, -+ * struct dtrace_argdesc *desc) -+ * -+ * 1.8.1 Overview -+ * -+ * Called to retrieve the argument description for an args[X] variable. -+ * -+ * 1.8.2 Arguments and notes -+ * -+ * The first argument is the cookie as passed to dtrace_register(). The -+ * second argument is the identifier of the current probe. The third -+ * argument is the probe argument as passed to dtrace_probe_create(). The -+ * fourth argument is a pointer to the argument description. This -+ * description is both an input and output parameter: it contains the -+ * index of the desired argument in the dtargd_ndx field, and expects -+ * the other fields to be filled in upon return. If there is no argument -+ * corresponding to the specified index, the dtargd_ndx field should be set -+ * to DTRACE_ARGNONE. -+ * -+ * 1.8.3 Return value -+ * -+ * None. The dtargd_ndx, dtargd_native, dtargd_xlate and dtargd_mapping -+ * members of the dtrace_argdesc structure are all output values. -+ * -+ * 1.8.4 Caller's context -+ * -+ * dtps_getargdesc() is called from ioctl() context. mod_lock is held, and -+ * the DTrace framework is locked in such a way that providers may not -+ * register or unregister. This means that the provider may not call any -+ * DTrace API that affects its registration with the framework, including -+ * dtrace_register(), dtrace_unregister(), dtrace_invalidate(), and -+ * dtrace_condense(). -+ * -+ * 1.9 uint64_t dtps_getargval(void *arg, dtrace_id_t id, void *parg, -+ * int argno, int aframes) -+ * -+ * 1.9.1 Overview -+ * -+ * Called to retrieve a value for an argX or args[X] variable. -+ * -+ * 1.9.2 Arguments and notes -+ * -+ * The first argument is the cookie as passed to dtrace_register(). The -+ * second argument is the identifier of the current probe. The third -+ * argument is the probe argument as passed to dtrace_probe_create(). The -+ * fourth argument is the number of the argument (the X in the example in -+ * 1.9.1). The fifth argument is the number of stack frames that were used -+ * to get from the actual place in the code that fired the probe to -+ * dtrace_probe() itself, the so-called artificial frames. This argument may -+ * be used to descend an appropriate number of frames to find the correct -+ * values. If this entry point is left NULL, the dtrace_getarg() built-in -+ * function is used. -+ * -+ * 1.9.3 Return value -+ * -+ * The value of the argument. -+ * -+ * 1.9.4 Caller's context -+ * -+ * This is called from within dtrace_probe() meaning that interrupts -+ * are disabled. No locks should be taken within this entry point. -+ * -+ * 1.10 int dtps_usermode(void *arg, dtrace_id_t id, void *parg) -+ * -+ * 1.10.1 Overview -+ * -+ * Called to determine if the probe was fired in a user context. -+ * -+ * 1.10.2 Arguments and notes -+ * -+ * The first argument is the cookie as passed to dtrace_register(). The -+ * second argument is the identifier of the current probe. The third -+ * argument is the probe argument as passed to dtrace_probe_create(). This -+ * entry point must not be left NULL for providers whose probes allow for -+ * mixed mode tracing, that is to say those probes that can fire during -+ * kernel- _or_ user-mode execution -+ * -+ * 1.10.3 Return value -+ * -+ * A boolean value. -+ * -+ * 1.10.4 Caller's context -+ * -+ * This is called from within dtrace_probe() meaning that interrupts -+ * are disabled. No locks should be taken within this entry point. -+ * -+ * 1.11 void dtps_destroy(void *arg, dtrace_id_t id, void *parg) -+ * -+ * 1.11.1 Overview -+ * -+ * Called to destroy the specified probe. -+ * -+ * 1.11.2 Arguments and notes -+ * -+ * The first argument is the cookie as passed to dtrace_register(). The -+ * second argument is the identifier of the probe to be destroyed. The third -+ * argument is the probe argument as passed to dtrace_probe_create(). The -+ * provider should free all state associated with the probe. The framework -+ * guarantees that dtps_destroy() is only called for probes that have either -+ * been disabled via dtps_disable() or were never enabled via dtps_enable(). -+ * Once dtps_disable() has been called for a probe, no further call will be -+ * made specifying the probe. -+ * -+ * 1.11.3 Return value -+ * -+ * None. -+ * -+ * 1.11.4 Caller's context -+ * -+ * The DTrace framework is locked in such a way that it may not be called -+ * back into at all. mod_lock is held. cpu_lock is not held, and may not be -+ * acquired. -+ * -+ * 1.12 void dtps_destroy_module(void *arg, struct modctl *mp) -+ * -+ * 1.12.1 Overview -+ * -+ * Called to notify provider that it can remove any per-module data. -+ * -+ * 1.12.2 Arguments and notes -+ * -+ * The first argument is the cookie as passed to dtrace_register(). The -+ * second argument is a pointer to a struct module structure that points to -+ * the module for which data may be cleared. -+ * -+ * 1.12.3 Return value -+ * -+ * None. -+ * -+ * -+ * 2 Provider-to-Framework API -+ * -+ * 2.1 Overview -+ * -+ * The Provider-to-Framework API provides the mechanism for the provider to -+ * register itself with the DTrace framework, to create probes, to lookup -+ * probes and (most importantly) to fire probes. The Provider-to-Framework -+ * consists of: -+ * -+ * dtrace_register() <-- Register a provider with the DTrace framework -+ * dtrace_unregister() <-- Remove a provider's DTrace registration -+ * dtrace_meta_register() <-- Register a metaprovider with the DTrace framework -+ * dtrace_meta_unregister()<-- Remove a metaprovider's DTrace registration -+ * dtrace_invalidate() <-- Invalidate the specified provider -+ * dtrace_condense() <-- Remove a provider's unenabled probes -+ * dtrace_attached() <-- Indicates whether or not DTrace has attached -+ * dtrace_probe_create() <-- Create a DTrace probe -+ * dtrace_probe_lookup() <-- Lookup a DTrace probe based on its name -+ * dtrace_probe_arg() <-- Return the probe argument for a specific probe -+ * dtrace_probe() <-- Fire the specified probe -+ * -+ * 2.2 int dtrace_register(const char *name, const struct dtrace_pattr *pap, -+ * uint32_t priv, struct cred *cr, const struct dtrace_pops *pops, -+ * void *arg, dtrace_provider_id_t *idp) -+ * -+ * 2.2.1 Overview -+ * -+ * dtrace_register() registers the calling provider with the DTrace -+ * framework. It should generally be called by DTrace providers in their -+ * attach(9E) entry point. -+ * -+ * 2.2.2 Arguments and Notes -+ * -+ * The first argument is the name of the provider. The second argument is a -+ * pointer to the stability attributes for the provider. The third argument -+ * is the privilege flags for the provider, and must be some combination of: -+ * -+ * DTRACE_PRIV_NONE <= All users may enable probes from this provider -+ * -+ * DTRACE_PRIV_PROC <= Any user with privilege of PRIV_DTRACE_PROC may -+ * enable probes from this provider -+ * -+ * DTRACE_PRIV_USER <= Any user with privilege of PRIV_DTRACE_USER may -+ * enable probes from this provider -+ * -+ * DTRACE_PRIV_KERNEL <= Any user with privilege of PRIV_DTRACE_KERNEL -+ * may enable probes from this provider -+ * -+ * DTRACE_PRIV_OWNER <= This flag places an additional constraint on -+ * the privilege requirements above. These probes -+ * require either (a) a user ID matching the user -+ * ID of the cred passed in the fourth argument -+ * or (b) the PRIV_PROC_OWNER privilege. -+ * -+ * Note that these flags designate the _visibility_ of the probes, not -+ * the conditions under which they may or may not fire. -+ * -+ * The fourth argument is the credential that is associated with the provider. -+ * This argument should be NULL if the privilege flags don't include -+ * DTRACE_PRIV_OWNER. If non-NULL, the framework stashes the uid represented -+ * by this credential for use at probe-time, in implicit predicates. These -+ * limit visibility of the probes to users which have sufficient privilege to -+ * access them. -+ * -+ * The fifth argument is a DTrace provider operations vector, which provides -+ * the implementation for the Framework-to-Provider API. (See Section 1, -+ * above.) This must be non-NULL, and each member must be non-NULL. The -+ * exceptions to this are (1) the dtps_provide() and dtps_provide_module() -+ * members (if the provider so desires, _one_ of these members may be left -+ * NULL -- denoting that the provider only implements the other) and (2) -+ * the dtps_suspend() and dtps_resume() members, which must either both be -+ * NULL or both be non-NULL. -+ * -+ * The sixth argument is a cookie to be specified as the first argument for -+ * each function in the Framework-to-Provider API. This argument may have -+ * any value. -+ * -+ * The final argument is a pointer to dtrace_provider_id_t. If -+ * dtrace_register() successfully completes, the provider identifier will be -+ * stored in the memory pointed to be this argument. This argument must be -+ * non-NULL. -+ * -+ * 2.2.3 Return value -+ * -+ * On success, dtrace_register() returns 0 and stores the new provider's -+ * identifier into the memory pointed to by the idp argument. On failure, -+ * dtrace_register() returns an errno: -+ * -+ * EINVAL The arguments passed to dtrace_register() were somehow invalid. -+ * This may because a parameter that must be non-NULL was NULL, -+ * because the name was invalid (either empty or an illegal -+ * provider name) or because the attributes were invalid. -+ * -+ * No other failure code is returned. -+ * -+ * 2.2.4 Caller's context -+ * -+ * dtrace_register() may induce calls to dtrace_provide(); the provider must -+ * hold no locks across dtrace_register() that may also be acquired by -+ * dtrace_provide(). cpu_lock and mod_lock must not be held. -+ * -+ * 2.3 int dtrace_unregister(dtrace_provider_id_t id) -+ * -+ * 2.3.1 Overview -+ * -+ * Unregisters the specified provider from the DTrace framework. It should -+ * generally be called by DTrace providers in their detach(9E) entry point. -+ * -+ * 2.3.2 Arguments and Notes -+ * -+ * The only argument is the provider identifier, as returned from a -+ * successful call to dtrace_register(). As a result of calling -+ * dtrace_unregister(), the DTrace framework will call back into the provider -+ * via the dtps_destroy() entry point. Once dtrace_unregister() successfully -+ * completes, however, the DTrace framework will no longer make calls through -+ * the Framework-to-Provider API. -+ * -+ * 2.3.3 Return value -+ * -+ * On success, dtrace_unregister returns 0. On failure, dtrace_unregister() -+ * returns an errno: -+ * -+ * EBUSY There are currently processes that have the DTrace pseudodevice -+ * open, or there exists an anonymous enabling that hasn't yet -+ * been claimed. -+ * -+ * No other failure code is returned. -+ * -+ * 2.3.4 Caller's context -+ * -+ * Because a call to dtrace_unregister() may induce calls through the -+ * Framework-to-Provider API, the caller may not hold any lock across -+ * dtrace_register() that is also acquired in any of the Framework-to- -+ * Provider API functions. Additionally, mod_lock may not be held. -+ * -+ * 2.4 void dtrace_invalidate(dtrace_provider_id_t id) -+ * -+ * 2.4.1 Overview -+ * -+ * Invalidates the specified provider. All subsequent probe lookups for the -+ * specified provider will fail, but its probes will not be removed. -+ * -+ * 2.4.2 Arguments and note -+ * -+ * The only argument is the provider identifier, as returned from a -+ * successful call to dtrace_register(). In general, a provider's probes -+ * always remain valid; dtrace_invalidate() is a mechanism for invalidating -+ * an entire provider, regardless of whether or not probes are enabled or -+ * not. Note that dtrace_invalidate() will _not_ prevent already enabled -+ * probes from firing -- it will merely prevent any new enablings of the -+ * provider's probes. -+ * -+ * 2.5 int dtrace_condense(dtrace_provider_id_t id) -+ * -+ * 2.5.1 Overview -+ * -+ * Removes all the unenabled probes for the given provider. This function is -+ * not unlike dtrace_unregister(), except that it doesn't remove the -+ * provider just as many of its associated probes as it can. -+ * -+ * 2.5.2 Arguments and Notes -+ * -+ * As with dtrace_unregister(), the sole argument is the provider identifier -+ * as returned from a successful call to dtrace_register(). As a result of -+ * calling dtrace_condense(), the DTrace framework will call back into the -+ * given provider's dtps_destroy() entry point for each of the provider's -+ * unenabled probes. -+ * -+ * 2.5.3 Return value -+ * -+ * Currently, dtrace_condense() always returns 0. However, consumers of this -+ * function should check the return value as appropriate; its behavior may -+ * change in the future. -+ * -+ * 2.5.4 Caller's context -+ * -+ * As with dtrace_unregister(), the caller may not hold any lock across -+ * dtrace_condense() that is also acquired in the provider's entry points. -+ * Also, mod_lock may not be held. -+ * -+ * 2.6 int dtrace_attached() -+ * -+ * 2.6.1 Overview -+ * -+ * Indicates whether or not DTrace has attached. -+ * -+ * 2.6.2 Arguments and Notes -+ * -+ * For most providers, DTrace makes initial contact beyond registration. -+ * That is, once a provider has registered with DTrace, it waits to hear -+ * from DTrace to create probes. However, some providers may wish to -+ * proactively create probes without first being told by DTrace to do so. -+ * If providers wish to do this, they must first call dtrace_attached() to -+ * determine if DTrace itself has attached. If dtrace_attached() returns 0, -+ * the provider must not make any other Provider-to-Framework API call. -+ * -+ * 2.6.3 Return value -+ * -+ * dtrace_attached() returns 1 if DTrace has attached, 0 otherwise. -+ * -+ * 2.7 int dtrace_probe_create(dtrace_provider_id_t id, const char *mod, -+ * const char *func, const char *name, int aframes, void *arg) -+ * -+ * 2.7.1 Overview -+ * -+ * Creates a probe with specified module name, function name, and name. -+ * -+ * 2.7.2 Arguments and Notes -+ * -+ * The first argument is the provider identifier, as returned from a -+ * successful call to dtrace_register(). The second, third, and fourth -+ * arguments are the module name, function name, and probe name, -+ * respectively. Of these, module name and function name may both be NULL -+ * (in which case the probe is considered to be unanchored), or they may both -+ * be non-NULL. The name must be non-NULL, and must point to a non-empty -+ * string. -+ * -+ * The fifth argument is the number of artificial stack frames that will be -+ * found on the stack when dtrace_probe() is called for the new probe. These -+ * artificial frames will be automatically be pruned should the stack() or -+ * stackdepth() functions be called as part of one of the probe's ECBs. If -+ * the parameter doesn't add an artificial frame, this parameter should be -+ * zero. -+ * -+ * The final argument is a probe argument that will be passed back to the -+ * provider when a probe-specific operation is called. (e.g., via -+ * dtps_enable(), dtps_disable(), etc.) -+ * -+ * Note that it is up to the provider to be sure that the probe that it -+ * creates does not already exist -- if the provider is unsure of the probe's -+ * existence, it should assure its absence with dtrace_probe_lookup() before -+ * calling dtrace_probe_create(). -+ * -+ * 2.7.3 Return value -+ * -+ * dtrace_probe_create() always succeeds, and always returns the identifier -+ * of the newly-created probe. -+ * -+ * 2.7.4 Caller's context -+ * -+ * While dtrace_probe_create() is generally expected to be called from -+ * dtps_provide() and/or dtps_provide_module(), it may be called from other -+ * non-DTrace contexts. Neither cpu_lock nor mod_lock may be held. -+ * -+ * 2.8 dtrace_id_t dtrace_probe_lookup(dtrace_provider_id_t id, -+ * const char *mod, const char *func, const char *name) -+ * -+ * 2.8.1 Overview -+ * -+ * Looks up a probe based on provdider and one or more of module name, -+ * function name and probe name. -+ * -+ * 2.8.2 Arguments and Notes -+ * -+ * The first argument is the provider identifier, as returned from a -+ * successful call to dtrace_register(). The second, third, and fourth -+ * arguments are the module name, function name, and probe name, -+ * respectively. Any of these may be NULL; dtrace_probe_lookup() will return -+ * the identifier of the first probe that is provided by the specified -+ * provider and matches all of the non-NULL matching criteria. -+ * dtrace_probe_lookup() is generally used by a provider to be check the -+ * existence of a probe before creating it with dtrace_probe_create(). -+ * -+ * 2.8.3 Return value -+ * -+ * If the probe exists, returns its identifier. If the probe does not exist, -+ * return DTRACE_IDNONE. -+ * -+ * 2.8.4 Caller's context -+ * -+ * While dtrace_probe_lookup() is generally expected to be called from -+ * dtps_provide() and/or dtps_provide_module(), it may also be called from -+ * other non-DTrace contexts. Neither cpu_lock nor mod_lock may be held. -+ * -+ * 2.9 void *dtrace_probe_arg(dtrace_provider_id_t id, dtrace_id_t probe) -+ * -+ * 2.9.1 Overview -+ * -+ * Returns the probe argument associated with the specified probe. -+ * -+ * 2.9.2 Arguments and Notes -+ * -+ * The first argument is the provider identifier, as returned from a -+ * successful call to dtrace_register(). The second argument is a probe -+ * identifier, as returned from dtrace_probe_lookup() or -+ * dtrace_probe_create(). This is useful if a probe has multiple -+ * provider-specific components to it: the provider can create the probe -+ * once with provider-specific state, and then add to the state by looking -+ * up the probe based on probe identifier. -+ * -+ * 2.9.3 Return value -+ * -+ * Returns the argument associated with the specified probe. If the -+ * specified probe does not exist, or if the specified probe is not provided -+ * by the specified provider, NULL is returned. -+ * -+ * 2.9.4 Caller's context -+ * -+ * While dtrace_probe_arg() is generally expected to be called from -+ * dtps_provide() and/or dtps_provide_module(), it may also be called from -+ * other non-DTrace contexts. Neither cpu_lock nor mod_lock may be held. -+ * -+ * 2.10 void dtrace_probe(dtrace_id_t probe, uintptr_t arg0, uintptr_t arg1, -+ * uintptr_t arg2, uintptr_t arg3, uintptr_t arg4) -+ * -+ * 2.10.1 Overview -+ * -+ * The epicenter of DTrace: fires the specified probes with the specified -+ * arguments. -+ * -+ * 2.10.2 Arguments and Notes -+ * -+ * The first argument is a probe identifier as returned by -+ * dtrace_probe_create() or dtrace_probe_lookup(). The second through sixth -+ * arguments are the values to which the D variables "arg0" through "arg4" -+ * will be mapped. -+ * -+ * dtrace_probe() should be called whenever the specified probe has fired -- -+ * however the provider defines it. -+ * -+ * 2.10.3 Return value -+ * -+ * None. -+ * -+ * 2.10.4 Caller's context -+ * -+ * dtrace_probe() may be called in virtually any context: kernel, user, -+ * interrupt, high-level interrupt, with arbitrary adaptive locks held, with -+ * dispatcher locks held, with interrupts disabled, etc. The only latitude -+ * that must be afforded to DTrace is the ability to make calls within -+ * itself (and to its in-kernel subroutines) and the ability to access -+ * arbitrary (but mapped) memory. On some platforms, this constrains -+ * context. For example, on UltraSPARC, dtrace_probe() cannot be called -+ * from any context in which TL is greater than zero. dtrace_probe() may -+ * also not be called from any routine which may be called by dtrace_probe() -+ * -- which includes functions in the DTrace framework and some in-kernel -+ * DTrace subroutines. All such functions "dtrace_"; providers that -+ * instrument the kernel arbitrarily should be sure to not instrument these -+ * routines. -+ */ -+ -+#include <dtrace/types.h> -+#include <linux/cred.h> -+#include <linux/module.h> -+#include <linux/dtrace/enabling_defines.h> -+#include <linux/dtrace/arg_defines.h> -+#include <dtrace/provider_defines.h> -+#include <linux/dtrace/stability.h> -+ -+struct dtrace_pops { -+ void (*dtps_provide)(void *, const struct dtrace_probedesc *); -+ void (*dtps_provide_module)(void *, struct module *); -+ int (*dtps_enable)(void *, dtrace_id_t, void *); -+ void (*dtps_disable)(void *, dtrace_id_t, void *); -+ void (*dtps_suspend)(void *, dtrace_id_t, void *); -+ void (*dtps_resume)(void *, dtrace_id_t, void *); -+ void (*dtps_getargdesc)(void *, dtrace_id_t, void *, -+ struct dtrace_argdesc *); -+ uint64_t (*dtps_getargval)(void *, dtrace_id_t, void *, int, int); -+ int (*dtps_usermode)(void *, dtrace_id_t, void *); -+ void (*dtps_destroy)(void *, dtrace_id_t, void *); -+ void (*dtps_destroy_module)(void *, struct module *); -+}; -+ -+struct dtrace_helper_probedesc { -+ char *dthpb_mod; -+ char *dthpb_func; -+ char *dthpb_name; -+ uint64_t dthpb_base; -+ uint32_t *dthpb_offs; -+ uint32_t *dthpb_enoffs; -+ uint32_t dthpb_noffs; -+ uint32_t dthpb_nenoffs; -+ uint8_t *dthpb_args; -+ uint8_t dthpb_xargc; -+ uint8_t dthpb_nargc; -+ char *dthpb_xtypes; -+ char *dthpb_ntypes; -+}; -+ -+struct dtrace_helper_provdesc { -+ char *dthpv_provname; -+ struct dtrace_pattr dthpv_pattr; -+}; -+ -+struct dtrace_mops { -+ void (*dtms_create_probe)(void *, void *, -+ struct dtrace_helper_probedesc *); -+ void *(*dtms_provide_pid)(void *, struct dtrace_helper_provdesc *, -+ pid_t); -+ void (*dtms_remove_pid)(void *, struct dtrace_helper_provdesc *, -+ pid_t); -+}; -+ -+/* -+ * DTrace Provider-to-Framework API Functions -+ */ -+ -+struct dtrace_meta { -+ struct dtrace_mops dtm_mops; -+ char *dtm_name; -+ void *dtm_arg; -+ uint64_t dtm_count; -+}; -+ -+struct dtrace_mprovider { -+ char *dtmp_name; -+ char *dtmp_pref; -+ struct dtrace_pattr *dtmp_attr; -+ uint32_t dtmp_priv; -+ struct dtrace_pops *dtmp_pops; -+ dtrace_provider_id_t dtmp_id; -+}; -+ -+struct dtrace_pmod { -+ struct module *mod; -+ struct list_head list; -+}; -+ -+extern int dtrace_register(const char *, const struct dtrace_pattr *, -+ uint32_t, const struct cred *, -+ const struct dtrace_pops *, void *, -+ dtrace_provider_id_t *); -+extern int dtrace_unregister(dtrace_provider_id_t); -+extern void dtrace_invalidate(dtrace_provider_id_t); -+extern int dtrace_condense(dtrace_provider_id_t); -+extern int dtrace_attached(void); -+ -+extern int dtrace_meta_register(const char *, const struct dtrace_mops *, -+ void *, dtrace_meta_provider_id_t *); -+extern int dtrace_meta_unregister(dtrace_meta_provider_id_t); -+ -+extern dtrace_id_t dtrace_probe_create(dtrace_provider_id_t, const char *, -+ const char *, const char *, int, -+ void *); -+extern void *dtrace_probe_arg(dtrace_provider_id_t, dtrace_id_t); -+extern dtrace_id_t dtrace_probe_lookup(dtrace_provider_id_t, const char *, -+ const char *, const char *); -+extern void dtrace_probe(dtrace_id_t, uintptr_t, uintptr_t, uintptr_t, -+ uintptr_t, uintptr_t, uintptr_t, uintptr_t); -+ -+/* -+ * Provider creation. -+ */ -+#ifdef DTRACE_HAVE_PROV_EXIT -+# define DT_PROV_EXIT(name) \ -+ extern int name##_prov_exit(void); -+#else -+# define DT_PROV_EXIT(name) \ -+ static int name##_prov_exit(void) \ -+ { \ -+ return (dtrace_unregister(name##_id) == 0); \ -+ } -+#endif -+ -+#define DT_PROVIDER_MODULE(name, priv) \ -+ dtrace_provider_id_t name##_id = DTRACE_PROVNONE; \ -+ \ -+ DT_PROV_EXIT(name) \ -+ \ -+ static int __init name##_init(void) \ -+ { \ -+ int ret = -ENOMEM; \ -+ struct dtrace_module *pdata = THIS_MODULE->pdata; \ -+ \ -+ if (pdata == NULL) \ -+ goto failed; \ -+ \ -+ ret = name##_dev_init(); \ -+ if (ret) \ -+ goto failed; \ -+ \ -+ ret = dtrace_register(__stringify(name), &name##_attr, priv, \ -+ NULL, &name##_pops, NULL, &name##_id); \ -+ if (ret) \ -+ goto failed; \ -+ \ -+ pdata->prov_exit = name##_prov_exit; \ -+ \ -+ return 0; \ -+ \ -+ failed: \ -+ return ret; \ -+ } \ -+ \ -+ static void __exit name##_exit(void) \ -+ { \ -+ name##_dev_exit(); \ -+ } \ -+ \ -+ module_init(name##_init); \ -+ module_exit(name##_exit); -+ -+#ifdef DTRACE_HAVE_PROV_EXIT -+# define DT_META_PROV_EXIT(name) \ -+ extern int name##_prov_exit(void); -+#else -+# define DT_META_PROV_EXIT(name) \ -+ static int name##_prov_exit(void) \ -+ { \ -+ return (dtrace_meta_unregister(name##_id) == 0); \ -+ } -+#endif -+ -+#define DT_META_PROVIDER_MODULE(name) \ -+ dtrace_meta_provider_id_t name##_id = DTRACE_METAPROVNONE; \ -+ \ -+ DT_META_PROV_EXIT(name) \ -+ \ -+ static int __init name##_init(void) \ -+ { \ -+ int ret = -ENOMEM; \ -+ struct dtrace_module *pdata = THIS_MODULE->pdata; \ -+ \ -+ if (pdata == NULL) \ -+ goto failed; \ -+ \ -+ ret = name##_dev_init(); \ -+ if (ret) \ -+ goto failed; \ -+ \ -+ ret = dtrace_meta_register(__stringify(name), &name##_mops, \ -+ NULL, &name##_id); \ -+ if (ret) \ -+ goto failed; \ -+ \ -+ pdata->prov_exit = name##_prov_exit; \ -+ \ -+ return 0; \ -+ \ -+ failed: \ -+ return ret; \ -+ } \ -+ \ -+ static void __exit name##_exit(void) \ -+ { \ -+ name##_dev_exit(); \ -+ } \ -+ \ -+ module_init(name##_init); \ -+ module_exit(name##_exit); -+ -+#define DT_MULTI_PROVIDER_MODULE(name, plist) \ -+ static int name##_prov_exit(void) \ -+ { \ -+ int ret = 0; \ -+ struct dtrace_mprovider *prov; \ -+ \ -+ for (prov = plist; prov->dtmp_name != NULL; prov++) { \ -+ if (prov->dtmp_id != DTRACE_PROVNONE) { \ -+ ret = dtrace_unregister(prov->dtmp_id); \ -+ if (ret != 0) { \ -+ pr_warn("Failed to unregister " \ -+ "provider %s: %d", \ -+ prov->dtmp_name, ret); \ -+ break; \ -+ } \ -+ \ -+ prov->dtmp_id = DTRACE_PROVNONE; \ -+ } \ -+ } \ -+ \ -+ return (ret == 0); \ -+ } \ -+ \ -+ static int __init name##_init(void) \ -+ { \ -+ int ret = -ENOMEM; \ -+ struct dtrace_mprovider *prov; \ -+ struct dtrace_module *pdata = THIS_MODULE->pdata; \ -+ \ -+ if (pdata == NULL) \ -+ goto failed; \ -+ \ -+ ret = name##_dev_init(); \ -+ if (ret) \ -+ goto failed; \ -+ \ -+ for (prov = plist; prov->dtmp_name != NULL; prov++) { \ -+ if (dtrace_register(prov->dtmp_name, prov->dtmp_attr, \ -+ prov->dtmp_priv, NULL, \ -+ prov->dtmp_pops, prov, \ -+ &prov->dtmp_id) != 0) \ -+ pr_warn("Failed to register provider %s", \ -+ prov->dtmp_name); \ -+ } \ -+ \ -+ pdata->prov_exit = name##_prov_exit; \ -+ \ -+ return 0; \ -+ \ -+ failed: \ -+ return ret; \ -+ } \ -+ \ -+ static void __exit name##_exit(void) \ -+ { \ -+ name##_dev_exit(); \ -+ } \ -+ \ -+ module_init(name##_init); \ -+ module_exit(name##_exit); -+ -+ -+#endif /* _DTRACE_PROVIDER_H */ -diff --git a/include/dtrace/provider_defines.h b/include/dtrace/provider_defines.h -new file mode 100644 -index 000000000000..104514e1261b ---- /dev/null -+++ b/include/dtrace/provider_defines.h -@@ -0,0 +1,41 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Dynamic Tracing for Linux - Provider defines -+ * -+ * Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _DTRACE_PROVIDER_DEFINES_H -+#define _DTRACE_PROVIDER_DEFINES_H -+ -+#include <linux/dtrace/universal.h> -+#include <linux/in6.h> -+ -+typedef uintptr_t dtrace_provider_id_t; -+typedef uintptr_t dtrace_meta_provider_id_t; -+typedef __be32 ipaddr_t; -+typedef ipaddr_t *ipaddr_t_p; -+typedef struct in6_addr in6_addr_t; -+ -+struct dtrace_pops; -+struct dtrace_helper_probedesc; -+struct dtrace_helper_provdesc; -+struct dtrace_mops; -+struct dtrace_meta; -+ -+#endif /* _DTRACE_PROVIDER_DEFINES_H */ -diff --git a/include/dtrace/types.h b/include/dtrace/types.h -new file mode 100644 -index 000000000000..7f8d0d7efcc7 ---- /dev/null -+++ b/include/dtrace/types.h -@@ -0,0 +1,131 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Dynamic Tracing for Linux - Kernel Types -+ * -+ * Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _DTRACE_TYPES_H -+#define _DTRACE_TYPES_H -+ -+/* -+ * This file contains types needed to parse the DTrace shared userspace/ kernel -+ * headers, and a few others (it has not been gardened to remove constants used -+ * only by the DTrace core). Userspace has its own version of these types -+ * (mostly from <unistd.h>). -+ * -+ * This file is compiled both in a normal kernel environment and in a peculiar -+ * halfway-house environment used for headers_checking of <ioctl.h>, in which -+ * among other things, no config.h symbols are available. As a result, you -+ * should be careful about #including kernel headers here: many will break -+ * headers_check if added. So far, it has always been sufficient to add them to -+ * dtrace/dtrace.h instead; if this turns out to be insufficient later (perhaps -+ * because DTrace core files cease to #include all of <dtrace.h>), the -+ * HEADERS_CHECK #define may prove useful to disable kernel-only portions of -+ * this file. -+ */ -+ -+#include <asm/bitsperlong.h> -+#include <linux/dtrace_os.h> -+ -+typedef unsigned char uchar_t; -+typedef unsigned int uint_t; -+typedef unsigned long ulong_t; -+ -+typedef long intptr_t; -+ -+#define UINT8_MAX (0xff) -+#define UINT8_MIN 0 -+#define UINT16_MAX (0xffff) -+#define UINT16_MIN 0 -+#define UINT32_MAX (0xffffffff) -+#define UINT32_MIN 0 -+#define UINT64_MAX (~0ULL) -+#define UINT64_MIN (0) -+#define INT64_MAX ((long long)(~0ULL>>1)) -+#define INT64_MIN (-INT64_MAX - 1LL) -+ -+#define NBBY (__BITS_PER_LONG / sizeof(long)) -+ -+/* -+ * This is a bit unusual, but OpenSolaris seems to like it. Basically, the -+ * values below are the number of time units (sec, milli, micro, nano) that -+ * comprise 1 second. As such, it is the value of the respective multiplier. -+ */ -+#define SEC 1 -+#define MILLISEC 1000 -+#define MICROSEC 1000000 -+#define NANOSEC 1000000000 -+ -+typedef enum { -+ TRUE = -1, -+ FALSE = 0 -+} boolean_t; -+ -+ -+#define DTRACE_ACCESS_KERNEL 0x1 -+ -+#define DTRACE_CRA_PROC 0x0001 -+#define DTRACE_CRA_PROC_CONTROL 0x0002 -+#define DTRACE_CRA_PROC_DESTRUCTIVE_ALLUSER 0x0004 -+#define DTRACE_CRA_PROC_DESTRUCTIVE_CREDCHG 0x0010 -+#define DTRACE_CRA_KERNEL 0x0020 -+#define DTRACE_CRA_KERNEL_DESTRUCTIVE 0x0040 -+ -+#define DTRACE_CRA_ALL (DTRACE_CRA_PROC | \ -+ DTRACE_CRA_PROC_CONTROL | \ -+ DTRACE_CRA_PROC_DESTRUCTIVE_ALLUSER | \ -+ DTRACE_CRA_PROC_DESTRUCTIVE_CREDCHG | \ -+ DTRACE_CRA_KERNEL | \ -+ DTRACE_CRA_KERNEL_DESTRUCTIVE) -+ -+#define DTRACE_CRV_ALLPROC 0x01 -+#define DTRACE_CRV_KERNEL 0x02 -+#define DTRACE_CRV_ALL (DTRACE_CRV_ALLPROC | DTRACE_CRV_KERNEL) -+ -+#define DTRACE_MATCH_FAIL -1 -+#define DTRACE_MATCH_NEXT 0 -+#define DTRACE_MATCH_DONE 1 -+ -+#define DTRACE_COND_OWNER 0x01 -+#define DTRACE_COND_USERMODE 0x02 -+ -+#define P2ROUNDUP(x, a) (-(-(x) & -(a))) -+ -+#if (BITS_PER_LONG == 64) || defined(CONFIG_KTIME_SCALAR) -+#define KTIME_INIT(s, ns) ((s64)(s) * NSEC_PER_SEC + (s64)(ns)) -+#else -+# define KTIME_INIT(n, ns) { .sec = (s), .nsec = (ns) } -+#endif -+#define ktime_lt(t0, t1) (t0 < t1) -+#define ktime_le(t0, t1) (t0 <= t1) -+#define ktime_ge(t0, t1) (t0 >= t1) -+#define ktime_gt(t0, t1) (t0 > t1) -+#define ktime_cp(t0, t1) (t0 = t1) -+ -+/* -+ * Translate between kernel config options and userspace-compatible definitions. -+ */ -+#ifdef CONFIG_64BIT -+#define _LP64 1 -+#endif -+#ifdef __LITTLE_ENDIAN -+#define _LITTLE_ENDIAN 1 -+#endif -+ -+#endif /* _DTRACE_TYPES_H */ -diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h -index bc56287a1ed1..25e7b8778b71 100644 ---- a/include/linux/cpuhotplug.h -+++ b/include/linux/cpuhotplug.h -@@ -107,6 +107,7 @@ enum cpuhp_state { - CPUHP_AP_IRQ_SIFIVE_PLIC_STARTING, - CPUHP_AP_ARM_MVEBU_COHERENCY, - CPUHP_AP_MICROCODE_LOADER, -+ CPUHP_AP_CYCLIC_STARTING, - CPUHP_AP_PERF_X86_AMD_UNCORE_STARTING, - CPUHP_AP_PERF_X86_STARTING, - CPUHP_AP_PERF_X86_AMD_IBS_STARTING, -diff --git a/include/linux/cyclic.h b/include/linux/cyclic.h -new file mode 100644 -index 000000000000..12ab85dc185b ---- /dev/null -+++ b/include/linux/cyclic.h -@@ -0,0 +1,49 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+#ifndef _CYCLIC_H_ -+#define _CYCLIC_H_ -+ -+#include <linux/ktime.h> -+#include <linux/types.h> -+ -+#define CY_LOW_LEVEL 0 -+#define CY_LOCK_LEVEL 1 -+#define CY_HIGH_LEVEL 2 -+#define CY_SOFT_LEVELS 2 -+#define CY_LEVELS 3 -+ -+typedef uintptr_t cyclic_id_t; -+typedef uint16_t cyc_level_t; -+typedef void (*cyc_func_t)(uintptr_t); -+ -+#define CYCLIC_NONE ((cyclic_id_t)0) -+ -+struct cyc_handler { -+ cyc_func_t cyh_func; -+ uintptr_t cyh_arg; -+ cyc_level_t cyh_level; -+}; -+ -+#define CY_INTERVAL_INF (-1) -+ -+struct cyc_time { -+ ktime_t cyt_when; -+ ktime_t cyt_interval; -+}; -+ -+struct cyc_omni_handler { -+ void (*cyo_online)(void *, uint32_t, struct cyc_handler *, -+ struct cyc_time *); -+ void (*cyo_offline)(void *, uint32_t, void *); -+ void *cyo_arg; -+}; -+ -+extern cyclic_id_t cyclic_add(struct cyc_handler *, struct cyc_time *); -+extern cyclic_id_t cyclic_add_omni(struct cyc_omni_handler *); -+extern void cyclic_remove(cyclic_id_t); -+extern void cyclic_reprogram(cyclic_id_t, ktime_t); -+ -+#endif /* _CYCLIC_H_ */ -diff --git a/include/linux/dtrace/cpu_defines.h b/include/linux/dtrace/cpu_defines.h -new file mode 100644 -index 000000000000..c8719378da80 ---- /dev/null -+++ b/include/linux/dtrace/cpu_defines.h -@@ -0,0 +1,61 @@ -+/* Copyright (C) 2011-2014 Oracle, Inc. */ -+ -+#ifndef _LINUX_DTRACE_CPU_DEFINES_H_ -+#define _LINUX_DTRACE_CPU_DEFINES_H_ -+ -+#include <linux/percpu.h> -+ -+#define CPUC_SIZE (sizeof (uint16_t) + sizeof(uint8_t) + \ -+ sizeof(uintptr_t) + sizeof(struct mutex)) -+#define CPUC_PADSIZE (192 - CPUC_SIZE) -+ -+#define per_cpu_core(cpu) (&per_cpu(dtrace_cpu_core, (cpu))) -+#if 0 -+# define this_cpu_core (this_cpu_ptr(&dtrace_cpu_core)) -+#else -+# define this_cpu_core (per_cpu_core(smp_processor_id())) -+#endif -+ -+#define DTRACE_CPUFLAG_ISSET(flag) \ -+ (this_cpu_core->cpuc_dtrace_flags & (flag)) -+ -+#define DTRACE_CPUFLAG_SET(flag) \ -+ (this_cpu_core->cpuc_dtrace_flags |= (flag)) -+ -+#define DTRACE_CPUFLAG_CLEAR(flag) \ -+ (this_cpu_core->cpuc_dtrace_flags &= ~(flag)) -+ -+#define CPU_DTRACE_NOFAULT 0x0001 -+#define CPU_DTRACE_DROP 0x0002 -+#define CPU_DTRACE_BADADDR 0x0004 -+#define CPU_DTRACE_BADALIGN 0x0008 -+#define CPU_DTRACE_DIVZERO 0x0010 -+#define CPU_DTRACE_ILLOP 0x0020 -+#define CPU_DTRACE_NOSCRATCH 0x0040 -+#define CPU_DTRACE_KPRIV 0x0080 -+#define CPU_DTRACE_UPRIV 0x0100 -+#define CPU_DTRACE_TUPOFLOW 0x0200 -+#define CPU_DTRACE_ENTRY 0x0800 -+#define CPU_DTRACE_BADSTACK 0x1000 -+#define CPU_DTRACE_NOPF 0x2000 -+#define CPU_DTRACE_PF_TRAPPED 0x4000 -+ -+#define CPU_DTRACE_FAULT (CPU_DTRACE_BADADDR | CPU_DTRACE_BADALIGN | \ -+ CPU_DTRACE_DIVZERO | CPU_DTRACE_ILLOP | \ -+ CPU_DTRACE_NOSCRATCH | CPU_DTRACE_KPRIV | \ -+ CPU_DTRACE_UPRIV | CPU_DTRACE_TUPOFLOW | \ -+ CPU_DTRACE_BADSTACK | CPU_DTRACE_PF_TRAPPED) -+#define CPU_DTRACE_ERROR (CPU_DTRACE_FAULT | CPU_DTRACE_DROP) -+ -+typedef uint32_t processorid_t; -+typedef uint32_t psetid_t; -+typedef uint32_t chipid_t; -+typedef uint32_t lgrp_id_t; -+ -+struct cpu_core; -+struct cpuinfo; -+ -+#define per_cpu_info(cpu) (&per_cpu(dtrace_cpu_info, (cpu))) -+#define this_cpu_info (this_cpu_ptr(&dtrace_cpu_info)) -+ -+#endif /* _LINUX_DTRACE_CPU_DEFINES_H_ */ -diff --git a/include/linux/dtrace_cpu.h b/include/linux/dtrace_cpu.h -new file mode 100644 -index 000000000000..6b3dc7219f49 ---- /dev/null -+++ b/include/linux/dtrace_cpu.h -@@ -0,0 +1,53 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+#ifndef _LINUX_DTRACE_CPU_H_ -+#define _LINUX_DTRACE_CPU_H_ -+ -+#ifdef CONFIG_DTRACE -+ -+#include <linux/ktime.h> -+#include <linux/mutex.h> -+#include <linux/spinlock.h> -+#include <linux/dtrace_types.h> -+#include <linux/dtrace_cpu_defines.h> -+#include <asm/dtrace_cpuinfo.h> -+ -+struct cpu_core { -+ uint16_t cpuc_dtrace_flags; -+ uint8_t cpuc_dcpc_intr_state; -+ uint8_t cpuc_pad[CPUC_PADSIZE]; -+ uintptr_t cpuc_dtrace_illval; -+ struct mutex cpuc_pid_lock; -+ -+ uintptr_t cpu_dtrace_caller; -+ struct pt_regs *cpu_dtrace_regs; -+ ktime_t cpu_dtrace_chillmark; -+ ktime_t cpu_dtrace_chilled; -+ rwlock_t cpu_ft_lock; -+ atomic64_t cpuc_sync_requests; -+ atomic64_t cpuc_in_probe_ctx; -+ dtrace_id_t cpuc_current_probe; -+}; -+ -+DECLARE_PER_CPU_SHARED_ALIGNED(struct cpu_core, dtrace_cpu_core); -+ -+struct cpuinfo { -+ processorid_t cpu_id; -+ psetid_t cpu_pset; -+ chipid_t cpu_chip; -+ lgrp_id_t cpu_lgrp; -+ cpuinfo_arch_t *cpu_info; -+}; -+ -+DECLARE_PER_CPU_SHARED_ALIGNED(struct cpuinfo, dtrace_cpu_info); -+ -+/* ABI requirement: type names compiled into DTrace userspace. */ -+typedef struct cpuinfo cpuinfo_t; -+ -+extern void dtrace_cpu_init(void); -+ -+#endif /* CONFIG_DTRACE */ -+#endif /* _LINUX_DTRACE_CPU_H_ */ -diff --git a/include/linux/dtrace_cpu_defines.h b/include/linux/dtrace_cpu_defines.h -new file mode 100644 -index 000000000000..f5866a6e95b8 ---- /dev/null -+++ b/include/linux/dtrace_cpu_defines.h -@@ -0,0 +1,2 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+#include <linux/dtrace/cpu_defines.h> -diff --git a/include/linux/dtrace_os.h b/include/linux/dtrace_os.h -new file mode 100644 -index 000000000000..5bcd77e08a14 ---- /dev/null -+++ b/include/linux/dtrace_os.h -@@ -0,0 +1,120 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+#ifndef _LINUX_DTRACE_OS_H_ -+#define _LINUX_DTRACE_OS_H_ -+ -+#ifndef HEADERS_CHECK -+ -+#ifdef CONFIG_DTRACE -+ -+#include <linux/ktime.h> -+#include <linux/mm.h> -+#include <linux/notifier.h> -+#include <linux/timekeeper_internal.h> -+#include <asm/unistd.h> -+#include <linux/dtrace_cpu.h> -+#include <linux/dtrace_task.h> -+#include <linux/dtrace_psinfo.h> -+ -+extern struct module *dtrace_kmod; -+ -+extern void __init dtrace_os_init(void); -+extern void __init dtrace_psinfo_os_init(void); -+extern void __init dtrace_task_os_init(void); -+ -+extern void dtrace_mod_pdata_alloc(struct module *); -+extern void dtrace_mod_pdata_free(struct module *); -+extern int dtrace_destroy_prov(struct module *); -+ -+extern int dtrace_enable(void); -+extern void dtrace_disable(void); -+ -+extern ktime_t dtrace_gethrtime(void); -+extern ktime_t dtrace_getwalltime(void); -+ -+enum dtrace_vtime_state { -+ DTRACE_VTIME_INACTIVE = 0, -+ DTRACE_VTIME_ACTIVE -+}; -+ -+extern enum dtrace_vtime_state dtrace_vtime_active; -+ -+typedef void for_each_module_fn(void *, struct module *); -+extern void dtrace_for_each_module(for_each_module_fn *fn, void *arg); -+ -+extern void dtrace_update_time(struct timekeeper *); -+extern ktime_t dtrace_get_walltime(void); -+ -+extern void dtrace_vtime_enable(void); -+extern void dtrace_vtime_disable(void); -+extern void dtrace_vtime_switch(struct task_struct *, struct task_struct *); -+ -+#include <asm/dtrace_util.h> -+ -+extern int dtrace_instr_size(const asm_instr_t *); -+ -+extern int dtrace_die_notifier(struct notifier_block *, unsigned long, void *); -+ -+#define STACKTRACE_KERNEL 0x01 -+#define STACKTRACE_USER 0x02 -+#define STACKTRACE_TYPE 0x0f -+ -+struct stacktrace_state { -+ uint64_t *pcs; -+ uint64_t *fps; -+ int limit; -+ int depth; -+ int flags; -+}; -+ -+extern void dtrace_stacktrace(struct stacktrace_state *); -+extern void dtrace_user_stacktrace(struct stacktrace_state *); -+extern void dtrace_handle_badaddr(struct pt_regs *); -+extern void dtrace_mod_pdata_init(struct dtrace_module *pdata); -+extern void dtrace_mod_pdata_cleanup(struct dtrace_module *pdata); -+ -+/* -+ * This is only safe to call if we know this is a userspace fault -+ * or that the call happens after early boot. -+ */ -+static inline int dtrace_no_pf(struct pt_regs *regs) -+{ -+ if (unlikely(DTRACE_CPUFLAG_ISSET(CPU_DTRACE_NOFAULT))) { -+ dtrace_handle_badaddr(regs); -+ return 1; -+ } -+ -+ return 0; -+} -+ -+extern void (*dtrace_helpers_cleanup)(struct task_struct *); -+extern void (*dtrace_helpers_fork)(struct task_struct *, struct task_struct *); -+ -+#else -+ -+/* -+ * See arch/x86/mm/fault.c. -+ */ -+ -+#define dtrace_no_pf(ignore) 0 -+ -+/* -+ * See kernel/timekeeper.c -+ */ -+#define dtrace_update_time(ignore) -+ -+/* -+ * See kernel/dtrace/dtrace_os.c -+ */ -+#define dtrace_mod_pdata_alloc(ignore) -+#define dtrace_mod_pdata_free(ignore) -+#define dtrace_destroy_prov(ignore) 1 -+ -+#endif /* CONFIG_DTRACE */ -+ -+#endif /* !HEADERS_CHECK */ -+ -+#endif /* _LINUX_DTRACE_OS_H_ */ -diff --git a/include/linux/dtrace_psinfo.h b/include/linux/dtrace_psinfo.h -new file mode 100644 -index 000000000000..53a9c317a8a3 ---- /dev/null -+++ b/include/linux/dtrace_psinfo.h -@@ -0,0 +1,59 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+#ifndef _LINUX_DTRACE_PSINFO_H_ -+#define _LINUX_DTRACE_PSINFO_H_ -+ -+#ifdef CONFIG_DTRACE -+ -+#define PR_PSARGS_SZ 80 -+#define PR_ARGV_SZ 512 -+#define PR_ENVP_SZ 512 -+ -+/* -+ * DTrace's per-process info (per-tgid). -+ * -+ * All threads in a process share the same structure instance. -+ */ -+struct dtrace_psinfo { -+ atomic_t dtps_usage; -+ unsigned long dtps_argc; -+ char **dtps_argv; -+ unsigned long dtps_envc; -+ char **dtps_envp; -+ char dtps_psargs[PR_PSARGS_SZ]; -+}; -+ -+/* -+ * DTrace psinfo API. Requires struct dtrace_task as its argument. -+ */ -+ -+extern void dtrace_psinfo_alloc(struct task_struct *); -+extern void dtrace_psinfo_free(struct dtrace_psinfo *); -+ -+static inline void dtrace_psinfo_get(struct dtrace_psinfo *psinfo) -+{ -+ if (likely(psinfo)) -+ atomic_inc(&(psinfo)->dtps_usage); -+} -+ -+static inline void dtrace_psinfo_put(struct dtrace_psinfo *psinfo) -+{ -+ if (likely((psinfo))) { -+ if (atomic_dec_and_test(&(psinfo)->dtps_usage)) -+ dtrace_psinfo_free(psinfo); -+ } -+} -+ -+#else /* CONFIG_DTRACE */ -+ -+#define dtrace_psinfo_alloc(ignore) -+#define dtrace_psinfo_free(ignore) -+#define dtrace_psinfo_get(ignore) -+#define dtrace_psinfo_put(ignore) -+ -+#endif /* CONFIG_DTRACE */ -+ -+#endif /* _LINUX_DTRACE_PSINFO_H_ */ -diff --git a/include/linux/dtrace_task.h b/include/linux/dtrace_task.h -new file mode 100644 -index 000000000000..ce7111223788 ---- /dev/null -+++ b/include/linux/dtrace_task.h -@@ -0,0 +1,38 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+#ifndef _LINUX_DTRACE_TASK_H_ -+#define _LINUX_DTRACE_TASK_H_ -+ -+#ifdef CONFIG_DTRACE -+ -+#include <linux/sched.h> -+ -+/* -+ * Opaque handle for per-task data. -+ */ -+struct dtrace_task; -+ -+/* -+ * DTrace's kernel API for per-task data manipulation. -+ */ -+ -+extern void dtrace_task_init(struct task_struct *); -+extern void dtrace_task_exec(struct task_struct *); -+extern void dtrace_task_copy(struct task_struct *, struct task_struct *); -+extern void dtrace_task_free(struct task_struct *); -+extern void dtrace_task_dup(struct task_struct *, struct task_struct *); -+ -+#else /* CONFIG_DTRACE */ -+ -+#define dtrace_task_init(ignore) -+#define dtrace_task_exec(ignore) -+#define dtrace_task_copy(ignore1, ignore2) -+#define dtrace_task_free(ignore) -+#define dtrace_task_dup(ignore1, ignore2) -+ -+#endif /* CONFIG_DTRACE */ -+ -+#endif /* _LINUX_DTRACE_TASK_H_ */ -diff --git a/include/linux/dtrace_task_impl.h b/include/linux/dtrace_task_impl.h -new file mode 100644 -index 000000000000..2f76b475c2f8 ---- /dev/null -+++ b/include/linux/dtrace_task_impl.h -@@ -0,0 +1,28 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. -+ */ -+#ifndef _LINUX_DTRACE_TASK_IMPL_H_ -+#define _LINUX_DTRACE_TASK_IMPL_H_ -+ -+#ifdef CONFIG_DTRACE -+ -+#include <linux/dtrace_task.h> -+#include <linux/dtrace_psinfo.h> -+ -+struct dtrace_task { -+ uint32_t dt_predcache; -+ ktime_t dt_vtime; -+ ktime_t dt_start; -+ uint8_t dt_stop; -+ uint8_t dt_sig; -+ struct dtrace_psinfo *dt_psinfo; -+ void *dt_helpers; -+ uint32_t dt_probes; -+ uint64_t dt_tp_count; -+ void *dt_ustack; -+}; -+ -+#endif /* CONFIG_DTRACE */ -+#endif /* _LINUX_DTRACE_TASK_IMPL_H_ */ -+ -diff --git a/include/linux/dtrace_types.h b/include/linux/dtrace_types.h -new file mode 100644 -index 000000000000..4484dc58e188 ---- /dev/null -+++ b/include/linux/dtrace_types.h -@@ -0,0 +1,13 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+#ifndef _DTRACE_TYPES_H_ -+#define _DTRACE_TYPES_H_ -+ -+typedef uint32_t dtrace_id_t; -+ -+#define DTRACE_IDNONE 0 -+ -+#endif /* _DTRACE_TYPES_H_ */ -diff --git a/include/linux/ktime.h b/include/linux/ktime.h -index a12b5523cc18..ba226005fd2a 100644 ---- a/include/linux/ktime.h -+++ b/include/linux/ktime.h -@@ -156,6 +156,14 @@ static inline s64 ktime_divns(const ktime_t kt, s64 div) - } - #endif - -+/* -+ * ktime_nz - Check whether a ktime_v variable is non-zero -+ */ -+static inline int ktime_nz(const ktime_t kt) -+{ -+ return kt != 0LL; -+} -+ - static inline s64 ktime_to_us(const ktime_t kt) - { - return ktime_divns(kt, NSEC_PER_USEC); -diff --git a/include/linux/module.h b/include/linux/module.h -index d44fe50d7c7f..44915ed85337 100644 ---- a/include/linux/module.h -+++ b/include/linux/module.h -@@ -512,6 +512,9 @@ struct module { - struct klp_modinfo *klp_info; - #endif - -+#ifdef CONFIG_DTRACE -+ void *pdata; -+#endif - #ifdef CONFIG_MODULE_UNLOAD - /* What modules depend on me? */ - struct list_head source_list; -diff --git a/include/linux/mutex.h b/include/linux/mutex.h -index dcd185cbfe79..bb18028db361 100644 ---- a/include/linux/mutex.h -+++ b/include/linux/mutex.h -@@ -20,6 +20,10 @@ - #include <linux/osq_lock.h> - #include <linux/debug_locks.h> - -+#ifdef CONFIG_SMP -+# include <asm/current.h> -+#endif -+ - struct ww_acquire_ctx; - - /* -@@ -224,4 +228,16 @@ enum mutex_trylock_recursive_enum { - extern /* __deprecated */ __must_check enum mutex_trylock_recursive_enum - mutex_trylock_recursive(struct mutex *lock); - -+#if defined(CONFIG_DEBUG_MUTEXES) || defined(CONFIG_SMP) -+static inline int mutex_owned(struct mutex *lock) -+{ -+ return mutex_is_locked(lock) && __mutex_owner(lock) == current; -+} -+#else -+static inline int mutex_owned(struct mutex *lock) -+{ -+ return mutex_is_locked(lock); -+} -+#endif -+ - #endif /* __LINUX_MUTEX_H */ -diff --git a/include/linux/rwlock.h b/include/linux/rwlock.h -index 3dcd617e65ae..a7e72774f17e 100644 ---- a/include/linux/rwlock.h -+++ b/include/linux/rwlock.h -@@ -59,6 +59,13 @@ do { \ - # define do_raw_write_unlock(rwlock) do {arch_write_unlock(&(rwlock)->raw_lock); __release(lock); } while (0) - #endif - -+#ifdef CONFIG_DTRACE -+#define peek_read_can_lock(rwlock) \ -+ arch_peek_read_can_lock(&(rwlock)->raw_lock) -+#define peek_write_can_lock(rwlock) \ -+ arch_peek_write_can_lock(&(rwlock)->raw_lock) -+#endif /* CONFIG_DTRACE */ -+ - /* - * Define the various rw_lock methods. Note we define these - * regardless of whether CONFIG_SMP or CONFIG_PREEMPT are set. The various -diff --git a/include/linux/sched.h b/include/linux/sched.h -index 76cd21fa5501..0be45d979989 100644 ---- a/include/linux/sched.h -+++ b/include/linux/sched.h -@@ -34,6 +34,7 @@ - #include <linux/rseq.h> - #include <linux/seqlock.h> - #include <linux/kcsan.h> -+#include <linux/dtrace_task.h> - - /* task_struct member predeclarations (sorted alphabetically): */ - struct audit_context; -@@ -1304,6 +1305,9 @@ struct task_struct { - struct request_queue *throttle_queue; - #endif - -+#ifdef CONFIG_DTRACE -+ struct dtrace_task *dt_task; -+#endif - #ifdef CONFIG_UPROBES - struct uprobe_task *utask; - #endif -diff --git a/include/linux/spinlock_up.h b/include/linux/spinlock_up.h -index 0ac9112c1bbe..cfd00c13f2aa 100644 ---- a/include/linux/spinlock_up.h -+++ b/include/linux/spinlock_up.h -@@ -69,4 +69,9 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock) - - #define arch_spin_is_contended(lock) (((void)(lock), 0)) - -+#ifdef CONFIG_DTRACE -+#define arch_peek_read_can_lock(lock) (((void)(lock), 1)) -+#define arch_peek_write_can_lock(lock) (((void)(lock), 1)) -+#endif /* CONFIG_DTRACE */ -+ - #endif /* __LINUX_SPINLOCK_UP_H */ -diff --git a/include/uapi/linux/dtrace/Kbuild b/include/uapi/linux/dtrace/Kbuild -new file mode 100644 -index 000000000000..0cb5b941b72b ---- /dev/null -+++ b/include/uapi/linux/dtrace/Kbuild -@@ -0,0 +1,35 @@ -+# UAPI Header export list -+header-y += actions_defines.h -+header-y += actions.h -+header-y += arg_defines.h -+header-y += arg.h -+header-y += buffer_defines.h -+header-y += buffer.h -+header-y += conf_defines.h -+header-y += conf.h -+header-y += cpu_defines.h -+header-y += dif_defines.h -+header-y += dif.h -+header-y += difo_defines.h -+header-y += difo.h -+header-y += dof_defines.h -+header-y += dof.h -+header-y += dtrace.h -+header-y += enabling_defines.h -+header-y += enabling.h -+header-y += fasttrap_defines.h -+header-y += fasttrap.h -+header-y += fasttrap_ioctl.h -+header-y += faults_defines.h -+header-y += faults.h -+header-y += helpers_defines.h -+header-y += helpers.h -+header-y += ioctl.h -+header-y += metadesc_defines.h -+header-y += metadesc.h -+header-y += options_defines.h -+header-y += options.h -+header-y += stability_defines.h -+header-y += stability.h -+header-y += status.h -+header-y += universal.h -diff --git a/include/uapi/linux/dtrace/actions.h b/include/uapi/linux/dtrace/actions.h -new file mode 100644 -index 000000000000..9b47343271ba ---- /dev/null -+++ b/include/uapi/linux/dtrace/actions.h -@@ -0,0 +1,14 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+#ifndef _LINUX_DTRACE_ACTIONS_H -+#define _LINUX_DTRACE_ACTIONS_H -+ -+#include <linux/dtrace/actions_defines.h> -+ -+#endif /* _LINUX_DTRACE_ACTIONS_H */ -diff --git a/include/uapi/linux/dtrace/actions_defines.h b/include/uapi/linux/dtrace/actions_defines.h -new file mode 100644 -index 000000000000..4512c291f58a ---- /dev/null -+++ b/include/uapi/linux/dtrace/actions_defines.h -@@ -0,0 +1,181 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_ACTIONS_DEFINES_H -+#define _LINUX_DTRACE_ACTIONS_DEFINES_H -+ -+#include <linux/dtrace/universal.h> -+ -+/* -+ * The upper byte determines the class of the action; the low bytes determines -+ * the specific action within that class. The classes of actions are as -+ * follows: -+ * -+ * [ no class ] <= May record process- or kernel-related data -+ * DTRACEACT_PROC <= Only records process-related data -+ * DTRACEACT_PROC_DESTRUCTIVE <= Potentially destructive to processes -+ * DTRACEACT_KERNEL <= Only records kernel-related data -+ * DTRACEACT_KERNEL_DESTRUCTIVE <= Potentially destructive to the kernel -+ * DTRACEACT_SPECULATIVE <= Speculation-related action -+ * DTRACEACT_AGGREGATION <= Aggregating action -+ */ -+#define DTRACEACT_NONE 0 /* no action */ -+#define DTRACEACT_DIFEXPR 1 /* action is DIF expression */ -+#define DTRACEACT_EXIT 2 /* exit() action */ -+#define DTRACEACT_PRINTF 3 /* printf() action */ -+#define DTRACEACT_PRINTA 4 /* printa() action */ -+#define DTRACEACT_LIBACT 5 /* library-controlled action */ -+#define DTRACEACT_TRACEMEM 6 /* tracemem() action */ -+#define DTRACEACT_PCAP 7 /* pcap() action */ -+ -+#define DTRACEACT_PROC 0x0100 -+#define DTRACEACT_USTACK (DTRACEACT_PROC + 1) -+#define DTRACEACT_JSTACK (DTRACEACT_PROC + 2) -+#define DTRACEACT_USYM (DTRACEACT_PROC + 3) -+#define DTRACEACT_UMOD (DTRACEACT_PROC + 4) -+#define DTRACEACT_UADDR (DTRACEACT_PROC + 5) -+ -+#define DTRACEACT_PROC_DESTRUCTIVE 0x0200 -+#define DTRACEACT_STOP (DTRACEACT_PROC_DESTRUCTIVE + 1) -+#define DTRACEACT_RAISE (DTRACEACT_PROC_DESTRUCTIVE + 2) -+#define DTRACEACT_SYSTEM (DTRACEACT_PROC_DESTRUCTIVE + 3) -+#define DTRACEACT_FREOPEN (DTRACEACT_PROC_DESTRUCTIVE + 4) -+ -+#define DTRACEACT_PROC_CONTROL 0x0300 -+ -+#define DTRACEACT_KERNEL 0x0400 -+#define DTRACEACT_STACK (DTRACEACT_KERNEL + 1) -+#define DTRACEACT_SYM (DTRACEACT_KERNEL + 2) -+#define DTRACEACT_MOD (DTRACEACT_KERNEL + 3) -+ -+#define DTRACEACT_KERNEL_DESTRUCTIVE 0x0500 -+#define DTRACEACT_BREAKPOINT (DTRACEACT_KERNEL_DESTRUCTIVE + 1) -+#define DTRACEACT_PANIC (DTRACEACT_KERNEL_DESTRUCTIVE + 2) -+#define DTRACEACT_CHILL (DTRACEACT_KERNEL_DESTRUCTIVE + 3) -+ -+#define DTRACEACT_SPECULATIVE 0x0600 -+#define DTRACEACT_SPECULATE (DTRACEACT_SPECULATIVE + 1) -+#define DTRACEACT_COMMIT (DTRACEACT_SPECULATIVE + 2) -+#define DTRACEACT_DISCARD (DTRACEACT_SPECULATIVE + 3) -+ -+#define DTRACEACT_CLASS(x) ((x) & 0xff00) -+ -+#define DTRACEACT_ISAGG(x) \ -+ (DTRACEACT_CLASS(x) == DTRACEACT_AGGREGATION) -+ -+#define DTRACEACT_ISDESTRUCTIVE(x) \ -+ (DTRACEACT_CLASS(x) == DTRACEACT_PROC_DESTRUCTIVE || \ -+ DTRACEACT_CLASS(x) == DTRACEACT_KERNEL_DESTRUCTIVE) -+ -+#define DTRACEACT_ISSPECULATIVE(x) \ -+ (DTRACEACT_CLASS(x) == DTRACEACT_SPECULATIVE) -+ -+#define DTRACEACT_ISPRINTFLIKE(x) \ -+ ((x) == DTRACEACT_PRINTF || (x) == DTRACEACT_PRINTA || \ -+ (x) == DTRACEACT_SYSTEM || (x) == DTRACEACT_FREOPEN) -+ -+/* -+ * DTrace Aggregating Actions -+ * -+ * These are functions f(x) for which the following is true: -+ * -+ * f(f(x_0) U f(x_1) U ... U f(x_n)) = f(x_0 U x_1 U ... U x_n) -+ * -+ * where x_n is a set of arbitrary data. Aggregating actions are in their own -+ * DTrace action class, DTTRACEACT_AGGREGATION. The macros provided here allow -+ * for easier processing of the aggregation argument and data payload for a few -+ * aggregating actions (notably: quantize(), lquantize(), and ustack()). -+ */ -+ -+#define DTRACEACT_AGGREGATION 0x0700 -+#define DTRACEAGG_COUNT (DTRACEACT_AGGREGATION + 1) -+#define DTRACEAGG_MIN (DTRACEACT_AGGREGATION + 2) -+#define DTRACEAGG_MAX (DTRACEACT_AGGREGATION + 3) -+#define DTRACEAGG_AVG (DTRACEACT_AGGREGATION + 4) -+#define DTRACEAGG_SUM (DTRACEACT_AGGREGATION + 5) -+#define DTRACEAGG_STDDEV (DTRACEACT_AGGREGATION + 6) -+#define DTRACEAGG_QUANTIZE (DTRACEACT_AGGREGATION + 7) -+#define DTRACEAGG_LQUANTIZE (DTRACEACT_AGGREGATION + 8) -+#define DTRACEAGG_LLQUANTIZE (DTRACEACT_AGGREGATION + 9) -+ -+#define DTRACE_QUANTIZE_NBUCKETS \ -+ (((sizeof(uint64_t) * NBBY) - 1) * 2 + 1) -+ -+#define DTRACE_QUANTIZE_ZEROBUCKET ((sizeof(uint64_t) * NBBY) - 1) -+ -+#define DTRACE_QUANTIZE_BUCKETVAL(buck) \ -+ (int64_t)((buck) < DTRACE_QUANTIZE_ZEROBUCKET ? \ -+ -(1LL << (DTRACE_QUANTIZE_ZEROBUCKET - 1 - (buck))) : \ -+ (buck) == DTRACE_QUANTIZE_ZEROBUCKET ? 0 : \ -+ 1LL << ((buck) - DTRACE_QUANTIZE_ZEROBUCKET - 1)) -+ -+#define DTRACE_LQUANTIZE_STEPSHIFT 48 -+#define DTRACE_LQUANTIZE_STEPMASK ((uint64_t)UINT16_MAX << 48) -+#define DTRACE_LQUANTIZE_LEVELSHIFT 32 -+#define DTRACE_LQUANTIZE_LEVELMASK ((uint64_t)UINT16_MAX << 32) -+#define DTRACE_LQUANTIZE_BASESHIFT 0 -+#define DTRACE_LQUANTIZE_BASEMASK UINT32_MAX -+ -+#define DTRACE_LQUANTIZE_STEP(x) \ -+ (uint16_t)(((x) & DTRACE_LQUANTIZE_STEPMASK) >> \ -+ DTRACE_LQUANTIZE_STEPSHIFT) -+ -+#define DTRACE_LQUANTIZE_LEVELS(x) \ -+ (uint16_t)(((x) & DTRACE_LQUANTIZE_LEVELMASK) >> \ -+ DTRACE_LQUANTIZE_LEVELSHIFT) -+ -+#define DTRACE_LQUANTIZE_BASE(x) \ -+ (int32_t)(((x) & DTRACE_LQUANTIZE_BASEMASK) >> \ -+ DTRACE_LQUANTIZE_BASESHIFT) -+ -+#define DTRACE_LLQUANTIZE_STEPSSHIFT 48 -+#define DTRACE_LLQUANTIZE_STEPSMASK ((uint64_t)UINT16_MAX << 48) -+#define DTRACE_LLQUANTIZE_HMAGSHIFT 32 -+#define DTRACE_LLQUANTIZE_HMAGMASK ((uint64_t)UINT16_MAX << 32) -+#define DTRACE_LLQUANTIZE_LMAGSHIFT 16 -+#define DTRACE_LLQUANTIZE_LMAGMASK ((uint64_t)UINT16_MAX << 16) -+#define DTRACE_LLQUANTIZE_FACTORSHIFT 0 -+#define DTRACE_LLQUANTIZE_FACTORMASK UINT16_MAX -+ -+#define DTRACE_LLQUANTIZE_STEPS(x) \ -+ (uint16_t)(((x) & DTRACE_LLQUANTIZE_STEPSMASK) >> \ -+ DTRACE_LLQUANTIZE_STEPSSHIFT) -+ -+#define DTRACE_LLQUANTIZE_HMAG(x) \ -+ (uint16_t)(((x) & DTRACE_LLQUANTIZE_HMAGMASK) >> \ -+ DTRACE_LLQUANTIZE_HMAGSHIFT) -+ -+#define DTRACE_LLQUANTIZE_LMAG(x) \ -+ (uint16_t)(((x) & DTRACE_LLQUANTIZE_LMAGMASK) >> \ -+ DTRACE_LLQUANTIZE_LMAGSHIFT) -+ -+#define DTRACE_LLQUANTIZE_FACTOR(x) \ -+ (uint16_t)(((x) & DTRACE_LLQUANTIZE_FACTORMASK) >> \ -+ DTRACE_LLQUANTIZE_FACTORSHIFT) -+ -+#define DTRACE_USTACK_NFRAMES(x) (uint32_t)((x) & UINT32_MAX) -+#define DTRACE_USTACK_STRSIZE(x) (uint32_t)((x) >> 32) -+#define DTRACE_USTACK_ARG(x, y) \ -+ ((((uint64_t)(y)) << 32) | ((x) & UINT32_MAX)) -+ -+#ifndef _LP64 -+# ifndef _LITTLE_ENDIAN -+# define DTRACE_PTR(type, name) uint32_t name##pad; type *name -+# else -+# define DTRACE_PTR(type, name) type *name; uint32_t name##pad -+# endif -+#else -+# define DTRACE_PTR(type, name) type *name -+#endif -+ -+#endif /* _LINUX_DTRACE_ACTIONS_DEFINES_H */ -diff --git a/include/uapi/linux/dtrace/arg.h b/include/uapi/linux/dtrace/arg.h -new file mode 100644 -index 000000000000..4a9099a816e6 ---- /dev/null -+++ b/include/uapi/linux/dtrace/arg.h -@@ -0,0 +1,42 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_ARG_H -+#define _LINUX_DTRACE_ARG_H -+ -+#include <linux/dtrace/universal.h> -+#include <linux/dtrace/arg_defines.h> -+ -+/* -+ * Because it would waste both space and time, argument types do not reside -+ * with the probe. In order to determine argument types for args[X] -+ * variables, the D compiler queries for argument types on a probe-by-probe -+ * basis. (This optimizes for the common case that arguments are either not -+ * used or used in an untyped fashion.) Typed arguments are specified with a -+ * string of the type name in the dtragd_native member of the argument -+ * description structure. Typed arguments may be further translated to types -+ * of greater stability; the provider indicates such a translated argument by -+ * filling in the dtargd_xlate member with the string of the translated type. -+ * Finally, the provider may indicate which argument value a given argument -+ * maps to by setting the dtargd_mapping member -- allowing a single argument -+ * to map to multiple args[X] variables. -+ */ -+typedef struct dtrace_argdesc { -+ dtrace_id_t dtargd_id; -+ int dtargd_ndx; -+ int dtargd_mapping; -+ char dtargd_native[DTRACE_ARGTYPELEN]; -+ char dtargd_xlate[DTRACE_ARGTYPELEN]; -+} dtrace_argdesc_t; -+ -+#endif /* _LINUX_DTRACE_ARG_H */ -diff --git a/include/uapi/linux/dtrace/arg_defines.h b/include/uapi/linux/dtrace/arg_defines.h -new file mode 100644 -index 000000000000..72862cd1b8e6 ---- /dev/null -+++ b/include/uapi/linux/dtrace/arg_defines.h -@@ -0,0 +1,21 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_ARG_DEFINES_H -+#define _LINUX_DTRACE_ARG_DEFINES_H -+ -+#include <linux/dtrace/universal.h> -+ -+struct dtrace_argdesc; -+ -+#endif /* _LINUX_DTRACE_ARG_DEFINES_H */ -diff --git a/include/uapi/linux/dtrace/buffer.h b/include/uapi/linux/dtrace/buffer.h -new file mode 100644 -index 000000000000..9bbbc4f1f14b ---- /dev/null -+++ b/include/uapi/linux/dtrace/buffer.h -@@ -0,0 +1,43 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_BUFFER_H -+#define _LINUX_DTRACE_BUFFER_H -+ -+#include <linux/dtrace/universal.h> -+#include <linux/dtrace/actions_defines.h> -+#include <linux/dtrace/buffer_defines.h> -+ -+/* -+ * In order to get a snapshot of the principal or aggregation buffer, -+ * user-level passes a buffer description to the kernel with the dtrace_bufdesc -+ * structure. This describes which CPU user-level is interested in, and -+ * where user-level wishes the kernel to snapshot the buffer to (the -+ * dtbd_data field). The kernel uses the same structure to pass back some -+ * information regarding the buffer: the size of data actually copied out, the -+ * number of drops, the number of errors, and the offset of the oldest record. -+ * If the buffer policy is a "switch" policy, taking a snapshot of the -+ * principal buffer has the additional effect of switching the active and -+ * inactive buffers. Taking a snapshot of the aggregation buffer _always_ has -+ * the additional effect of switching the active and inactive buffers. -+ */ -+typedef struct dtrace_bufdesc { -+ uint64_t dtbd_size; /* size of buffer */ -+ uint32_t dtbd_cpu; /* CPU or DTRACE_CPUALL */ -+ uint32_t dtbd_errors; /* number of errors */ -+ uint64_t dtbd_drops; /* number of drops */ -+ DTRACE_PTR(char, dtbd_data); /* data */ -+ uint64_t dtbd_oldest; /* offset of oldest record */ -+} dtrace_bufdesc_t; -+ -+#endif /* _LINUX_DTRACE_BUFFER_H */ -diff --git a/include/uapi/linux/dtrace/buffer_defines.h b/include/uapi/linux/dtrace/buffer_defines.h -new file mode 100644 -index 000000000000..16c3c193618a ---- /dev/null -+++ b/include/uapi/linux/dtrace/buffer_defines.h -@@ -0,0 +1,21 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_BUFFER_DEFINES_H -+#define _LINUX_DTRACE_BUFFER_DEFINES_H -+ -+#include <linux/dtrace/universal.h> -+ -+struct dtrace_bufdesc; -+ -+#endif /* _LINUX_DTRACE_BUFFER_DEFINES_H */ -diff --git a/include/uapi/linux/dtrace/conf.h b/include/uapi/linux/dtrace/conf.h -new file mode 100644 -index 000000000000..95b201958f4c ---- /dev/null -+++ b/include/uapi/linux/dtrace/conf.h -@@ -0,0 +1,35 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_CONF_H -+#define _LINUX_DTRACE_CONF_H -+ -+#include <linux/dtrace/universal.h> -+#include <linux/dtrace/conf_defines.h> -+ -+/* -+ * User-level may need to understand some elements of the kernel DTrace -+ * configuration in order to generate correct DIF. This information is -+ * conveyed via the dtrace_conf structure. -+ */ -+typedef struct dtrace_conf { -+ uint_t dtc_difversion; /* supported DIF version */ -+ uint_t dtc_difintregs; /* # of DIF integer registers */ -+ uint_t dtc_diftupregs; /* # of DIF tuple registers */ -+ uint_t dtc_ctfmodel; /* CTF data model */ -+ /* Deviation from Solaris... Used to just be 8 padding entries. */ -+ uint_t dtc_maxbufs; /* max # of buffers */ -+ uint_t dtc_pad[7]; /* reserved for future use */ -+} dtrace_conf_t; -+ -+#endif /* _LINUX_DTRACE_CONF_H */ -diff --git a/include/uapi/linux/dtrace/conf_defines.h b/include/uapi/linux/dtrace/conf_defines.h -new file mode 100644 -index 000000000000..5c4a1cb5d37c ---- /dev/null -+++ b/include/uapi/linux/dtrace/conf_defines.h -@@ -0,0 +1,21 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_CONF_DEFINES_H -+#define _LINUX_DTRACE_CONF_DEFINES_H -+ -+#include <linux/dtrace/universal.h> -+ -+struct dtrace_conf; -+ -+#endif /* _LINUX_DTRACE_CONF_DEFINES_H */ -diff --git a/include/uapi/linux/dtrace/cpu_defines.h b/include/uapi/linux/dtrace/cpu_defines.h -new file mode 100644 -index 000000000000..a1cd3e410ccc ---- /dev/null -+++ b/include/uapi/linux/dtrace/cpu_defines.h -@@ -0,0 +1,17 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+#ifndef _LINUX_DTRACE_CPU_DEFINES_H_ -+#define _LINUX_DTRACE_CPU_DEFINES_H_ -+ -+typedef uint32_t processorid_t; -+typedef uint32_t psetid_t; -+typedef uint32_t chipid_t; -+typedef uint32_t lgrp_id_t; -+ -+#endif /* _LINUX_DTRACE_CPU_DEFINES_H_ */ -diff --git a/include/uapi/linux/dtrace/dif.h b/include/uapi/linux/dtrace/dif.h -new file mode 100644 -index 000000000000..92daea17a1f1 ---- /dev/null -+++ b/include/uapi/linux/dtrace/dif.h -@@ -0,0 +1,60 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_DIF_H -+#define _LINUX_DTRACE_DIF_H -+ -+#include <linux/dtrace/universal.h> -+#include <linux/dtrace/dif_defines.h> -+ -+/* -+ * The following definitions describe the DTrace Intermediate Format (DIF), a a -+ * RISC-like instruction set and program encoding used to represent predicates -+ * and actions that can be bound to DTrace probes. The constants below defining -+ * the number of available registers are suggested minimums; the compiler should -+ * use DTRACEIOC_CONF to dynamically obtain the number of registers provided by -+ * the current DTrace implementation. -+ */ -+ -+/* -+ * A DTrace Intermediate Format Type (DIF Type) is used to represent the types -+ * of variables, function and associative array arguments, and the return type -+ * for each DIF object (shown below). It contains a description of the type, -+ * its size in bytes, and a module identifier. -+ */ -+ -+typedef struct dtrace_diftype { -+ uint8_t dtdt_kind; -+ uint8_t dtdt_ckind; -+ uint8_t dtdt_flags; -+ uint8_t dtdt_pad; -+ uint32_t dtdt_size; -+} dtrace_diftype_t; -+ -+/* -+ * A DTrace Intermediate Format variable record is used to describe each of the -+ * variables referenced by a given DIF object. It contains an integer variable -+ * identifier along with variable scope and properties, as shown below. The -+ * size of this structure must be sizeof (int) aligned. -+ */ -+ -+typedef struct dtrace_difv { -+ uint32_t dtdv_name; -+ uint32_t dtdv_id; -+ uint8_t dtdv_kind; -+ uint8_t dtdv_scope; -+ uint16_t dtdv_flags; -+ struct dtrace_diftype dtdv_type; -+} dtrace_difv_t; -+ -+#endif /* _LINUX_DTRACE_DIF_H */ -diff --git a/include/uapi/linux/dtrace/dif_defines.h b/include/uapi/linux/dtrace/dif_defines.h -new file mode 100644 -index 000000000000..80b913f097a2 ---- /dev/null -+++ b/include/uapi/linux/dtrace/dif_defines.h -@@ -0,0 +1,288 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_DIF_DEFINES_H -+#define _LINUX_DTRACE_DIF_DEFINES_H -+ -+#include <linux/dtrace/universal.h> -+ -+/* -+ * The following definitions describe the DTrace Intermediate Format (DIF), a a -+ * RISC-like instruction set and program encoding used to represent predicates -+ * and actions that can be bound to DTrace probes. The constants below defining -+ * the number of available registers are suggested minimums; the compiler should -+ * use DTRACEIOC_CONF to dynamically obtain the number of registers provided by -+ * the current DTrace implementation. -+ */ -+ -+#define DIF_VERSION_1 1 -+#define DIF_VERSION_2 2 -+#define DIF_VERSION DIF_VERSION_2 -+#define DIF_DIR_NREGS 8 /* number of DIF integer registers */ -+#define DIF_DTR_NREGS 8 /* number of DIF tuple registers */ -+ -+#define DIF_OP_OR 1 /* or r1, r2, rd */ -+#define DIF_OP_XOR 2 /* xor r1, r2, rd */ -+#define DIF_OP_AND 3 /* and r1, r2, rd */ -+#define DIF_OP_SLL 4 /* sll r1, r2, rd */ -+#define DIF_OP_SRL 5 /* srl r1, r2, rd */ -+#define DIF_OP_SUB 6 /* sub r1, r2, rd */ -+#define DIF_OP_ADD 7 /* add r1, r2, rd */ -+#define DIF_OP_MUL 8 /* mul r1, r2, rd */ -+#define DIF_OP_SDIV 9 /* sdiv r1, r2, rd */ -+#define DIF_OP_UDIV 10 /* udiv r1, r2, rd */ -+#define DIF_OP_SREM 11 /* srem r1, r2, rd */ -+#define DIF_OP_UREM 12 /* urem r1, r2, rd */ -+#define DIF_OP_NOT 13 /* not r1, rd */ -+#define DIF_OP_MOV 14 /* mov r1, rd */ -+#define DIF_OP_CMP 15 /* cmp r1, r2 */ -+#define DIF_OP_TST 16 /* tst r1 */ -+#define DIF_OP_BA 17 /* ba label */ -+#define DIF_OP_BE 18 /* be label */ -+#define DIF_OP_BNE 19 /* bne label */ -+#define DIF_OP_BG 20 /* bg label */ -+#define DIF_OP_BGU 21 /* bgu label */ -+#define DIF_OP_BGE 22 /* bge label */ -+#define DIF_OP_BGEU 23 /* bgeu label */ -+#define DIF_OP_BL 24 /* bl label */ -+#define DIF_OP_BLU 25 /* blu label */ -+#define DIF_OP_BLE 26 /* ble label */ -+#define DIF_OP_BLEU 27 /* bleu label */ -+#define DIF_OP_LDSB 28 /* ldsb [r1], rd */ -+#define DIF_OP_LDSH 29 /* ldsh [r1], rd */ -+#define DIF_OP_LDSW 30 /* ldsw [r1], rd */ -+#define DIF_OP_LDUB 31 /* ldub [r1], rd */ -+#define DIF_OP_LDUH 32 /* lduh [r1], rd */ -+#define DIF_OP_LDUW 33 /* lduw [r1], rd */ -+#define DIF_OP_LDX 34 /* ldx [r1], rd */ -+#define DIF_OP_RET 35 /* ret rd */ -+#define DIF_OP_NOP 36 /* nop */ -+#define DIF_OP_SETX 37 /* setx intindex, rd */ -+#define DIF_OP_SETS 38 /* sets strindex, rd */ -+#define DIF_OP_SCMP 39 /* scmp r1, r2 */ -+#define DIF_OP_LDGA 40 /* ldga var, ri, rd */ -+#define DIF_OP_LDGS 41 /* ldgs var, rd */ -+#define DIF_OP_STGS 42 /* stgs var, rs */ -+#define DIF_OP_LDTA 43 /* ldta var, ri, rd */ -+#define DIF_OP_LDTS 44 /* ldts var, rd */ -+#define DIF_OP_STTS 45 /* stts var, rs */ -+#define DIF_OP_SRA 46 /* sra r1, r2, rd */ -+#define DIF_OP_CALL 47 /* call subr, rd */ -+#define DIF_OP_PUSHTR 48 /* pushtr type, rs, rr */ -+#define DIF_OP_PUSHTV 49 /* pushtv type, rs, rv */ -+#define DIF_OP_POPTS 50 /* popts */ -+#define DIF_OP_FLUSHTS 51 /* flushts */ -+#define DIF_OP_LDGAA 52 /* ldgaa var, rd */ -+#define DIF_OP_LDTAA 53 /* ldtaa var, rd */ -+#define DIF_OP_STGAA 54 /* stgaa var, rs */ -+#define DIF_OP_STTAA 55 /* sttaa var, rs */ -+#define DIF_OP_LDLS 56 /* ldls var, rd */ -+#define DIF_OP_STLS 57 /* stls var, rs */ -+#define DIF_OP_ALLOCS 58 /* allocs r1, rd */ -+#define DIF_OP_COPYS 59 /* copys r1, r2, rd */ -+#define DIF_OP_STB 60 /* stb r1, [rd] */ -+#define DIF_OP_STH 61 /* sth r1, [rd] */ -+#define DIF_OP_STW 62 /* stw r1, [rd] */ -+#define DIF_OP_STX 63 /* stx r1, [rd] */ -+#define DIF_OP_ULDSB 64 /* uldsb [r1], rd */ -+#define DIF_OP_ULDSH 65 /* uldsh [r1], rd */ -+#define DIF_OP_ULDSW 66 /* uldsw [r1], rd */ -+#define DIF_OP_ULDUB 67 /* uldub [r1], rd */ -+#define DIF_OP_ULDUH 68 /* ulduh [r1], rd */ -+#define DIF_OP_ULDUW 69 /* ulduw [r1], rd */ -+#define DIF_OP_ULDX 70 /* uldx [r1], rd */ -+#define DIF_OP_RLDSB 71 /* rldsb [r1], rd */ -+#define DIF_OP_RLDSH 72 /* rldsh [r1], rd */ -+#define DIF_OP_RLDSW 73 /* rldsw [r1], rd */ -+#define DIF_OP_RLDUB 74 /* rldub [r1], rd */ -+#define DIF_OP_RLDUH 75 /* rlduh [r1], rd */ -+#define DIF_OP_RLDUW 76 /* rlduw [r1], rd */ -+#define DIF_OP_RLDX 77 /* rldx [r1], rd */ -+#define DIF_OP_XLATE 78 /* xlate xlrindex, rd */ -+#define DIF_OP_XLARG 79 /* xlarg xlrindex, rd */ -+ -+#define DIF_INTOFF_MAX 0xffff /* highest integer table offset */ -+#define DIF_STROFF_MAX 0xffff /* highest string table offset */ -+#define DIF_REGISTER_MAX 0xff /* highest register number */ -+#define DIF_VARIABLE_MAX 0xffff /* highest variable identifier */ -+#define DIF_SUBROUTINE_MAX 0xffff /* highest subroutine code */ -+ -+#define DIF_VAR_ARRAY_MIN 0x0000 /* lowest numbered array variable */ -+#define DIF_VAR_ARRAY_UBASE 0x0080 /* lowest user-defined array */ -+#define DIF_VAR_ARRAY_MAX 0x00ff /* highest numbered array variable */ -+ -+#define DIF_VAR_OTHER_MIN 0x0100 /* lowest numbered scalar or assc */ -+#define DIF_VAR_OTHER_UBASE 0x0500 /* lowest user-defined scalar or assc */ -+#define DIF_VAR_OTHER_MAX 0xffff /* highest numbered scalar or assc */ -+ -+#define DIF_VAR_ARGS 0x0000 -+#define DIF_VAR_REGS 0x0001 -+#define DIF_VAR_UREGS 0x0002 -+#define DIF_VAR_CURTHREAD 0x0100 -+#define DIF_VAR_TIMESTAMP 0x0101 -+#define DIF_VAR_VTIMESTAMP 0x0102 -+#define DIF_VAR_IPL 0x0103 -+#define DIF_VAR_EPID 0x0104 -+#define DIF_VAR_ID 0x0105 -+#define DIF_VAR_ARG0 0x0106 -+#define DIF_VAR_ARG1 0x0107 -+#define DIF_VAR_ARG2 0x0108 -+#define DIF_VAR_ARG3 0x0109 -+#define DIF_VAR_ARG4 0x010a -+#define DIF_VAR_ARG5 0x010b -+#define DIF_VAR_ARG6 0x010c -+#define DIF_VAR_ARG7 0x010d -+#define DIF_VAR_ARG8 0x010e -+#define DIF_VAR_ARG9 0x010f -+#define DIF_VAR_STACKDEPTH 0x0110 -+#define DIF_VAR_CALLER 0x0111 -+#define DIF_VAR_PROBEPROV 0x0112 -+#define DIF_VAR_PROBEMOD 0x0113 -+#define DIF_VAR_PROBEFUNC 0x0114 -+#define DIF_VAR_PROBENAME 0x0115 -+#define DIF_VAR_PID 0x0116 -+#define DIF_VAR_TID 0x0117 -+#define DIF_VAR_EXECNAME 0x0118 -+#define DIF_VAR_ZONENAME 0x0119 -+#define DIF_VAR_WALLTIMESTAMP 0x011a -+#define DIF_VAR_USTACKDEPTH 0x011b -+#define DIF_VAR_UCALLER 0x011c -+#define DIF_VAR_PPID 0x011d -+#define DIF_VAR_UID 0x011e -+#define DIF_VAR_GID 0x011f -+#define DIF_VAR_ERRNO 0x0120 -+#define DIF_VAR_CURCPU 0x0121 -+ -+#define DIF_SUBR_RAND 0 -+#define DIF_SUBR_MUTEX_OWNED 1 -+#define DIF_SUBR_MUTEX_OWNER 2 -+#define DIF_SUBR_MUTEX_TYPE_ADAPTIVE 3 -+#define DIF_SUBR_MUTEX_TYPE_SPIN 4 -+#define DIF_SUBR_RW_READ_HELD 5 -+#define DIF_SUBR_RW_WRITE_HELD 6 -+#define DIF_SUBR_RW_ISWRITER 7 -+#define DIF_SUBR_COPYIN 8 -+#define DIF_SUBR_COPYINSTR 9 -+#define DIF_SUBR_SPECULATION 10 -+#define DIF_SUBR_PROGENYOF 11 -+#define DIF_SUBR_STRLEN 12 -+#define DIF_SUBR_COPYOUT 13 -+#define DIF_SUBR_COPYOUTSTR 14 -+#define DIF_SUBR_ALLOCA 15 -+#define DIF_SUBR_BCOPY 16 -+#define DIF_SUBR_COPYINTO 17 -+#define DIF_SUBR_MSGDSIZE 18 -+#define DIF_SUBR_MSGSIZE 19 -+#define DIF_SUBR_GETMAJOR 20 -+#define DIF_SUBR_GETMINOR 21 -+#define DIF_SUBR_DDI_PATHNAME 22 -+#define DIF_SUBR_STRJOIN 23 -+#define DIF_SUBR_LLTOSTR 24 -+#define DIF_SUBR_BASENAME 25 -+#define DIF_SUBR_DIRNAME 26 -+#define DIF_SUBR_CLEANPATH 27 -+#define DIF_SUBR_STRCHR 28 -+#define DIF_SUBR_STRRCHR 29 -+#define DIF_SUBR_STRSTR 30 -+#define DIF_SUBR_STRTOK 31 -+#define DIF_SUBR_SUBSTR 32 -+#define DIF_SUBR_INDEX 33 -+#define DIF_SUBR_RINDEX 34 -+#define DIF_SUBR_HTONS 35 -+#define DIF_SUBR_HTONL 36 -+#define DIF_SUBR_HTONLL 37 -+#define DIF_SUBR_NTOHS 38 -+#define DIF_SUBR_NTOHL 39 -+#define DIF_SUBR_NTOHLL 40 -+#define DIF_SUBR_INET_NTOP 41 -+#define DIF_SUBR_INET_NTOA 42 -+#define DIF_SUBR_INET_NTOA6 43 -+#define DIF_SUBR_D_PATH 44 -+#define DIF_SUBR_LINK_NTOP 45 -+ -+#define DIF_SUBR_MAX 45 -+ -+typedef uint32_t dif_instr_t; -+ -+#define DIF_INSTR_OP(i) (((i) >> 24) & 0xff) -+#define DIF_INSTR_R1(i) (((i) >> 16) & 0xff) -+#define DIF_INSTR_R2(i) (((i) >> 8) & 0xff) -+#define DIF_INSTR_RD(i) ((i) & 0xff) -+#define DIF_INSTR_RS(i) ((i) & 0xff) -+#define DIF_INSTR_LABEL(i) ((i) & 0xffffff) -+#define DIF_INSTR_VAR(i) (((i) >> 8) & 0xffff) -+#define DIF_INSTR_INTEGER(i) (((i) >> 8) & 0xffff) -+#define DIF_INSTR_STRING(i) (((i) >> 8) & 0xffff) -+#define DIF_INSTR_SUBR(i) (((i) >> 8) & 0xffff) -+#define DIF_INSTR_TYPE(i) (((i) >> 16) & 0xff) -+#define DIF_INSTR_XLREF(i) (((i) >> 8) & 0xffff) -+#define DIF_INSTR_FMT(op, r1, r2, d) \ -+ (((op) << 24) | ((r1) << 16) | ((r2) << 8) | (d)) -+ -+#define DIF_INSTR_NOT(r1, d) (DIF_INSTR_FMT(DIF_OP_NOT, r1, 0, d)) -+#define DIF_INSTR_MOV(r1, d) (DIF_INSTR_FMT(DIF_OP_MOV, r1, 0, d)) -+#define DIF_INSTR_CMP(op, r1, r2) (DIF_INSTR_FMT(op, r1, r2, 0)) -+#define DIF_INSTR_TST(r1) (DIF_INSTR_FMT(DIF_OP_TST, r1, 0, 0)) -+#define DIF_INSTR_BRANCH(op, label) (((op) << 24) | (label)) -+#define DIF_INSTR_LOAD(op, r1, d) (DIF_INSTR_FMT(op, r1, 0, d)) -+#define DIF_INSTR_STORE(op, r1, d) (DIF_INSTR_FMT(op, r1, 0, d)) -+#define DIF_INSTR_SETX(i, d) ((DIF_OP_SETX << 24) | ((i) << 8) | (d)) -+#define DIF_INSTR_SETS(s, d) ((DIF_OP_SETS << 24) | ((s) << 8) | (d)) -+#define DIF_INSTR_RET(d) (DIF_INSTR_FMT(DIF_OP_RET, 0, 0, d)) -+#define DIF_INSTR_NOP (DIF_OP_NOP << 24) -+#define DIF_INSTR_LDA(op, v, r, d) (DIF_INSTR_FMT(op, v, r, d)) -+#define DIF_INSTR_LDV(op, v, d) (((op) << 24) | ((v) << 8) | (d)) -+#define DIF_INSTR_STV(op, v, rs) (((op) << 24) | ((v) << 8) | (rs)) -+#define DIF_INSTR_CALL(s, d) ((DIF_OP_CALL << 24) | ((s) << 8) | (d)) -+#define DIF_INSTR_PUSHTS(op, t, r2, rs) (DIF_INSTR_FMT(op, t, r2, rs)) -+#define DIF_INSTR_POPTS (DIF_OP_POPTS << 24) -+#define DIF_INSTR_FLUSHTS (DIF_OP_FLUSHTS << 24) -+#define DIF_INSTR_ALLOCS(r1, d) (DIF_INSTR_FMT(DIF_OP_ALLOCS, r1, 0, d)) -+#define DIF_INSTR_COPYS(r1, r2, d) (DIF_INSTR_FMT(DIF_OP_COPYS, r1, r2, d)) -+#define DIF_INSTR_XLATE(op, r, d) (((op) << 24) | ((r) << 8) | (d)) -+ -+#define DIF_REG_R0 0 -+ -+/* -+ * A DTrace Intermediate Format Type (DIF Type) is used to represent the types -+ * of variables, function and associative array arguments, and the return type -+ * for each DIF object (shown below). It contains a description of the type, -+ * its size in bytes, and a module identifier. -+ */ -+ -+#define DIF_TYPE_CTF 0 -+#define DIF_TYPE_STRING 1 -+ -+#define DIF_TF_BYREF 0x1 -+ -+/* -+ * A DTrace Intermediate Format variable record is used to describe each of the -+ * variables referenced by a given DIF object. It contains an integer variable -+ * identifier along with variable scope and properties, as shown below. The -+ * size of this structure must be sizeof (int) aligned. -+ */ -+ -+#define DIFV_KIND_ARRAY 0 -+#define DIFV_KIND_SCALAR 1 -+ -+#define DIFV_SCOPE_GLOBAL 0 -+#define DIFV_SCOPE_THREAD 1 -+#define DIFV_SCOPE_LOCAL 2 -+ -+#define DIFV_F_REF 0x1 -+#define DIFV_F_MOD 0x2 -+ -+struct dtrace_diftype; -+struct dtrace_difv; -+ -+#endif /* _LINUX_DTRACE_DIF_DEFINES_H */ -diff --git a/include/uapi/linux/dtrace/difo.h b/include/uapi/linux/dtrace/difo.h -new file mode 100644 -index 000000000000..6e9efd7f0a43 ---- /dev/null -+++ b/include/uapi/linux/dtrace/difo.h -@@ -0,0 +1,57 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_DIFO_H -+#define _LINUX_DTRACE_DIFO_H -+ -+#include <linux/dtrace/universal.h> -+#include <linux/dtrace/dif.h> -+#include <linux/dtrace/dof_defines.h> -+ -+/* -+ * A DIFO is used to store the compiled DIF for a D expression, its return -+ * type, and its string and variable tables. The string table is a single -+ * buffer of character data into which sets instructions and variable -+ * references can reference strings using a byte offset. The variable table -+ * is an array of dtrace_difv_t structures that describe the name and type of -+ * each variable and the id used in the DIF code. This structure is described -+ * above in the DIF section of this header file. The DIFO is used at both -+ * user-level (in the library) and in the kernel, but the structure is never -+ * passed between the two: the DOF structures form the only interface. As a -+ * result, the definition can change depending on the presence of _KERNEL. -+ */ -+ -+typedef struct dtrace_difo { -+ dif_instr_t *dtdo_buf; /* instruction buffer */ -+ uint64_t *dtdo_inttab; /* integer table (optional) */ -+ char *dtdo_strtab; /* string table (optional) */ -+ struct dtrace_difv *dtdo_vartab; /* variable table (optional) */ -+ uint_t dtdo_len; /* length of instruction buffer */ -+ uint_t dtdo_intlen; /* length of integer table */ -+ uint_t dtdo_strlen; /* length of string table */ -+ uint_t dtdo_varlen; /* length of variable table */ -+ struct dtrace_diftype dtdo_rtype; /* return type */ -+ uint_t dtdo_refcnt; /* owner reference count */ -+ uint_t dtdo_destructive; /* invokes destructive subroutines */ -+#ifndef _KERNEL -+ struct dtrace_diftype orig_dtdo_rtype; /* original return type */ -+ struct dof_relodesc *dtdo_kreltab; /* kernel relocations */ -+ struct dof_relodesc *dtdo_ureltab; /* user relocations */ -+ struct dt_node **dtdo_xlmtab; /* translator references */ -+ uint_t dtdo_krelen; /* length of krelo table */ -+ uint_t dtdo_urelen; /* length of urelo table */ -+ uint_t dtdo_xlmlen; /* length of translator table */ -+#endif -+} dtrace_difo_t; -+ -+#endif /* _LINUX_DTRACE_DIFO_H */ -diff --git a/include/uapi/linux/dtrace/difo_defines.h b/include/uapi/linux/dtrace/difo_defines.h -new file mode 100644 -index 000000000000..fdd25f2b7691 ---- /dev/null -+++ b/include/uapi/linux/dtrace/difo_defines.h -@@ -0,0 +1,21 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_DIFO_DEFINES_H -+#define _LINUX_DTRACE_DIFO_DEFINES_H -+ -+#include <linux/dtrace/universal.h> -+ -+struct dtrace_difo; -+ -+#endif /* _LINUX_DTRACE_DIFO_DEFINES_H */ -diff --git a/include/uapi/linux/dtrace/dof.h b/include/uapi/linux/dtrace/dof.h -new file mode 100644 -index 000000000000..54c6ca710443 ---- /dev/null -+++ b/include/uapi/linux/dtrace/dof.h -@@ -0,0 +1,196 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_DOF_H -+#define _LINUX_DTRACE_DOF_H -+ -+#include <linux/dtrace/universal.h> -+#include <linux/dtrace/dif.h> -+#include <linux/dtrace/dof_defines.h> -+ -+/* -+ * DTrace programs can be persistently encoded in the DOF format so that they -+ * may be embedded in other programs (for example, in an ELF file) or in the -+ * dtrace driver configuration file for use in anonymous tracing. The DOF -+ * format is versioned and extensible so that it can be revised and so that -+ * internal data structures can be modified or extended compatibly. All DOF -+ * structures use fixed-size types, so the 32-bit and 64-bit representations -+ * are identical and consumers can use either data model transparently. -+ * -+ * The file layout is structured as follows: -+ * -+ * +---------------+-------------------+----- ... ----+---- ... ------+ -+ * | dof_hdr_t | dof_sec_t[ ... ] | loadable | non-loadable | -+ * | (file header) | (section headers) | section data | section data | -+ * +---------------+-------------------+----- ... ----+---- ... ------+ -+ * |<------------ dof_hdr.dofh_loadsz --------------->| | -+ * |<------------ dof_hdr.dofh_filesz ------------------------------->| -+ * -+ * The file header stores meta-data including a magic number, data model for -+ * the instrumentation, data encoding, and properties of the DIF code within. -+ * The header describes its own size and the size of the section headers. By -+ * convention, an array of section headers follows the file header, and then -+ * the data for all loadable sections and unloadable sections. This permits -+ * consumer code to easily download the headers and all loadable data into the -+ * DTrace driver in one contiguous chunk, omitting other extraneous sections. -+ * -+ * The section headers describe the size, offset, alignment, and section type -+ * for each section. Sections are described using a set of #defines that tell -+ * the consumer what kind of data is expected. Sections can contain links to -+ * other sections by storing a dof_secidx_t, an index into the section header -+ * array, inside of the section data structures. The section header includes -+ * an entry size so that sections with data arrays can grow their structures. -+ * -+ * The DOF data itself can contain many snippets of DIF (i.e. >1 DIFOs), which -+ * are represented themselves as a collection of related DOF sections. This -+ * permits us to change the set of sections associated with a DIFO over time, -+ * and also permits us to encode DIFOs that contain different sets of sections. -+ * When a DOF section wants to refer to a DIFO, it stores the dof_secidx_t of a -+ * section of type DOF_SECT_DIFOHDR. This section's data is then an array of -+ * dof_secidx_t's which in turn denote the sections associated with this DIFO. -+ * -+ * This loose coupling of the file structure (header and sections) to the -+ * structure of the DTrace program itself (ECB descriptions, action -+ * descriptions, and DIFOs) permits activities such as relocation processing -+ * to occur in a single pass without having to understand D program structure. -+ * -+ * Finally, strings are always stored in ELF-style string tables along with a -+ * string table section index and string table offset. Therefore strings in -+ * DOF are always arbitrary-length and not bound to the current implementation. -+ */ -+ -+typedef struct dof_hdr { -+ uint8_t dofh_ident[DOF_ID_SIZE];/* ident bytes (see defines) */ -+ uint32_t dofh_flags; /* file attribute flags (if any) */ -+ uint32_t dofh_hdrsize; /* size of file header in bytes */ -+ uint32_t dofh_secsize; /* size of section header in bytes */ -+ uint32_t dofh_secnum; /* number of section headers */ -+ uint64_t dofh_secoff; /* file offset of section headers */ -+ uint64_t dofh_loadsz; /* file size of loadable portion */ -+ uint64_t dofh_filesz; /* file size of entire DOF file */ -+ uint64_t dofh_pad; /* reserved for future use */ -+} dof_hdr_t; -+ -+typedef struct dof_sec { -+ uint32_t dofs_type; /* section type (see defines) */ -+ uint32_t dofs_align; /* section data memory alignment */ -+ uint32_t dofs_flags; /* section flags (if any) */ -+ uint32_t dofs_entsize; /* size of section entry (if table) */ -+ uint64_t dofs_offset; /* offset of section data within file */ -+ uint64_t dofs_size; /* size of section data in bytes */ -+} dof_sec_t; -+ -+ -+typedef struct dof_ecbdesc { -+ dof_secidx_t dofe_probes; /* link to DOF_SECT_PROBEDESC */ -+ dof_secidx_t dofe_pred; /* link to DOF_SECT_DIFOHDR */ -+ dof_secidx_t dofe_actions; /* link to DOF_SECT_ACTDESC */ -+ uint32_t dofe_pad; /* reserved for future use */ -+ uint64_t dofe_uarg; /* user-supplied library argument */ -+} dof_ecbdesc_t; -+ -+typedef struct dof_probedesc { -+ dof_secidx_t dofp_strtab; /* link to DOF_SECT_STRTAB section */ -+ dof_stridx_t dofp_provider; /* provider string */ -+ dof_stridx_t dofp_mod; /* module string */ -+ dof_stridx_t dofp_func; /* function string */ -+ dof_stridx_t dofp_name; /* name string */ -+ uint32_t dofp_id; /* probe identifier (or zero) */ -+} dof_probedesc_t; -+ -+typedef struct dof_actdesc { -+ dof_secidx_t dofa_difo; /* link to DOF_SECT_DIFOHDR */ -+ dof_secidx_t dofa_strtab; /* link to DOF_SECT_STRTAB section */ -+ uint32_t dofa_kind; /* action kind (DTRACEACT_* constant) */ -+ uint32_t dofa_ntuple; /* number of subsequent tuple actions */ -+ uint64_t dofa_arg; /* kind-specific argument */ -+ uint64_t dofa_uarg; /* user-supplied argument */ -+} dof_actdesc_t; -+ -+typedef struct dof_difohdr { -+ struct dtrace_diftype dofd_rtype; /* return type for this fragment */ -+ dof_secidx_t dofd_links[1]; /* variable length array of indices */ -+} dof_difohdr_t; -+ -+typedef struct dof_relohdr { -+ dof_secidx_t dofr_strtab; /* link to DOF_SECT_STRTAB for names */ -+ dof_secidx_t dofr_relsec; /* link to DOF_SECT_RELTAB for relos */ -+ dof_secidx_t dofr_tgtsec; /* link to section we are relocating */ -+} dof_relohdr_t; -+ -+typedef struct dof_relodesc { -+ dof_stridx_t dofr_name; /* string name of relocation symbol */ -+ uint32_t dofr_type; /* relo type (DOF_RELO_* constant) */ -+ uint64_t dofr_offset; /* byte offset for relocation */ -+ uint64_t dofr_data; /* additional type-specific data */ -+} dof_relodesc_t; -+ -+typedef struct dof_optdesc { -+ uint32_t dofo_option; /* option identifier */ -+ dof_secidx_t dofo_strtab; /* string table, if string option */ -+ uint64_t dofo_value; /* option value or string index */ -+} dof_optdesc_t; -+ -+typedef struct dof_provider { -+ dof_secidx_t dofpv_strtab; /* link to DOF_SECT_STRTAB section */ -+ dof_secidx_t dofpv_probes; /* link to DOF_SECT_PROBES section */ -+ dof_secidx_t dofpv_prargs; /* link to DOF_SECT_PRARGS section */ -+ dof_secidx_t dofpv_proffs; /* link to DOF_SECT_PROFFS section */ -+ dof_stridx_t dofpv_name; /* provider name string */ -+ dof_attr_t dofpv_provattr; /* provider attributes */ -+ dof_attr_t dofpv_modattr; /* module attributes */ -+ dof_attr_t dofpv_funcattr; /* function attributes */ -+ dof_attr_t dofpv_nameattr; /* name attributes */ -+ dof_attr_t dofpv_argsattr; /* args attributes */ -+ dof_secidx_t dofpv_prenoffs; /* link to DOF_SECT_PRENOFFS section */ -+} dof_provider_t; -+ -+typedef struct dof_probe { -+ uint64_t dofpr_addr; /* probe base address or offset */ -+ dof_stridx_t dofpr_func; /* probe function string */ -+ dof_stridx_t dofpr_name; /* probe name string */ -+ dof_stridx_t dofpr_nargv; /* native argument type strings */ -+ dof_stridx_t dofpr_xargv; /* translated argument type strings */ -+ uint32_t dofpr_argidx; /* index of first argument mapping */ -+ uint32_t dofpr_offidx; /* index of first offset entry */ -+ uint8_t dofpr_nargc; /* native argument count */ -+ uint8_t dofpr_xargc; /* translated argument count */ -+ uint16_t dofpr_noffs; /* number of offset entries for probe */ -+ uint32_t dofpr_enoffidx; /* index of first is-enabled offset */ -+ uint16_t dofpr_nenoffs; /* number of is-enabled offsets */ -+ uint16_t dofpr_pad1; /* reserved for future use */ -+ uint32_t dofpr_pad2; /* reserved for future use */ -+} dof_probe_t; -+ -+typedef struct dof_xlator { -+ dof_secidx_t dofxl_members; /* link to DOF_SECT_XLMEMBERS section */ -+ dof_secidx_t dofxl_strtab; /* link to DOF_SECT_STRTAB section */ -+ dof_stridx_t dofxl_argv; /* input parameter type strings */ -+ uint32_t dofxl_argc; /* input parameter list length */ -+ dof_stridx_t dofxl_type; /* output type string name */ -+ dof_attr_t dofxl_attr; /* output stability attributes */ -+} dof_xlator_t; -+ -+typedef struct dof_xlmember { -+ dof_secidx_t dofxm_difo; /* member link to DOF_SECT_DIFOHDR */ -+ dof_stridx_t dofxm_name; /* member name */ -+ struct dtrace_diftype dofxm_type; /* member type */ -+} dof_xlmember_t; -+ -+typedef struct dof_xlref { -+ dof_secidx_t dofxr_xlator; /* link to DOF_SECT_XLATORS section */ -+ uint32_t dofxr_member; /* index of referenced dof_xlmember */ -+ uint32_t dofxr_argn; /* index of argument for DIF_OP_XLARG */ -+} dof_xlref_t; -+ -+#endif /* _LINUX_DTRACE_DOF_H */ -diff --git a/include/uapi/linux/dtrace/dof_defines.h b/include/uapi/linux/dtrace/dof_defines.h -new file mode 100644 -index 000000000000..5357d5e099cc ---- /dev/null -+++ b/include/uapi/linux/dtrace/dof_defines.h -@@ -0,0 +1,192 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_DOF_DEFINES_H -+#define _LINUX_DTRACE_DOF_DEFINES_H -+ -+#include <linux/dtrace/universal.h> -+ -+/* -+ * DTrace programs can be persistently encoded in the DOF format so that they -+ * may be embedded in other programs (for example, in an ELF file) or in the -+ * dtrace driver configuration file for use in anonymous tracing. The DOF -+ * format is versioned and extensible so that it can be revised and so that -+ * internal data structures can be modified or extended compatibly. All DOF -+ * structures use fixed-size types, so the 32-bit and 64-bit representations -+ * are identical and consumers can use either data model transparently. -+ * -+ * The file layout is structured as follows: -+ * -+ * +---------------+-------------------+----- ... ----+---- ... ------+ -+ * | dof_hdr_t | dof_sec_t[ ... ] | loadable | non-loadable | -+ * | (file header) | (section headers) | section data | section data | -+ * +---------------+-------------------+----- ... ----+---- ... ------+ -+ * |<------------ dof_hdr.dofh_loadsz --------------->| | -+ * |<------------ dof_hdr.dofh_filesz ------------------------------->| -+ * -+ * The file header stores meta-data including a magic number, data model for -+ * the instrumentation, data encoding, and properties of the DIF code within. -+ * The header describes its own size and the size of the section headers. By -+ * convention, an array of section headers follows the file header, and then -+ * the data for all loadable sections and unloadable sections. This permits -+ * consumer code to easily download the headers and all loadable data into the -+ * DTrace driver in one contiguous chunk, omitting other extraneous sections. -+ * -+ * The section headers describe the size, offset, alignment, and section type -+ * for each section. Sections are described using a set of #defines that tell -+ * the consumer what kind of data is expected. Sections can contain links to -+ * other sections by storing a dof_secidx_t, an index into the section header -+ * array, inside of the section data structures. The section header includes -+ * an entry size so that sections with data arrays can grow their structures. -+ * -+ * The DOF data itself can contain many snippets of DIF (i.e. >1 DIFOs), which -+ * are represented themselves as a collection of related DOF sections. This -+ * permits us to change the set of sections associated with a DIFO over time, -+ * and also permits us to encode DIFOs that contain different sets of sections. -+ * When a DOF section wants to refer to a DIFO, it stores the dof_secidx_t of a -+ * section of type DOF_SECT_DIFOHDR. This section's data is then an array of -+ * dof_secidx_t's which in turn denote the sections associated with this DIFO. -+ * -+ * This loose coupling of the file structure (header and sections) to the -+ * structure of the DTrace program itself (ECB descriptions, action -+ * descriptions, and DIFOs) permits activities such as relocation processing -+ * to occur in a single pass without having to understand D program structure. -+ * -+ * Finally, strings are always stored in ELF-style string tables along with a -+ * string table section index and string table offset. Therefore strings in -+ * DOF are always arbitrary-length and not bound to the current implementation. -+ */ -+ -+#define DOF_ID_SIZE 16 /* total size of dofh_ident[] in bytes */ -+ -+#define DOF_ID_MAG0 0 -+#define DOF_ID_MAG1 1 -+#define DOF_ID_MAG2 2 -+#define DOF_ID_MAG3 3 -+#define DOF_ID_MODEL 4 -+#define DOF_ID_ENCODING 5 -+#define DOF_ID_VERSION 6 -+#define DOF_ID_DIFVERS 7 -+#define DOF_ID_DIFIREG 8 /* DIF integer registers used by compiler */ -+#define DOF_ID_DIFTREG 9 /* DIF tuple registers used by compiler */ -+#define DOF_ID_PAD 10 /* start of padding bytes (all zeroes) */ -+ -+#define DOF_MAG_MAG0 0x7F /* DOF_ID_MAG[0-3] */ -+#define DOF_MAG_MAG1 'D' -+#define DOF_MAG_MAG2 'O' -+#define DOF_MAG_MAG3 'F' -+ -+#define DOF_MAG_STRING "\177DOF" -+#define DOF_MAG_STRLEN 4 -+ -+#define DOF_MODEL_NONE 0 /* DOF_ID_MODEL */ -+#define DOF_MODEL_ILP32 1 -+#define DOF_MODEL_LP64 2 -+ -+#ifdef _LP64 -+#define DOF_MODEL_NATIVE DOF_MODEL_LP64 -+#else -+#define DOF_MODEL_NATIVE DOF_MODEL_ILP32 -+#endif -+ -+#define DOF_ENCODE_NONE 0 /* DOF_ID_ENCODING */ -+#define DOF_ENCODE_LSB 1 -+#define DOF_ENCODE_MSB 2 -+ -+#ifndef _LITTLE_ENDIAN -+#define DOF_ENCODE_NATIVE DOF_ENCODE_MSB -+#else -+#define DOF_ENCODE_NATIVE DOF_ENCODE_LSB -+#endif -+ -+#define DOF_VERSION_1 1 -+#define DOF_VERSION_2 2 -+#define DOF_VERSION DOF_VERSION_2 -+ -+#define DOF_FL_VALID 0 /* mask of all valid dofh_flags bits */ -+ -+typedef uint32_t dof_secidx_t; /* section header table index type */ -+typedef uint32_t dof_stridx_t; /* string table index type */ -+ -+#define DOF_SECIDX_NONE -1U /* null value for section indices */ -+#define DOF_STRIDX_NONE -1U /* null value for string indices */ -+ -+#define DOF_SECT_NONE 0 /* null section */ -+#define DOF_SECT_COMMENTS 1 /* compiler comments */ -+#define DOF_SECT_SOURCE 2 /* D program source code */ -+#define DOF_SECT_ECBDESC 3 /* dof_ecbdesc_t */ -+#define DOF_SECT_PROBEDESC 4 /* dof_probedesc_t */ -+#define DOF_SECT_ACTDESC 5 /* dof_actdesc_t array */ -+#define DOF_SECT_DIFOHDR 6 /* dof_difohdr_t (variable length) */ -+#define DOF_SECT_DIF 7 /* uint32_t array of byte code */ -+#define DOF_SECT_STRTAB 8 /* string table */ -+#define DOF_SECT_VARTAB 9 /* dtrace_difv_t array */ -+#define DOF_SECT_RELTAB 10 /* dof_relodesc_t array */ -+#define DOF_SECT_TYPTAB 11 /* dtrace_diftype_t array */ -+#define DOF_SECT_URELHDR 12 /* dof_relohdr_t (user relocations) */ -+#define DOF_SECT_KRELHDR 13 /* dof_relohdr_t (kernel relocations) */ -+#define DOF_SECT_OPTDESC 14 /* dof_optdesc_t array */ -+#define DOF_SECT_PROVIDER 15 /* dof_provider_t */ -+#define DOF_SECT_PROBES 16 /* dof_probe_t array */ -+#define DOF_SECT_PRARGS 17 /* uint8_t array (probe arg mappings) */ -+#define DOF_SECT_PROFFS 18 /* uint32_t array (probe arg offsets) */ -+#define DOF_SECT_INTTAB 19 /* uint64_t array */ -+#define DOF_SECT_UTSNAME 20 /* struct utsname */ -+#define DOF_SECT_XLTAB 21 /* dof_xlref_t array */ -+#define DOF_SECT_XLMEMBERS 22 /* dof_xlmember_t array */ -+#define DOF_SECT_XLIMPORT 23 /* dof_xlator_t */ -+#define DOF_SECT_XLEXPORT 24 /* dof_xlator_t */ -+#define DOF_SECT_PREXPORT 25 /* dof_secidx_t array (exported objs) */ -+#define DOF_SECT_PRENOFFS 26 /* uint32_t array (enabled offsets) */ -+ -+#define DOF_SECF_LOAD 1 /* section should be loaded */ -+ -+#define DOF_SEC_ISLOADABLE(x) \ -+ (((x) == DOF_SECT_ECBDESC) || ((x) == DOF_SECT_PROBEDESC) || \ -+ ((x) == DOF_SECT_ACTDESC) || ((x) == DOF_SECT_DIFOHDR) || \ -+ ((x) == DOF_SECT_DIF) || ((x) == DOF_SECT_STRTAB) || \ -+ ((x) == DOF_SECT_VARTAB) || ((x) == DOF_SECT_RELTAB) || \ -+ ((x) == DOF_SECT_TYPTAB) || ((x) == DOF_SECT_URELHDR) || \ -+ ((x) == DOF_SECT_KRELHDR) || ((x) == DOF_SECT_OPTDESC) || \ -+ ((x) == DOF_SECT_PROVIDER) || ((x) == DOF_SECT_PROBES) || \ -+ ((x) == DOF_SECT_PRARGS) || ((x) == DOF_SECT_PROFFS) || \ -+ ((x) == DOF_SECT_INTTAB) || ((x) == DOF_SECT_XLTAB) || \ -+ ((x) == DOF_SECT_XLMEMBERS) || ((x) == DOF_SECT_XLIMPORT) || \ -+ ((x) == DOF_SECT_XLIMPORT) || ((x) == DOF_SECT_XLEXPORT) || \ -+ ((x) == DOF_SECT_PREXPORT) || ((x) == DOF_SECT_PRENOFFS)) -+ -+#define DOF_RELO_NONE 0 /* empty relocation entry */ -+#define DOF_RELO_SETX 1 /* relocate setx value */ -+ -+typedef uint32_t dof_attr_t; /* encoded stability attributes */ -+ -+#define DOF_ATTR(n, d, c) (((n) << 24) | ((d) << 16) | ((c) << 8)) -+#define DOF_ATTR_NAME(a) (((a) >> 24) & 0xff) -+#define DOF_ATTR_DATA(a) (((a) >> 16) & 0xff) -+#define DOF_ATTR_CLASS(a) (((a) >> 8) & 0xff) -+ -+struct dof_hdr; -+struct dof_sec; -+struct dof_ecbdesc; -+struct dof_probedesc; -+struct dof_actdesc; -+struct dof_difohdr; -+struct dof_relohdr; -+struct dof_relodesc; -+struct dof_optdesc; -+struct dof_provider; -+struct dof_xlator; -+struct dof_xlmember; -+struct dof_xlref; -+ -+#endif /* _LINUX_DTRACE_DOF_DEFINES_H */ -diff --git a/include/uapi/linux/dtrace/dtrace.h b/include/uapi/linux/dtrace/dtrace.h -new file mode 100644 -index 000000000000..0ee9d35876ef ---- /dev/null -+++ b/include/uapi/linux/dtrace/dtrace.h -@@ -0,0 +1,33 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_H_ -+#define _LINUX_DTRACE_H_ -+ -+#include <linux/dtrace/universal.h> -+#include <linux/dtrace/dif.h> -+#include <linux/dtrace/actions.h> -+#include <linux/dtrace/dof.h> -+#include <linux/dtrace/difo.h> -+#include <linux/dtrace/enabling.h> -+#include <linux/dtrace/metadesc.h> -+#include <linux/dtrace/options.h> -+#include <linux/dtrace/buffer.h> -+#include <linux/dtrace/status.h> -+#include <linux/dtrace/conf.h> -+#include <linux/dtrace/faults.h> -+#include <linux/dtrace/arg.h> -+#include <linux/dtrace/stability.h> -+#include <linux/dtrace/helpers.h> -+ -+#endif /* _LINUX_DTRACE_H_ */ -diff --git a/include/uapi/linux/dtrace/enabling.h b/include/uapi/linux/dtrace/enabling.h -new file mode 100644 -index 000000000000..8aac2ab9ea8d ---- /dev/null -+++ b/include/uapi/linux/dtrace/enabling.h -@@ -0,0 +1,76 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_ENABLING_H -+#define _LINUX_DTRACE_ENABLING_H -+ -+#include <linux/dtrace/universal.h> -+#include <linux/dtrace/difo_defines.h> -+#include <linux/dtrace/enabling_defines.h> -+ -+/* -+ * When DTrace is tracking the description of a DTrace enabling entity (probe, -+ * predicate, action, ECB, record, etc.), it does so in a description -+ * structure. These structures all end in "desc", and are used at both -+ * user-level and in the kernel -- but (with the exception of -+ * dtrace_probedesc_t) they are never passed between them. Typically, -+ * user-level will use the description structures when assembling an enabling. -+ * It will then distill those description structures into a DOF object (see -+ * above), and send it into the kernel. The kernel will again use the -+ * description structures to create a description of the enabling as it reads -+ * the DOF. When the description is complete, the enabling will be actually -+ * created -- turning it into the structures that represent the enabling -+ * instead of merely describing it. Not surprisingly, the description -+ * structures bear a strong resemblance to the DOF structures that act as their -+ * conduit. -+ */ -+ -+struct dtrace_predicate; -+ -+typedef struct dtrace_probedesc { -+ dtrace_id_t dtpd_id; /* probe identifier */ -+ char dtpd_provider[DTRACE_PROVNAMELEN]; /* probe provider name */ -+ char dtpd_mod[DTRACE_MODNAMELEN]; /* probe module name */ -+ char dtpd_func[DTRACE_FUNCNAMELEN]; /* probe function name */ -+ char dtpd_name[DTRACE_NAMELEN]; /* probe name */ -+} dtrace_probedesc_t; -+ -+typedef struct dtrace_repldesc { -+ struct dtrace_probedesc dtrpd_match; /* probe descr. to match */ -+ struct dtrace_probedesc dtrpd_create; /* probe descr. to create */ -+} dtrace_repldesc_t; -+ -+typedef struct dtrace_preddesc { -+ struct dtrace_difo *dtpdd_difo; /* pointer to DIF object */ -+ struct dtrace_predicate *dtpdd_predicate; /* pointer to predicate */ -+} dtrace_preddesc_t; -+ -+typedef struct dtrace_actdesc { -+ struct dtrace_difo *dtad_difo; /* pointer to DIF object */ -+ struct dtrace_actdesc *dtad_next; /* next action */ -+ dtrace_actkind_t dtad_kind; /* kind of action */ -+ uint32_t dtad_ntuple; /* number in tuple */ -+ uint64_t dtad_arg; /* action argument */ -+ uint64_t dtad_uarg; /* user argument */ -+ int dtad_refcnt; /* reference count */ -+} dtrace_actdesc_t; -+ -+typedef struct dtrace_ecbdesc { -+ struct dtrace_actdesc *dted_action; /* action description(s) */ -+ struct dtrace_preddesc dted_pred; /* predicate description */ -+ struct dtrace_probedesc dted_probe; /* probe description */ -+ uint64_t dted_uarg; /* library argument */ -+ int dted_refcnt; /* reference count */ -+} dtrace_ecbdesc_t; -+ -+#endif /* _LINUX_DTRACE_ENABLING_H */ -diff --git a/include/uapi/linux/dtrace/enabling_defines.h b/include/uapi/linux/dtrace/enabling_defines.h -new file mode 100644 -index 000000000000..221c3efca015 ---- /dev/null -+++ b/include/uapi/linux/dtrace/enabling_defines.h -@@ -0,0 +1,25 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_ENABLING_DEFINES_H -+#define _LINUX_DTRACE_ENABLING_DEFINES_H -+ -+#include <linux/dtrace/universal.h> -+ -+struct dtrace_probedesc; -+struct dtrace_repldesc; -+struct dtrace_preddesc; -+struct dtrace_actdesc; -+struct dtrace_ecbdesc; -+ -+#endif /* _LINUX_DTRACE_ENABLING_DEFINES_H */ -diff --git a/include/uapi/linux/dtrace/fasttrap.h b/include/uapi/linux/dtrace/fasttrap.h -new file mode 100644 -index 000000000000..4dbf1a2a35cd ---- /dev/null -+++ b/include/uapi/linux/dtrace/fasttrap.h -@@ -0,0 +1,56 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_FASTTRAP_H -+#define _LINUX_DTRACE_FASTTRAP_H -+ -+#include <linux/dtrace/universal.h> -+#include <linux/dtrace/fasttrap_defines.h> -+ -+typedef enum fasttrap_probe_type { -+ DTFTP_NONE = 0, -+ DTFTP_ENTRY, -+ DTFTP_RETURN, -+ DTFTP_OFFSETS, -+ DTFTP_POST_OFFSETS, -+ DTFTP_IS_ENABLED -+} fasttrap_probe_type_t; -+ -+typedef struct fasttrap_probe_spec { -+ pid_t ftps_pid; /* task PID */ -+ enum fasttrap_probe_type ftps_type; /* probe type */ -+ char ftps_func[DTRACE_FUNCNAMELEN]; /* probe function */ -+ char ftps_mod[DTRACE_MODNAMELEN]; /* probe module */ -+ uint64_t ftps_pc; /* probe address */ -+ uint64_t ftps_size; /* function size (in bytes) */ -+ uint8_t ftps_glen; /* glob pattern length */ -+ char ftps_gstr[1]; /* glob pattern string */ -+} fasttrap_probe_spec_t; -+ -+typedef uint8_t fasttrap_instr_t; -+ -+typedef struct fasttrap_instr_query { -+ uint64_t ftiq_pc; -+ pid_t ftiq_pid; -+ fasttrap_instr_t ftiq_instr; -+} fasttrap_instr_query_t; -+ -+/* -+ * Include after the definitions, to get ioctl()s when fasttrap.h is included. -+ * fasttrap_ioctl.h also #includes this header, to get structures when it is -+ * included itself, as is done by headers_check. -+ */ -+ -+#include <linux/dtrace/fasttrap_ioctl.h> -+ -+#endif /* _LINUX_DTRACE_FASTTRAP_H */ -diff --git a/include/uapi/linux/dtrace/fasttrap_defines.h b/include/uapi/linux/dtrace/fasttrap_defines.h -new file mode 100644 -index 000000000000..4bb07564e1c4 ---- /dev/null -+++ b/include/uapi/linux/dtrace/fasttrap_defines.h -@@ -0,0 +1,25 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_FASTTRAP_DEFINES_H -+#define _LINUX_DTRACE_FASTTRAP_DEFINES_H -+ -+#include <linux/dtrace/universal.h> -+ -+#ifndef __cplusplus -+enum fasttrap_probe_type; -+#endif -+struct fasttrap_probe_spec; -+struct fasttrap_instr_query; -+ -+#endif /* _LINUX_DTRACE_FASTTRAP_DEFINES_H */ -diff --git a/include/uapi/linux/dtrace/fasttrap_ioctl.h b/include/uapi/linux/dtrace/fasttrap_ioctl.h -new file mode 100644 -index 000000000000..b5a8b0731fb6 ---- /dev/null -+++ b/include/uapi/linux/dtrace/fasttrap_ioctl.h -@@ -0,0 +1,19 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+#ifndef _LINUX_DTRACE_FASTRRAP_IOCTL_H_ -+#define _LINUX_DTRACE_FASTTRAP_IOCTL_H_ -+ -+#include <linux/ioctl.h> -+#include <linux/dtrace/fasttrap.h> -+ -+#define FASTTRAPIOC 0xf4 -+#define FASTTRAPIOC_MAKEPROBE _IOW(FASTTRAPIOC, 1, struct fasttrap_probe_spec) -+#define FASTTRAPIOC_GETINSTR _IOR(FASTTRAPIOC, 2, struct fasttrap_instr_query) -+ -+#endif /* _LINUX_DTRACE_FASTTRAP_IOCTL_H_ */ -diff --git a/include/uapi/linux/dtrace/faults.h b/include/uapi/linux/dtrace/faults.h -new file mode 100644 -index 000000000000..afa2ae548fa6 ---- /dev/null -+++ b/include/uapi/linux/dtrace/faults.h -@@ -0,0 +1,20 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_FAULTS_H -+#define _LINUX_DTRACE_FAULTS_H -+ -+#include <linux/dtrace/universal.h> -+#include <linux/dtrace/faults_defines.h> -+ -+#endif /* _LINUX_DTRACE_FAULTS_H */ -diff --git a/include/uapi/linux/dtrace/faults_defines.h b/include/uapi/linux/dtrace/faults_defines.h -new file mode 100644 -index 000000000000..d225f2e847e4 ---- /dev/null -+++ b/include/uapi/linux/dtrace/faults_defines.h -@@ -0,0 +1,39 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_FAULTS_DEFINES_H -+#define _LINUX_DTRACE_FAULTS_DEFINES_H -+ -+#include <linux/dtrace/universal.h> -+ -+/* -+ * The constants below DTRACEFLT_LIBRARY indicate probe processing faults; -+ * constants at or above DTRACEFLT_LIBRARY indicate faults in probe -+ * postprocessing at user-level. Probe processing faults induce an ERROR -+ * probe and are replicated in unistd.d to allow users' ERROR probes to decode -+ * the error condition using thse symbolic labels. -+ */ -+#define DTRACEFLT_UNKNOWN 0 /* Unknown fault */ -+#define DTRACEFLT_BADADDR 1 /* Bad address */ -+#define DTRACEFLT_BADALIGN 2 /* Bad alignment */ -+#define DTRACEFLT_ILLOP 3 /* Illegal operation */ -+#define DTRACEFLT_DIVZERO 4 /* Divide-by-zero */ -+#define DTRACEFLT_NOSCRATCH 5 /* Out of scratch space */ -+#define DTRACEFLT_KPRIV 6 /* Illegal kernel access */ -+#define DTRACEFLT_UPRIV 7 /* Illegal user access */ -+#define DTRACEFLT_TUPOFLOW 8 /* Tuple stack overflow */ -+#define DTRACEFLT_BADSTACK 9 /* Bad stack */ -+ -+#define DTRACEFLT_LIBRARY 1000 /* Library-level fault */ -+ -+#endif /* _LINUX_DTRACE_FAULTS_DEFINES_H */ -diff --git a/include/uapi/linux/dtrace/helpers.h b/include/uapi/linux/dtrace/helpers.h -new file mode 100644 -index 000000000000..553f23994881 ---- /dev/null -+++ b/include/uapi/linux/dtrace/helpers.h -@@ -0,0 +1,101 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_HELPERS_H -+#define _LINUX_DTRACE_HELPERS_H -+ -+#include <linux/dtrace/universal.h> -+#include <linux/dtrace/helpers_defines.h> -+ -+/* -+ * DTrace Helpers -+ * -+ * In general, DTrace establishes probes in processes and takes actions on -+ * processes without knowing their specific user-level structures. Instead of -+ * existing in the framework, process-specific knowledge is contained by the -+ * enabling D program -- which can apply process-specific knowledge by making -+ * appropriate use of DTrace primitives like copyin() and copyinstr() to -+ * operate on user-level data. However, there may exist some specific probes -+ * of particular semantic relevance that the application developer may wish to -+ * explicitly export. For example, an application may wish to export a probe -+ * at the point that it begins and ends certain well-defined transactions. In -+ * addition to providing probes, programs may wish to offer assistance for -+ * certain actions. For example, in highly dynamic environments (e.g., Java), -+ * it may be difficult to obtain a stack trace in terms of meaningful symbol -+ * names (the translation from instruction addresses to corresponding symbol -+ * names may only be possible in situ); these environments may wish to define -+ * a series of actions to be applied in situ to obtain a meaningful stack -+ * trace. -+ * -+ * These two mechanisms -- user-level statically defined tracing and assisting -+ * DTrace actions -- are provided via DTrace _helpers_. Helpers are specified -+ * via DOF, but unlike enabling DOF, helper DOF may contain definitions of -+ * providers, probes and their arguments. If a helper wishes to provide -+ * action assistance, probe descriptions and corresponding DIF actions may be -+ * specified in the helper DOF. For such helper actions, however, the probe -+ * description describes the specific helper: all DTrace helpers have the -+ * provider name "dtrace" and the module name "helper", and the name of the -+ * helper is contained in the function name (for example, the ustack() helper -+ * is named "ustack"). Any helper-specific name may be contained in the name -+ * (for example, if a helper were to have a constructor, it might be named -+ * "dtrace:helper:<helper>:init"). Helper actions are only called when the -+ * action that they are helping is taken. Helper actions may only return DIF -+ * expressions, and may only call the following subroutines: -+ * -+ * alloca() <= Allocates memory out of the consumer's scratch space -+ * bcopy() <= Copies memory to scratch space -+ * copyin() <= Copies memory from user-level into consumer's scratch -+ * copyinto() <= Copies memory into a specific location in scratch -+ * copyinstr() <= Copies a string into a specific location in scratch -+ * -+ * Helper actions may only access the following built-in variables: -+ * -+ * curthread <= Current kthread_t pointer -+ * tid <= Current thread identifier -+ * pid <= Current process identifier -+ * ppid <= Parent process identifier -+ * uid <= Current user ID -+ * gid <= Current group ID -+ * execname <= Current executable name -+ * zonename <= Current zone name -+ * -+ * Helper actions may not manipulate or allocate dynamic variables, but they -+ * may have clause-local and statically-allocated global variables. The -+ * helper action variable state is specific to the helper action -- variables -+ * used by the helper action may not be accessed outside of the helper -+ * action, and the helper action may not access variables that like outside -+ * of it. Helper actions may not load from kernel memory at-large; they are -+ * restricting to loading current user state (via copyin() and variants) and -+ * scratch space. As with probe enablings, helper actions are executed in -+ * program order. The result of the helper action is the result of the last -+ * executing helper expression. -+ * -+ * Helpers -- composed of either providers/probes or probes/actions (or both) -+ * -- are added by opening the "helper" minor node, and issuing an ioctl(2) -+ * (DTRACEHIOC_ADDDOF) that specifies the dof_helper_t structure. This -+ * encapsulates the name and base address of the user-level library or -+ * executable publishing the helpers and probes as well as the DOF that -+ * contains the definitions of those helpers and probes. -+ * -+ * The DTRACEHIOC_ADD and DTRACEHIOC_REMOVE are left in place for legacy -+ * helpers and should no longer be used. No other ioctls are valid on the -+ * helper minor node. -+ */ -+ -+typedef struct dof_helper { -+ char dofhp_mod[DTRACE_MODNAMELEN]; /* executable or library name */ -+ uint64_t dofhp_addr; /* base address of object */ -+ uint64_t dofhp_dof; /* address of helper DOF */ -+} dof_helper_t; -+ -+#endif /* _LINUX_DTRACE_HELPERS_H */ -diff --git a/include/uapi/linux/dtrace/helpers_defines.h b/include/uapi/linux/dtrace/helpers_defines.h -new file mode 100644 -index 000000000000..8bf52f058001 ---- /dev/null -+++ b/include/uapi/linux/dtrace/helpers_defines.h -@@ -0,0 +1,21 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_HELPERS_DEFINES_H -+#define _LINUX_DTRACE_HELPERS_DEFINES_H -+ -+#include <linux/dtrace/universal.h> -+ -+struct dof_helper; -+ -+#endif /* _LINUX_DTRACE_HELPERS_DEFINES_H */ -diff --git a/include/uapi/linux/dtrace/ioctl.h b/include/uapi/linux/dtrace/ioctl.h -new file mode 100644 -index 000000000000..ef2476af2629 ---- /dev/null -+++ b/include/uapi/linux/dtrace/ioctl.h -@@ -0,0 +1,47 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+#ifndef _LINUX_DTRACE_IOCTL_H_ -+#define _LINUX_DTRACE_IOCTL_H_ -+ -+#include <linux/ioctl.h> -+#include <linux/dtrace/arg.h> -+#include <linux/dtrace/buffer.h> -+#include <linux/dtrace/conf.h> -+#include <linux/dtrace/dof.h> -+#include <linux/dtrace/enabling.h> -+#include <linux/dtrace/helpers.h> -+#include <linux/dtrace/metadesc.h> -+#include <linux/dtrace/stability.h> -+#include <linux/dtrace/status.h> -+#include <linux/dtrace/cpu_defines.h> -+ -+#define DTRACEIOC 0xd4 -+#define DTRACEIOC_PROVIDER _IOR(DTRACEIOC, 1, struct dtrace_providerdesc) -+#define DTRACEIOC_PROBES _IOR(DTRACEIOC, 2, struct dtrace_probedesc) -+#define DTRACEIOC_BUFSNAP _IOR(DTRACEIOC, 4, struct dtrace_bufdesc) -+#define DTRACEIOC_PROBEMATCH _IOR(DTRACEIOC, 5, struct dtrace_probedesc) -+#define DTRACEIOC_ENABLE _IOW(DTRACEIOC, 6, void *) -+#define DTRACEIOC_AGGSNAP _IOR(DTRACEIOC, 7, struct dtrace_bufdesc) -+#define DTRACEIOC_EPROBE _IOW(DTRACEIOC, 8, struct dtrace_eprobedesc) -+#define DTRACEIOC_PROBEARG _IOR(DTRACEIOC, 9, struct dtrace_argdesc) -+#define DTRACEIOC_CONF _IOR(DTRACEIOC, 10, struct dtrace_conf) -+#define DTRACEIOC_STATUS _IOR(DTRACEIOC, 11, struct dtrace_status) -+#define DTRACEIOC_GO _IOW(DTRACEIOC, 12, processorid_t) -+#define DTRACEIOC_STOP _IOW(DTRACEIOC, 13, processorid_t) -+#define DTRACEIOC_AGGDESC _IOR(DTRACEIOC, 15, struct dtrace_aggdesc) -+#define DTRACEIOC_FORMAT _IOR(DTRACEIOC, 16, struct dtrace_fmtdesc) -+#define DTRACEIOC_DOFGET _IOR(DTRACEIOC, 17, struct dof_hdr) -+#define DTRACEIOC_REPLICATE _IOR(DTRACEIOC, 18, void *) -+ -+#define DTRACEHIOC 0xd8 -+#define DTRACEHIOC_ADD _IOW(DTRACEHIOC, 1, struct dof_hdr) -+#define DTRACEHIOC_REMOVE _IOW(DTRACEHIOC, 2, int) -+#define DTRACEHIOC_ADDDOF _IOW(DTRACEHIOC, 3, struct dof_helper) -+ -+#endif /* _LINUX_DTRACE_IOCTL_H */ -diff --git a/include/uapi/linux/dtrace/metadesc.h b/include/uapi/linux/dtrace/metadesc.h -new file mode 100644 -index 000000000000..a6b3d82b2c97 ---- /dev/null -+++ b/include/uapi/linux/dtrace/metadesc.h -@@ -0,0 +1,81 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_METADESC_H -+#define _LINUX_DTRACE_METADESC_H -+ -+#include <linux/dtrace/universal.h> -+#include <linux/dtrace/actions_defines.h> -+#include <linux/dtrace/metadesc_defines.h> -+ -+/* -+ * DTrace separates the trace data stream from the metadata stream. The only -+ * metadata tokens placed in the data stream are enabled probe identifiers -+ * (EPIDs) or (in the case of aggregations) aggregation identifiers. In order -+ * to determine the structure of the data, DTrace consumers pass the token to -+ * the kernel, and receive in return a corresponding description of the enabled -+ * probe (via the dtrace_eprobedesc structure) or the aggregation (via the -+ * dtrace_aggdesc structure). Both of these structures are expressed in terms -+ * of record descriptions (via the dtrace_recdesc structure) that describe the -+ * exact structure of the data. Some record descriptions may also contain a -+ * format identifier; this additional bit of metadata can be retrieved from the -+ * kernel, for which a format description is returned via the dtrace_fmtdesc -+ * structure. Note that all four of these structures must be bitness-neutral -+ * to allow for a 32-bit DTrace consumer on a 64-bit kernel. -+ */ -+typedef struct dtrace_recdesc { -+ dtrace_actkind_t dtrd_action; /* kind of action */ -+ uint32_t dtrd_size; /* size of record */ -+ uint32_t dtrd_offset; /* offset in ECB's data */ -+ uint16_t dtrd_alignment; /* required alignment */ -+ uint16_t dtrd_format; /* format, if any */ -+ uint64_t dtrd_arg; /* action argument */ -+ uint64_t dtrd_uarg; /* user argument */ -+} dtrace_recdesc_t; -+ -+typedef struct dtrace_eprobedesc { -+ dtrace_epid_t dtepd_epid; /* enabled probe ID */ -+ dtrace_id_t dtepd_probeid; /* probe ID */ -+ uint64_t dtepd_uarg; /* library argument */ -+ uint32_t dtepd_size; /* total size */ -+ int dtepd_nrecs; /* number of records */ -+ struct dtrace_recdesc dtepd_rec[1]; /* records themselves */ -+} dtrace_eprobedesc_t; -+ -+typedef struct dtrace_aggdesc { -+ DTRACE_PTR(char, dtagd_name); /* not filled in by kernel */ -+ dtrace_aggvarid_t dtagd_varid; /* not filled in by kernel */ -+ int dtagd_flags; /* not filled in by kernel */ -+ dtrace_aggid_t dtagd_id; /* aggregation ID */ -+ dtrace_epid_t dtagd_epid; /* enabled probe ID */ -+ uint32_t dtagd_size; /* size in bytes */ -+ int dtagd_nrecs; /* number of records */ -+ uint32_t dtagd_pad; /* explicit padding */ -+ struct dtrace_recdesc dtagd_rec[1]; /* record descriptions */ -+} dtrace_aggdesc_t; -+ -+typedef struct dtrace_fmtdesc { -+ DTRACE_PTR(char, dtfd_string); /* format string */ -+ int dtfd_length; /* length of format string */ -+ uint16_t dtfd_format; /* format identifier */ -+} dtrace_fmtdesc_t; -+ -+#define DTRACE_SIZEOF_EPROBEDESC(desc) \ -+ (sizeof(struct dtrace_eprobedesc) + ((desc)->dtepd_nrecs ? \ -+ (((desc)->dtepd_nrecs - 1) * sizeof(struct dtrace_recdesc)) : 0)) -+ -+#define DTRACE_SIZEOF_AGGDESC(desc) \ -+ (sizeof(struct dtrace_aggdesc) + ((desc)->dtagd_nrecs ? \ -+ (((desc)->dtagd_nrecs - 1) * sizeof(struct dtrace_recdesc)) : 0)) -+ -+#endif /* _LINUX_DTRACE_METADESC_H */ -diff --git a/include/uapi/linux/dtrace/metadesc_defines.h b/include/uapi/linux/dtrace/metadesc_defines.h -new file mode 100644 -index 000000000000..b27cc28822c8 ---- /dev/null -+++ b/include/uapi/linux/dtrace/metadesc_defines.h -@@ -0,0 +1,24 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_METADESC_DEFINES_H -+#define _LINUX_DTRACE_METADESC_DEFINES_H -+ -+#include <linux/dtrace/universal.h> -+ -+struct dtrace_recdesc; -+struct dtrace_eprobedesc; -+struct dtrace_aggdesc; -+struct dtrace_fmtdesc; -+ -+#endif /* _LINUX_DTRACE_METADESC_DEFINES_H */ -diff --git a/include/uapi/linux/dtrace/options.h b/include/uapi/linux/dtrace/options.h -new file mode 100644 -index 000000000000..0a652ca2a148 ---- /dev/null -+++ b/include/uapi/linux/dtrace/options.h -@@ -0,0 +1,20 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_OPTIONS_H -+#define _LINUX_DTRACE_OPTIONS_H -+ -+#include <linux/dtrace/universal.h> -+#include <linux/dtrace/options_defines.h> -+ -+#endif /* _LINUX_DTRACE_OPTIONS_H */ -diff --git a/include/uapi/linux/dtrace/options_defines.h b/include/uapi/linux/dtrace/options_defines.h -new file mode 100644 -index 000000000000..26009c84437e ---- /dev/null -+++ b/include/uapi/linux/dtrace/options_defines.h -@@ -0,0 +1,72 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_OPTIONS_DEFINES_H -+#define _LINUX_DTRACE_OPTIONS_DEFINES_H -+ -+#include <linux/dtrace/universal.h> -+ -+/* -+ * Run-time DTrace options are set and retrieved via DOF_SECT_OPTDESC sections -+ * in a DOF image. The dof_optdesc structure contains an option identifier and -+ * an option value. The valid option identifiers are found below; the mapping -+ * between option identifiers and option identifying strings is maintained at -+ * user-level. Note that the value of DTRACEOPT_UNSET is such that all of the -+ * following are potentially valid option values: all positive integers, zero -+ * and negative one. Some options (notably "bufpolicy" and "bufresize") take -+ * predefined tokens as their values; these are defined with -+ * DTRACEOPT_{option}_{token}. -+ */ -+ -+#define DTRACEOPT_BUFSIZE 0 /* buffer size */ -+#define DTRACEOPT_BUFPOLICY 1 /* buffer policy */ -+#define DTRACEOPT_DYNVARSIZE 2 /* dynamic variable size */ -+#define DTRACEOPT_AGGSIZE 3 /* aggregation size */ -+#define DTRACEOPT_SPECSIZE 4 /* speculation size */ -+#define DTRACEOPT_NSPEC 5 /* number of speculations */ -+#define DTRACEOPT_STRSIZE 6 /* string size */ -+#define DTRACEOPT_CLEANRATE 7 /* dynvar cleaning rate */ -+#define DTRACEOPT_CPU 8 /* CPU to trace */ -+#define DTRACEOPT_BUFRESIZE 9 /* buffer resizing policy */ -+#define DTRACEOPT_GRABANON 10 /* grab anonymous state, if any */ -+#define DTRACEOPT_FLOWINDENT 11 /* indent function entry/return */ -+#define DTRACEOPT_QUIET 12 /* only output explicitly traced data */ -+#define DTRACEOPT_STACKFRAMES 13 /* number of stack frames */ -+#define DTRACEOPT_USTACKFRAMES 14 /* number of user stack frames */ -+#define DTRACEOPT_AGGRATE 15 /* aggregation snapshot rate */ -+#define DTRACEOPT_SWITCHRATE 16 /* buffer switching rate */ -+#define DTRACEOPT_STATUSRATE 17 /* status rate */ -+#define DTRACEOPT_DESTRUCTIVE 18 /* destructive actions allowed */ -+#define DTRACEOPT_STACKINDENT 19 /* output indent for stack traces */ -+#define DTRACEOPT_RAWBYTES 20 /* always print bytes in raw form */ -+#define DTRACEOPT_JSTACKFRAMES 21 /* number of jstack() frames */ -+#define DTRACEOPT_JSTACKSTRSIZE 22 /* size of jstack() string table */ -+#define DTRACEOPT_AGGSORTKEY 23 /* sort aggregations by key */ -+#define DTRACEOPT_AGGSORTREV 24 /* reverse-sort aggregations */ -+#define DTRACEOPT_AGGSORTPOS 25 /* agg. position to sort on */ -+#define DTRACEOPT_AGGSORTKEYPOS 26 /* agg. key position to sort on */ -+#define DTRACEOPT_QUIETRESIZE 27 /* quieten buffer-resize messages */ -+#define DTRACEOPT_NORESOLVE 28 /* prevent resolution of symbols */ -+#define DTRACEOPT_PCAPSIZE 29 /* number of bytes to be captured */ -+#define DTRACEOPT_MAX 30 /* number of options */ -+ -+#define DTRACEOPT_UNSET (dtrace_optval_t)-2 /* unset option */ -+ -+#define DTRACEOPT_BUFPOLICY_RING 0 /* ring buffer */ -+#define DTRACEOPT_BUFPOLICY_FILL 1 /* fill buffer, then stop */ -+#define DTRACEOPT_BUFPOLICY_SWITCH 2 /* switch buffers */ -+ -+#define DTRACEOPT_BUFRESIZE_AUTO 0 /* automatic resizing */ -+#define DTRACEOPT_BUFRESIZE_MANUAL 1 /* manual resizing */ -+ -+#endif /* _LINUX_DTRACE_OPTIONS_DEFINES_H */ -diff --git a/include/uapi/linux/dtrace/stability.h b/include/uapi/linux/dtrace/stability.h -new file mode 100644 -index 000000000000..380effdab291 ---- /dev/null -+++ b/include/uapi/linux/dtrace/stability.h -@@ -0,0 +1,52 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_STABILITY_H -+#define _LINUX_DTRACE_STABILITY_H -+ -+#include <linux/dtrace/universal.h> -+#include <linux/dtrace/stability_defines.h> -+ -+/* -+ * Each DTrace provider advertises the name and data stability of each of its -+ * probe description components, as well as its architectural dependencies. The -+ * D compiler can query the provider attributes (dtrace_pattr_t) in order to -+ * compute the properties of an input program and report them. -+ */ -+ -+typedef struct dtrace_ppriv { -+ uint32_t dtpp_flags; /* privilege flags */ -+ uid_t dtpp_uid; /* user ID */ -+} dtrace_ppriv_t; -+ -+typedef struct dtrace_attribute { -+ dtrace_stability_t dtat_name; /* entity name stability */ -+ dtrace_stability_t dtat_data; /* entity data stability */ -+ dtrace_class_t dtat_class; /* entity data dependency */ -+} dtrace_attribute_t; -+ -+typedef struct dtrace_pattr { -+ struct dtrace_attribute dtpa_provider; /* provider attributes */ -+ struct dtrace_attribute dtpa_mod; /* module attributes */ -+ struct dtrace_attribute dtpa_func; /* function attributes */ -+ struct dtrace_attribute dtpa_name; /* name attributes */ -+ struct dtrace_attribute dtpa_args; /* args[] attributes */ -+} dtrace_pattr_t; -+ -+typedef struct dtrace_providerdesc { -+ char dtvd_name[DTRACE_PROVNAMELEN]; /* provider name */ -+ struct dtrace_pattr dtvd_attr; /* stability attributes */ -+ struct dtrace_ppriv dtvd_priv; /* privileges required */ -+} dtrace_providerdesc_t; -+ -+#endif /* _LINUX_DTRACE_STABILITY_H */ -diff --git a/include/uapi/linux/dtrace/stability_defines.h b/include/uapi/linux/dtrace/stability_defines.h -new file mode 100644 -index 000000000000..ca58c5c03c2b ---- /dev/null -+++ b/include/uapi/linux/dtrace/stability_defines.h -@@ -0,0 +1,53 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_STABILITY_DEFINES_H -+#define _LINUX_DTRACE_STABILITY_DEFINES_H -+ -+#include <linux/dtrace/universal.h> -+ -+typedef uint8_t dtrace_stability_t; /* stability code */ -+typedef uint8_t dtrace_class_t; /* architectural dependency class */ -+ -+#define DTRACE_STABILITY_INTERNAL 0 /* private to DTrace itself */ -+#define DTRACE_STABILITY_PRIVATE 1 /* private to Sun (see docs) */ -+#define DTRACE_STABILITY_OBSOLETE 2 /* scheduled for removal */ -+#define DTRACE_STABILITY_EXTERNAL 3 /* not controlled by Sun */ -+#define DTRACE_STABILITY_UNSTABLE 4 /* new or rapidly changing */ -+#define DTRACE_STABILITY_EVOLVING 5 /* less rapidly changing */ -+#define DTRACE_STABILITY_STABLE 6 /* mature interface from Sun */ -+#define DTRACE_STABILITY_STANDARD 7 /* industry standard */ -+#define DTRACE_STABILITY_MAX 7 /* maximum valid stability */ -+ -+#define DTRACE_CLASS_UNKNOWN 0 /* unknown architectural dependency */ -+#define DTRACE_CLASS_CPU 1 /* CPU-module-specific */ -+#define DTRACE_CLASS_PLATFORM 2 /* platform-specific (uname -i) */ -+#define DTRACE_CLASS_GROUP 3 /* hardware-group-specific (uname -m) */ -+#define DTRACE_CLASS_ISA 4 /* ISA-specific (uname -p) */ -+#define DTRACE_CLASS_COMMON 5 /* common to all systems */ -+#define DTRACE_CLASS_MAX 5 /* maximum valid class */ -+ -+#define DTRACE_PRIV_NONE 0x0000 -+#define DTRACE_PRIV_KERNEL 0x0001 -+#define DTRACE_PRIV_USER 0x0002 -+#define DTRACE_PRIV_PROC 0x0004 -+#define DTRACE_PRIV_OWNER 0x0008 -+#define DTRACE_PRIV_ALL (DTRACE_PRIV_KERNEL | DTRACE_PRIV_USER | \ -+ DTRACE_PRIV_PROC | DTRACE_PRIV_OWNER) -+ -+struct dtrace_ppriv; -+struct dtrace_attribute; -+struct dtrace_pattr; -+struct dtrace_providerdesc; -+ -+#endif /* _LINUX_DTRACE_STABILITY_DEFINES_H */ -diff --git a/include/uapi/linux/dtrace/status.h b/include/uapi/linux/dtrace/status.h -new file mode 100644 -index 000000000000..dc324199f170 ---- /dev/null -+++ b/include/uapi/linux/dtrace/status.h -@@ -0,0 +1,50 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_STATUS_H -+#define _LINUX_DTRACE_STATUS_H -+ -+#include <linux/dtrace/universal.h> -+ -+/* -+ * The status of DTrace is relayed via the dtrace_status structure. This -+ * structure contains members to count drops other than the capacity drops -+ * available via the buffer interface (see above). This consists of dynamic -+ * drops (including capacity dynamic drops, rinsing drops and dirty drops), and -+ * speculative drops (including capacity speculative drops, drops due to busy -+ * speculative buffers and drops due to unavailable speculative buffers). -+ * Additionally, the status structure contains a field to indicate the number -+ * of "fill"-policy buffers have been filled and a boolean field to indicate -+ * that exit() has been called. If the dtst_exiting field is non-zero, no -+ * further data will be generated until tracing is stopped (at which time any -+ * enablings of the END action will be processed); if user-level sees that -+ * this field is non-zero, tracing should be stopped as soon as possible. -+ */ -+ -+typedef struct dtrace_status { -+ uint64_t dtst_dyndrops; /* dynamic drops */ -+ uint64_t dtst_dyndrops_rinsing; /* dyn drops due to rinsing */ -+ uint64_t dtst_dyndrops_dirty; /* dyn drops due to dirty */ -+ uint64_t dtst_specdrops; /* speculative drops */ -+ uint64_t dtst_specdrops_busy; /* spec drops due to busy */ -+ uint64_t dtst_specdrops_unavail; /* spec drops due to unavail */ -+ uint64_t dtst_errors; /* total errors */ -+ uint64_t dtst_filled; /* number of filled bufs */ -+ uint64_t dtst_stkstroverflows; /* stack string tab overflows */ -+ uint64_t dtst_dblerrors; /* errors in ERROR probes */ -+ char dtst_killed; /* non-zero if killed */ -+ char dtst_exiting; /* non-zero if exit() called */ -+ char dtst_pad[6]; /* pad out to 64-bit align */ -+} dtrace_status_t; -+ -+#endif /* _LINUX_DTRACE_STATUS_H */ -diff --git a/include/uapi/linux/dtrace/universal.h b/include/uapi/linux/dtrace/universal.h -new file mode 100644 -index 000000000000..5c2f3f838fef ---- /dev/null -+++ b/include/uapi/linux/dtrace/universal.h -@@ -0,0 +1,47 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_UNIVERSAL_H_ -+#define _LINUX_DTRACE_UNIVERSAL_H_ -+ -+#define DTRACE_CPUALL -1 /* all CPUs */ -+#define DTRACE_IDNONE 0 /* invalid probe identifier */ -+#define DTRACE_EPIDNONE 0 /* invalid enabled probe identifier */ -+#define DTRACE_AGGIDNONE 0 /* invalid aggregation identifier */ -+#define DTRACE_AGGVARIDNONE 0 /* invalid aggregation variable ID */ -+#define DTRACE_CACHEIDNONE 0 /* invalid predicate cache */ -+#define DTRACE_PROVNONE 0 /* invalid provider identifier */ -+#define DTRACE_METAPROVNONE 0 /* invalid meta-provider identifier */ -+#define DTRACE_ARGNONE -1 /* invalid argument index */ -+ -+#define DTRACE_PROVNAMELEN 64 -+#define DTRACE_MODNAMELEN 64 -+#define DTRACE_FUNCNAMELEN 128 -+#define DTRACE_NAMELEN 64 -+#define DTRACE_FULLNAMELEN (DTRACE_PROVNAMELEN + DTRACE_MODNAMELEN + \ -+ DTRACE_FUNCNAMELEN + DTRACE_NAMELEN + 4) -+#define DTRACE_ARGTYPELEN 128 -+ -+typedef uint16_t dtrace_actkind_t; /* action kind */ -+ -+typedef uint32_t dtrace_aggid_t; /* aggregation identifier */ -+typedef uint32_t dtrace_cacheid_t; /* predicate cache identifier */ -+typedef uint32_t dtrace_epid_t; /* enabled probe identifier */ -+typedef uint32_t dtrace_optid_t; /* option identifier */ -+typedef uint32_t dtrace_specid_t; /* speculation identifier */ -+ -+typedef uint64_t dtrace_aggvarid_t; /* aggregation variable id */ -+typedef uint64_t dtrace_genid_t; /* generation identifier */ -+typedef uint64_t dtrace_optval_t; /* option value */ -+ -+#endif /* _LINUX_DTRACE_UNIVERSAL_H_ */ -diff --git a/init/Kconfig b/init/Kconfig -index 5a86bbbf43e0..0f1b919272da 100644 ---- a/init/Kconfig -+++ b/init/Kconfig -@@ -2052,6 +2052,8 @@ config PROFILING - Say Y here to enable the extended profiling support mechanisms used - by profilers such as OProfile. - -+source "kernel/dtrace/Kconfig" -+ - # - # Place an empty function call at each tracepoint site. Can be - # dynamically changed for a probe function. -diff --git a/init/main.c b/init/main.c -index 9d964511fe0c..f510b7af38c2 100644 ---- a/init/main.c -+++ b/init/main.c -@@ -98,6 +98,8 @@ - #include <linux/mem_encrypt.h> - #include <linux/kcsan.h> - #include <linux/init_syscalls.h> -+#include <linux/dtrace_cpu.h> -+#include <linux/dtrace_os.h> - - #include <asm/io.h> - #include <asm/bugs.h> -@@ -1057,6 +1059,10 @@ asmlinkage __visible void __init __no_sanitize_address start_kernel(void) - sfi_init_late(); - kcsan_init(); - -+#ifdef CONFIG_DTRACE -+ dtrace_os_init(); -+#endif -+ - /* Do the rest non-__init'ed, we're now alive */ - arch_call_rest_init(); - -@@ -1512,6 +1518,10 @@ static noinline void __init kernel_init_freeable(void) - - init_mm_internals(); - -+#ifdef CONFIG_DTRACE -+ dtrace_cpu_init(); -+#endif -+ - rcu_init_tasks_generic(); - do_pre_smp_initcalls(); - lockup_detector_init(); -diff --git a/kernel/Makefile b/kernel/Makefile -index 6c9f19911be0..498cb12d89c6 100644 ---- a/kernel/Makefile -+++ b/kernel/Makefile -@@ -121,6 +121,7 @@ obj-$(CONFIG_TORTURE_TEST) += torture.o - obj-$(CONFIG_HAS_IOMEM) += iomem.o - obj-$(CONFIG_RSEQ) += rseq.o - obj-$(CONFIG_WATCH_QUEUE) += watch_queue.o -+obj-$(CONFIG_DTRACE) += dtrace/ - - obj-$(CONFIG_SYSCTL_KUNIT_TEST) += sysctl-test.o - -diff --git a/kernel/dtrace/Kconfig b/kernel/dtrace/Kconfig -new file mode 100644 -index 000000000000..854e4411343f ---- /dev/null -+++ b/kernel/dtrace/Kconfig -@@ -0,0 +1,54 @@ -+# -+# Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved. -+# -+ -+menuconfig DTRACE -+ bool "DTrace (Dynamic Tracing) Support" -+ default y -+ depends on ARCH_SUPPORTS_DTRACE -+ select KALLSYMS -+ select KALLMODSYMS -+ select WAITFD -+ select CTF -+ help -+ The DTrace dynamic tracing framework. -+ -+if DTRACE -+ -+config DT_CORE -+ tristate "DTrace core" -+ default m -+ help -+ The core of DTrace: needed for all providers. -+ -+if DT_CORE -+ -+config DT_DT_TEST -+ tristate "DTrace Test Probe" -+ default m -+ help -+ A test provider used by the testsuite. -+ -+config DT_DEBUG -+ bool "DTrace debugging" -+ default m -+ help -+ This controls the inclusion of various piece of code that perform -+ internal checks within the DTrace core. It also enables all the -+ assertions within the DTrace code. -+ -+if DT_DEBUG -+ -+config DT_DEBUG_MUTEX -+ bool "DTrace mutex debugging" -+ default n -+ help -+ This controls the use of DTrace specific wrappers to output debug -+ messages whenever a mutex is locked or unlocked within the DTrace -+ code (core and providers). -+ -+endif # DT_DEBUG -+ -+endif # DT_CORE -+ -+endif #DTRACE -diff --git a/kernel/dtrace/Makefile b/kernel/dtrace/Makefile -new file mode 100644 -index 000000000000..872785327c3d ---- /dev/null -+++ b/kernel/dtrace/Makefile -@@ -0,0 +1,12 @@ -+# -+# Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. -+# -+ -+DT_CORE_ARCH_OBJS = $(addprefix ../../arch/$(SRCARCH)/kernel/, \ -+ dtrace_util.o) -+ -+ifdef CONFIG_DT_CORE -+obj-y += cyclic.o dtrace_os.o dtrace_cpu.o \ -+ dtrace_task.o dtrace_psinfo.o \ -+ $(DT_CORE_ARCH_OBJS) -+endif -diff --git a/kernel/dtrace/cyclic.c b/kernel/dtrace/cyclic.c -new file mode 100644 -index 000000000000..6497ceee3782 ---- /dev/null -+++ b/kernel/dtrace/cyclic.c -@@ -0,0 +1,526 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: cyclic.c -+ * DESCRIPTION: Minimal cyclic implementation -+ * -+ * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/cpu.h> -+#include <linux/cyclic.h> -+#include <linux/hrtimer.h> -+#include <linux/module.h> -+#include <linux/proc_fs.h> -+#include <linux/seq_file.h> -+#include <linux/slab.h> -+#include <linux/spinlock.h> -+#include <linux/workqueue.h> -+ -+static int omni_enabled; -+ -+#define _CYCLIC_CPU_UNDEF (-1) -+#define _CYCLIC_CPU_OMNI (-2) -+#define CYCLIC_IS_OMNI(cyc) ((cyc)->cpu == _CYCLIC_CPU_OMNI) -+ -+struct cyclic_work { -+ struct work_struct work; -+ struct cyclic *cyc; -+}; -+ -+struct cyclic { -+ struct list_head list; -+ int cpu; -+ union { -+ struct { -+ struct cyc_time when; -+ struct cyc_handler hdlr; -+ uint32_t pend; -+ struct hrtimer timr; -+ struct cyclic_work work; -+ } cyc; -+ struct { -+ struct cyc_omni_handler hdlr; -+ struct list_head cycl; -+ } omni; -+ }; -+}; -+ -+static LIST_HEAD(cyclics); -+ -+static void cyclic_fire(struct work_struct *work) -+{ -+ struct cyclic_work *cwork = (struct cyclic_work *)work; -+ struct cyclic *cyc = cwork->cyc; -+ uint32_t cpnd, npnd; -+ -+ do { -+ /* -+ * We know that the 'pend' counter for the cyclic is non-zero. -+ * So, we can start with calling the handler at least once. -+ */ -+ (*cyc->cyc.hdlr.cyh_func)(cyc->cyc.hdlr.cyh_arg); -+ -+again: -+ /* -+ * The 'pend' counter may be modified by cyclic_expire() while -+ * we go through this loop. We use an atomic compare-and-set -+ * instruction to determine whether it got changed. If so, we -+ * retrieve the updated 'pend' value and try this again. -+ * -+ * Note that when the cyclic is being removed, the hrtimer will -+ * be cancelled first, which ensures that 'pend' will no longer -+ * be incremented. When that happens, this loop will simply -+ * run through the remaining pending calls, and terminate. -+ */ -+ cpnd = cyc->cyc.pend; -+ npnd = cpnd - 1; -+ if (cmpxchg(&cyc->cyc.pend, cpnd, npnd) != cpnd) -+ goto again; -+ } while (npnd > 0); -+} -+ -+/* -+ * Timer expiration handler for cyclic hrtimers. Cyclic worker functions must -+ * be able to perform a variety of tasks (including calling functions that -+ * could sleep), and therefore they cannot be called from interrupt context. -+ * -+ * We schedule a workqueue to do the actual work. -+ * -+ * But... under heavy load it is possible that the hrtimer will expire again -+ * before the workqueue had a chance to run. That would lead to missed events -+ * which isn't quite acceptable. Therefore, we use a counter to record how -+ * many times the timer has expired vs how many times the handler has been -+ * called. The counter is incremented by this function upon hrtimer expiration -+ * and decremented by the cyclic_fire. Note that the workqueue is responsible -+ * for calling the handler multiple times if the counter indicates that multiple -+ * invocation are pending. -+ * -+ * This function is called as hrtimer handler, and therefore runs in interrupt -+ * context, which by definition will ensure that manipulation of the 'pend' -+ * counter in the cyclic can be done without locking, and changes will appear -+ * atomic to the cyclic_fire(). -+ * -+ * Moral of the story: the handler may not get called at the absolute times as -+ * requested, but it will be called the correct number of times. -+ */ -+static enum hrtimer_restart cyclic_expire(struct hrtimer *timr) -+{ -+ struct cyclic *cyc = container_of(timr, struct cyclic, cyc.timr); -+ -+ /* -+ * High priority cyclics call directly into their handler. This means -+ * that the handler must satisfy all requirements for executing code in -+ * interrupt context. -+ */ -+ if (cyc->cyc.hdlr.cyh_level == CY_HIGH_LEVEL) { -+ (*cyc->cyc.hdlr.cyh_func)(cyc->cyc.hdlr.cyh_arg); -+ goto done; -+ } -+ -+ /* -+ * Increment the 'pend' counter, in case the work is already set to -+ * run. If the counter was 0 upon entry, we need to schedule the -+ * work. If the increment wraps the counter back to 0, we admit -+ * defeat, and reset it to its max value. -+ */ -+ if (cyc->cyc.pend++ == 0) -+ schedule_work_on(cyc->cpu, -+ (struct work_struct *)&cyc->cyc.work); -+ else if (cyc->cyc.pend == 0) -+ cyc->cyc.pend = UINT_MAX; -+ -+done: -+ /* -+ * Prepare the timer for the next expiration. -+ */ -+ if (cyc->cyc.when.cyt_interval == CY_INTERVAL_INF) -+ return HRTIMER_NORESTART; -+ -+ hrtimer_forward_now(timr, cyc->cyc.when.cyt_interval); -+ -+ return HRTIMER_RESTART; -+} -+ -+struct cyclic *cyclic_new(int omni) -+{ -+ struct cyclic *cyc; -+ -+ cyc = kmalloc(sizeof(struct cyclic), GFP_KERNEL); -+ if (cyc == NULL) -+ return NULL; -+ -+ INIT_LIST_HEAD(&cyc->list); -+ -+ if (!omni) { -+ cyc->cpu = _CYCLIC_CPU_UNDEF; -+ cyc->cyc.pend = 0; -+ hrtimer_init(&cyc->cyc.timr, CLOCK_MONOTONIC, -+ HRTIMER_MODE_REL_PINNED); -+ cyc->cyc.timr.function = cyclic_expire; -+ cyc->cyc.work.cyc = cyc; -+ INIT_WORK((struct work_struct *)&cyc->cyc.work, cyclic_fire); -+ } else { -+ cyc->cpu = _CYCLIC_CPU_OMNI; -+ INIT_LIST_HEAD(&cyc->omni.cycl); -+ } -+ -+ return cyc; -+} -+ -+static inline void cyclic_restart(struct cyclic *cyc) -+{ -+ if (cyc->cyc.when.cyt_interval == CY_INTERVAL_INF) -+ return; -+ -+ if (cyc->cyc.when.cyt_when == 0) -+ hrtimer_start(&cyc->cyc.timr, cyc->cyc.when.cyt_interval, -+ HRTIMER_MODE_REL_PINNED); -+ else -+ hrtimer_start(&cyc->cyc.timr, cyc->cyc.when.cyt_when, -+ HRTIMER_MODE_ABS_PINNED); -+} -+ -+/* -+ * Add a new cyclic to the system. -+ */ -+cyclic_id_t cyclic_add(struct cyc_handler *hdlr, struct cyc_time *when) -+{ -+ struct cyclic *cyc; -+ -+ if (hdlr == NULL || when == NULL) -+ return CYCLIC_NONE; -+ -+ cyc = cyclic_new(0); -+ if (cyc == NULL) -+ return CYCLIC_NONE; -+ -+ list_add(&cyc->list, &cyclics); -+ cyc->cpu = smp_processor_id(); -+ cyc->cyc.when = *when; -+ cyc->cyc.hdlr = *hdlr; -+ -+ cyclic_restart(cyc); -+ -+ return (cyclic_id_t)cyc; -+} -+EXPORT_SYMBOL(cyclic_add); -+ -+static void cyclic_omni_xcall(struct cyclic *cyc) -+{ -+ cyclic_restart(cyc); -+} -+ -+/* -+ * Add a new cyclic to the system. -+ */ -+static void cyclic_add_pinned(int cpu, struct cyclic *omni, -+ struct cyc_handler *hdlr, struct cyc_time *when) -+{ -+ struct cyclic *cyc; -+ -+ cyc = cyclic_new(0); -+ if (cyc == NULL) -+ return; -+ -+ list_add(&cyc->list, &omni->omni.cycl); -+ cyc->cpu = cpu; -+ cyc->cyc.when = *when; -+ cyc->cyc.hdlr = *hdlr; -+ -+ smp_call_function_single(cpu, (smp_call_func_t)cyclic_omni_xcall, -+ cyc, 1); -+} -+ -+/* -+ * Start a cyclic on a specific CPU as sub-cyclic to an omni-present cyclic. -+ */ -+static void cyclic_omni_start(struct cyclic *omni, int cpu) -+{ -+ struct cyc_time when; -+ struct cyc_handler hdlr; -+ -+ omni->omni.hdlr.cyo_online(omni->omni.hdlr.cyo_arg, cpu, &hdlr, &when); -+ cyclic_add_pinned(cpu, omni, &hdlr, &when); -+} -+ -+#ifdef CONFIG_HOTPLUG_CPU -+static int cyclic_cpu_offline(unsigned int cpu) -+{ -+ struct cyclic *cyc; -+ -+ list_for_each_entry(cyc, &cyclics, list) { -+ struct cyclic *c, *n; -+ -+ if (!CYCLIC_IS_OMNI(cyc)) -+ continue; -+ -+ list_for_each_entry_safe(c, n, &cyc->omni.cycl, list) { -+ if (c->cpu == cpu) -+ cyclic_remove((cyclic_id_t)c); -+ } -+ } -+ return 0; -+} -+ -+static int cyclic_cpu_online(unsigned int cpu) -+{ -+ struct cyclic *cyc; -+ -+ list_for_each_entry(cyc, &cyclics, list) { -+ struct cyclic *c, *n; -+ -+ if (!CYCLIC_IS_OMNI(cyc)) -+ continue; -+ -+ list_for_each_entry_safe(c, n, &cyc->omni.cycl, list) { -+ if (c->cpu == cpu) -+ break; -+ } -+ -+ if (c->cpu == cpu) -+ continue; -+ -+ cyclic_omni_start(cyc, cpu); -+ } -+ return 0; -+} -+#endif -+ -+/* -+ * Add a new omnipresent cyclic to the system. -+ */ -+cyclic_id_t cyclic_add_omni(struct cyc_omni_handler *omni) -+{ -+ int cpu; -+ struct cyclic *cyc; -+ -+ cyc = cyclic_new(1); -+ if (cyc == NULL) -+ return CYCLIC_NONE; -+ -+ list_add(&cyc->list, &cyclics); -+ cyc->omni.hdlr = *omni; -+ -+ for_each_online_cpu(cpu) -+ cyclic_omni_start(cyc, cpu); -+ -+ return (cyclic_id_t)cyc; -+} -+EXPORT_SYMBOL(cyclic_add_omni); -+ -+/* -+ * Remove a specific cyclic from the system. -+ */ -+void cyclic_remove(cyclic_id_t id) -+{ -+ struct cyclic *cyc = (struct cyclic *)id; -+ -+ if (CYCLIC_IS_OMNI(cyc)) { -+ struct cyclic *child, *n; -+ -+ /* -+ * If this is an omni-present cyclic, we first need to remove -+ * all the associated per-CPU cyclics. Note that the recursive -+ * call into cyclic_remove() for a child cyclic will remove it -+ * from the list of per-CPU cyclics associated with the -+ * omni-present cyclic, so we do not need to handle that here. -+ */ -+ list_for_each_entry_safe(child, n, &cyc->omni.cycl, list) -+ cyclic_remove((cyclic_id_t)child); -+ } else { -+ /* -+ * We know that hrtimer_cancel() will wait for the timer -+ * callback to finish if it is being executed at the time of -+ * making this call. It is therefore guaranteed that 'pend' -+ * will no longer get incremented. -+ * -+ * The call to cancel_work_sync() will wait for the workqueue -+ * handler to finish also, and since the handler always brings -+ * 'pend' down to zero prior to returning, it is guaranteed that -+ * (1) all pending handler calls will be made before -+ * cyclic_remove() returns -+ * (2) the amount of work to do before returning is finite. -+ */ -+ hrtimer_cancel(&cyc->cyc.timr); -+ cancel_work_sync((struct work_struct *)&cyc->cyc.work); -+ } -+ -+ list_del(&cyc->list); -+ kfree(cyc); -+} -+EXPORT_SYMBOL(cyclic_remove); -+ -+struct cyclic_reprog { -+ cyclic_id_t cycid; -+ ktime_t delta; -+}; -+ -+static void cyclic_reprogram_xcall(struct cyclic_reprog *creprog) -+{ -+ cyclic_reprogram(creprog->cycid, creprog->delta); -+} -+ -+/* -+ * Reprogram cyclic to fire with given delta from now. -+ * -+ * The underlying design makes it safe to call cyclic_reprogram from whithin a -+ * cyclic handler without race with cyclic_remove. If called from outside of the -+ * cyclic handler it is up to the owner to ensure to not call cyclic_reprogram -+ * after call to cyclic_remove. -+ * -+ * This function cannot be called from interrupt/bottom half contexts. -+ */ -+void cyclic_reprogram(cyclic_id_t id, ktime_t delta) -+{ -+ struct cyclic *cyc = (struct cyclic *)id; -+ -+ /* -+ * For omni present cyclic we reprogram child for current CPU. -+ */ -+ if (CYCLIC_IS_OMNI(cyc)) { -+ struct cyclic *c, *n; -+ -+ list_for_each_entry_safe(c, n, &cyc->omni.cycl, list) { -+ if (c->cpu != smp_processor_id()) -+ continue; -+ -+ hrtimer_start(&c->cyc.timr, delta, -+ HRTIMER_MODE_ABS_PINNED); -+ -+ break; -+ } -+ -+ return; -+ } -+ -+ /* -+ * Regular cyclic reprogram must ensure that the timer remains bound -+ * to the CPU it was registered on. In case we are called from -+ * different CPU we use xcall to trigger reprogram from correct cpu. -+ */ -+ if (cyc->cpu != smp_processor_id()) { -+ struct cyclic_reprog creprog = { -+ .cycid = id, -+ .delta = delta, -+ }; -+ -+ smp_call_function_single(cyc->cpu, (smp_call_func_t) -+ cyclic_reprogram_xcall, &creprog, 1); -+ } else { -+ hrtimer_start(&cyc->cyc.timr, delta, HRTIMER_MODE_REL_PINNED); -+ } -+} -+EXPORT_SYMBOL(cyclic_reprogram); -+ -+static void *s_start(struct seq_file *seq, loff_t *pos) -+{ -+ loff_t n = *pos; -+ struct cyclic *cyc; -+ -+ list_for_each_entry(cyc, &cyclics, list) { -+ if (n == 0) -+ return cyc; -+ -+ n--; -+ } -+ -+ return NULL; -+} -+ -+static void *s_next(struct seq_file *seq, void *p, loff_t *pos) -+{ -+ struct cyclic *cyc = p; -+ -+ ++*pos; -+ -+ cyc = list_entry(cyc->list.next, struct cyclic, list); -+ if (&cyc->list == &cyclics) -+ return NULL; -+ -+ return cyc; -+} -+ -+static void s_stop(struct seq_file *seq, void *p) -+{ -+} -+ -+static int s_show(struct seq_file *seq, void *p) -+{ -+ struct cyclic *cyc = p; -+ -+ if (CYCLIC_IS_OMNI(cyc)) { -+ struct cyclic *c; -+ -+ seq_puts(seq, "Omni-present cyclic:\n"); -+ list_for_each_entry(c, &cyc->omni.cycl, list) -+ seq_printf(seq, -+ " CPU-%d: %c %lld ns hdlr %pB arg %llx\n", -+ c->cpu, -+ c->cyc.hdlr.cyh_level == CY_HIGH_LEVEL -+ ? 'H' : 'l', -+ c->cyc.when.cyt_interval, -+ c->cyc.hdlr.cyh_func, -+ (uint64_t)c->cyc.hdlr.cyh_arg); -+ } else -+ seq_printf(seq, "CPU-%d: %c %lld ns hdlr %pB arg %llx\n", -+ cyc->cpu, -+ cyc->cyc.hdlr.cyh_level == CY_HIGH_LEVEL -+ ? 'H' : 'l', -+ cyc->cyc.when.cyt_interval, -+ cyc->cyc.hdlr.cyh_func, -+ (uint64_t)cyc->cyc.hdlr.cyh_arg); -+ -+ return 0; -+} -+ -+static const struct seq_operations cyclicinfo_ops = { -+ .start = s_start, -+ .next = s_next, -+ .stop = s_stop, -+ .show = s_show, -+}; -+ -+static int cyclicinfo_open(struct inode *inode, struct file *file) -+{ -+ return seq_open(file, &cyclicinfo_ops); -+} -+ -+static const struct proc_ops proc_cyclicinfo_ops = { -+ .proc_open = cyclicinfo_open, -+ .proc_read = seq_read, -+ .proc_lseek = seq_lseek, -+ .proc_release = seq_release, -+}; -+ -+static int __init cyclic_init(void) -+{ -+ int ret; -+ -+ proc_create("cyclicinfo", 0400, NULL, &proc_cyclicinfo_ops); -+ -+#ifdef CONFIG_HOTPLUG_CPU -+ if (!omni_enabled) { -+ ret = cpuhp_setup_state_nocalls(CPUHP_AP_CYCLIC_STARTING, -+ "Cyclic omni-timer starting", -+ cyclic_cpu_online, -+ cyclic_cpu_offline); -+ if (ret) -+ pr_warn_once("Cannot enable cyclic omni timer\n"); -+ else -+ omni_enabled = 1; -+ } -+#endif -+ -+ return 0; -+} -+module_init(cyclic_init); -diff --git a/kernel/dtrace/dtrace_cpu.c b/kernel/dtrace/dtrace_cpu.c -new file mode 100644 -index 000000000000..1bc6e3bb4ce0 ---- /dev/null -+++ b/kernel/dtrace/dtrace_cpu.c -@@ -0,0 +1,61 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_cpu.c -+ * DESCRIPTION: DTrce - per-CPU state -+ * -+ * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/dtrace_cpu.h> -+#include <linux/module.h> -+#include <asm/dtrace_cpuinfo.h> -+ -+DEFINE_PER_CPU_SHARED_ALIGNED(struct cpu_core, dtrace_cpu_core); -+EXPORT_PER_CPU_SYMBOL(dtrace_cpu_core); -+ -+DEFINE_PER_CPU_SHARED_ALIGNED(struct cpuinfo, dtrace_cpu_info); -+EXPORT_PER_CPU_SYMBOL(dtrace_cpu_info); -+ -+void dtrace_cpu_init(void) -+{ -+ int cpu; -+ -+ /* -+ * Force this type into the CTF for the sake of userspace's -+ * ABI requirements. -+ */ -+ cpuinfo_t *dummy __attribute__((__unused__)) = NULL; -+ -+ for_each_present_cpu(cpu) { -+ cpuinfo_arch_t *ci = &cpu_data(cpu); -+ struct cpuinfo *cpui = per_cpu_info(cpu); -+ struct cpu_core *cpuc = per_cpu_core(cpu); -+ -+ cpui->cpu_id = cpu; -+ cpui->cpu_pset = 0; -+ cpui->cpu_chip = dtrace_cpuinfo_chip(ci); -+ cpui->cpu_lgrp = 0; -+ cpui->cpu_info = ci; -+ -+ cpuc->cpuc_dtrace_flags = 0; -+ cpuc->cpuc_dcpc_intr_state = 0; -+ cpuc->cpuc_dtrace_illval = 0; -+ mutex_init(&cpuc->cpuc_pid_lock); -+ -+ cpuc->cpu_dtrace_regs = NULL; -+ cpuc->cpu_dtrace_caller = 0; -+ rwlock_init(&cpuc->cpu_ft_lock); -+ -+ cpuc->cpuc_current_probe = DTRACE_IDNONE; -+ } -+} -diff --git a/kernel/dtrace/dtrace_os.c b/kernel/dtrace/dtrace_os.c -new file mode 100644 -index 000000000000..d023f3913323 ---- /dev/null -+++ b/kernel/dtrace/dtrace_os.c -@@ -0,0 +1,332 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_os.c -+ * DESCRIPTION: DTrace - OS support functions -+ * -+ * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/binfmts.h> -+#include <linux/dtrace_cpu.h> -+#include <linux/dtrace_os.h> -+#include <linux/fs.h> -+#include <linux/hardirq.h> -+#include <linux/interrupt.h> -+#include <linux/kdebug.h> -+#include <linux/module.h> -+#include <linux/moduleloader.h> -+#include <linux/sched.h> -+#include <linux/slab.h> -+#include <linux/stacktrace.h> -+#include <linux/timekeeping.h> -+#include <linux/vmalloc.h> -+#include <linux/kallsyms.h> -+#include <linux/uaccess.h> -+#include <linux/workqueue.h> -+#include <asm/ptrace.h> -+#include <linux/init_task.h> -+#include <linux/sched/mm.h> -+#include <linux/shmem_fs.h> -+#include <linux/dtrace_task_impl.h> -+ -+/* -+ * OS SPECIFIC DTRACE SETUP -+ */ -+ -+/* -+ * DTrace pseudo module that represents vmlinux (the kernel itself). -+ * Since we populate its sdt data members only once, it can be marked -+ * as RO after init. -+ */ -+struct module *dtrace_kmod __ro_after_init = NULL; -+EXPORT_SYMBOL(dtrace_kmod); -+ -+int dtrace_ustackdepth_max = 2048; -+ -+struct kmem_cache *dtrace_pdata_cachep = NULL; -+ -+void __init dtrace_os_init(void) -+{ -+ /* -+ * Setup for module handling. -+ */ -+ dtrace_pdata_cachep = kmem_cache_create("dtrace_pdata_cache", -+ sizeof(struct dtrace_module), 0, -+ SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); -+ if (dtrace_pdata_cachep == NULL) -+ pr_debug("Can't allocate kmem cache for pdata\n"); -+ -+ /* -+ * We need to set up a psinfo structure for PID 0 (swapper). -+ */ -+ dtrace_task_os_init(); -+ dtrace_psinfo_os_init(); -+ dtrace_task_init(&init_task); -+ dtrace_psinfo_alloc(&init_task); -+} -+ -+/* -+ * MODULE SUPPORT FUNCTIONS -+ */ -+extern struct list_head *dtrace_modules; -+ -+/* -+ * Iterate over all loaded kernel modules. This is required until the linux -+ * kernel receives its own module iterator. -+ */ -+void dtrace_for_each_module(for_each_module_fn func, void *arg) -+{ -+ struct module *mp; -+ -+ if (func == NULL) -+ return; -+ -+ /* The dtrace fake module is not in the list. */ -+ func(arg, dtrace_kmod); -+ -+ list_for_each_entry(mp, dtrace_modules, list) { -+ -+#ifdef MODULES_VADDR -+ if ((uintptr_t)mp < MODULES_VADDR || -+ (uintptr_t)mp >= MODULES_END) -+ continue; -+#else -+ if ((uintptr_t)mp < VMALLOC_START || -+ (uintptr_t)mp >= VMALLOC_END) -+ continue; -+#endif -+ -+ func(arg, mp); -+ } -+} -+EXPORT_SYMBOL_GPL(dtrace_for_each_module); -+ -+ -+void dtrace_mod_pdata_alloc(struct module *mp) -+{ -+ struct dtrace_module *pdata; -+ -+ pdata = kmem_cache_alloc(dtrace_pdata_cachep, GFP_KERNEL | __GFP_ZERO); -+ if (pdata == NULL) { -+ mp->pdata = NULL; -+ return; -+ } -+ -+ dtrace_mod_pdata_init(pdata); -+ mp->pdata = pdata; -+} -+ -+void dtrace_mod_pdata_free(struct module *mp) -+{ -+ struct dtrace_module *pdata = mp->pdata; -+ -+ if (mp->pdata == NULL) -+ return; -+ -+ mp->pdata = NULL; -+ dtrace_mod_pdata_cleanup(pdata); -+ kmem_cache_free(dtrace_pdata_cachep, pdata); -+} -+ -+/* -+ * This function is called with module_mutex held. -+ */ -+int dtrace_destroy_prov(struct module *mp) -+{ -+ struct dtrace_module *pdata = mp->pdata; -+ -+ if (pdata != NULL && pdata->prov_exit != NULL) -+ return pdata->prov_exit(); -+ -+ return 1; -+} -+ -+/*---------------------------------------------------------------------------*\ -+(* TIME SUPPORT FUNCTIONS *) -+\*---------------------------------------------------------------------------*/ -+enum dtrace_vtime_state dtrace_vtime_active = 0; -+ -+/* -+ * Until Linux kernel gains lock-free realtime clock access we are maintaining -+ * our own version for lock-free access from within a probe context. -+ */ -+static struct dtrace_time_fast { -+ seqcount_latch_t dtwf_seq; -+ ktime_t dtwf_offsreal[2]; -+} dtrace_time ____cacheline_aligned; -+ -+/* -+ * Callback from timekeeper code that allows dtrace to update its own time data. -+ */ -+void dtrace_update_time(struct timekeeper *tk) -+{ -+ raw_write_seqcount_latch(&dtrace_time.dtwf_seq); -+ dtrace_time.dtwf_offsreal[0] = tk->offs_real; -+ raw_write_seqcount_latch(&dtrace_time.dtwf_seq); -+ dtrace_time.dtwf_offsreal[1] = tk->offs_real; -+} -+ -+/* Lock free walltime */ -+ktime_t dtrace_get_walltime(void) -+{ -+ u64 nsec = ktime_get_mono_fast_ns(); -+ unsigned int seq; -+ ktime_t offset; -+ -+ do { -+ seq = raw_read_seqcount_latch(&dtrace_time.dtwf_seq); -+ offset = dtrace_time.dtwf_offsreal[seq & 0x1]; -+ } while (read_seqcount_latch_retry(&dtrace_time.dtwf_seq, seq)); -+ -+ return ktime_add_ns(offset, nsec); -+} -+EXPORT_SYMBOL(dtrace_get_walltime); -+ -+ktime_t dtrace_gethrtime(void) -+{ -+ return ns_to_ktime(ktime_get_raw_fast_ns()); -+} -+EXPORT_SYMBOL(dtrace_gethrtime); -+ -+/* Needed for lockstat probes where we cannot include ktime.h */ -+u64 dtrace_gethrtime_ns(void) -+{ -+ return ktime_get_raw_fast_ns(); -+} -+EXPORT_SYMBOL(dtrace_gethrtime_ns); -+ -+void dtrace_vtime_enable(void) -+{ -+ enum dtrace_vtime_state old, new; -+ -+ do { -+ old = dtrace_vtime_active; -+ if (old == DTRACE_VTIME_ACTIVE) { -+ pr_warn_once("DTrace virtual time already enabled"); -+ return; -+ } -+ -+ new = DTRACE_VTIME_ACTIVE; -+ } while (cmpxchg(&dtrace_vtime_active, old, new) != old); -+} -+EXPORT_SYMBOL(dtrace_vtime_enable); -+ -+void dtrace_vtime_disable(void) -+{ -+ int old, new; -+ -+ do { -+ old = dtrace_vtime_active; -+ if (old == DTRACE_VTIME_INACTIVE) { -+ pr_warn_once("DTrace virtual time already disabled"); -+ return; -+ } -+ -+ new = DTRACE_VTIME_INACTIVE; -+ } while (cmpxchg(&dtrace_vtime_active, old, new) != old); -+} -+EXPORT_SYMBOL(dtrace_vtime_disable); -+ -+void dtrace_vtime_switch(struct task_struct *prev, struct task_struct *next) -+{ -+ struct dtrace_task *dprev = prev->dt_task; -+ struct dtrace_task *dnext = next->dt_task; -+ ktime_t now = dtrace_gethrtime(); -+ -+ if (dprev != NULL && ktime_nz(dprev->dt_start)) { -+ dprev->dt_vtime = ktime_add(dprev->dt_vtime, -+ ktime_sub(now, -+ dprev->dt_start)); -+ dprev->dt_start = ktime_set(0, 0); -+ } -+ -+ if (dnext != NULL) -+ dnext->dt_start = now; -+} -+ -+void dtrace_stacktrace(struct stacktrace_state *st) -+{ -+ int i; -+ -+ if ((st->flags & STACKTRACE_TYPE) == STACKTRACE_USER) { -+ dtrace_user_stacktrace(st); -+ return; -+ } -+ -+ if (st->pcs == NULL) { -+ st->depth = 0; -+ return; -+ } -+ -+ st->depth = stack_trace_save((long unsigned int *) st->pcs, -+ st->limit ? st->limit : 512, st->depth); -+ -+ /* -+ * For entirely unknown reasons, the save_stack_trace() implementation -+ * on x86_64 adds a ULONG_MAX entry after the last stack trace entry. -+ * This might be a sentinel value, but given that struct stack_trace -+ * already contains a nr_entries counter, this seems rather pointless. -+ * Alas, we need to add a special case for that... And to make matters -+ * worse, it actually does this only when there is room for it (i.e. -+ * when nr_entries < max_entries). -+ * Since ULONG_MAX is never a valid PC, we can just check for that. -+ */ -+#if defined(CONFIG_X86_64) || defined(CONFIG_ARM64) -+ if (st->depth && st->pcs[st->depth - 1] == ULONG_MAX) -+ st->depth--; -+#endif -+ -+ if (st->fps != NULL) { -+ for (i = 0; i < st->limit; i++) -+ st->fps[i] = 0; -+ } -+} -+EXPORT_SYMBOL(dtrace_stacktrace); -+ -+/* -+ * INVALID OPCODE AND PAGE FAULT HANDLING -+ */ -+static struct notifier_block dtrace_die = { -+ .notifier_call = dtrace_die_notifier, -+ .priority = 0x7fffffff -+}; -+ -+static int dtrace_enabled; -+ -+/* -+ * DTrace enable/disable must be called with dtrace_lock being held. It is not -+ * possible to check for safety here with an ASSERT as the lock itself is in the -+ * DTrace Framework kernel module. -+ */ -+int dtrace_enable(void) -+{ -+ if (dtrace_enabled) -+ return 0; -+ -+ if (register_die_notifier(&dtrace_die) != 0) -+ return 1; -+ -+ dtrace_enabled = 1; -+ return 0; -+} -+EXPORT_SYMBOL(dtrace_enable); -+ -+void dtrace_disable(void) -+{ -+ if (!dtrace_enabled) -+ return; -+ -+ unregister_die_notifier(&dtrace_die); -+ dtrace_enabled = 0; -+} -+EXPORT_SYMBOL(dtrace_disable); -diff --git a/kernel/dtrace/dtrace_psinfo.c b/kernel/dtrace/dtrace_psinfo.c -new file mode 100644 -index 000000000000..bb5f6fc2ce63 ---- /dev/null -+++ b/kernel/dtrace/dtrace_psinfo.c -@@ -0,0 +1,212 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_psinfo.c -+ * DESCRIPTION: DTrace - DTrace psinfo implementation -+ * -+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/binfmts.h> -+#include <linux/dtrace_psinfo.h> -+#include <linux/dtrace_task_impl.h> -+#include <linux/mm.h> -+#include <linux/sched.h> -+#include <linux/sched/mm.h> -+#include <linux/slab.h> -+#include <linux/uaccess.h> -+ -+struct kmem_cache *dtrace_psinfo_cachep; -+ -+/* -+ * Free the psinfo_t structure. -+ */ -+void dtrace_psinfo_free(struct dtrace_psinfo *psinfo) -+{ -+ kfree(psinfo->dtps_argv); -+ kfree(psinfo->dtps_envp); -+ kmem_cache_free(dtrace_psinfo_cachep, psinfo); -+} -+ -+/* -+ * Allocate a new dtrace_psinfo_t structure. -+ */ -+void dtrace_psinfo_alloc(struct task_struct *tsk) -+{ -+ struct dtrace_psinfo *psinfo; -+ struct mm_struct *mm = NULL; -+ -+ if (unlikely(tsk->dt_task == NULL)) -+ return; -+ -+ if (likely(tsk->dt_task->dt_psinfo != NULL)) { -+ struct dtrace_psinfo *tmp = tsk->dt_task->dt_psinfo; -+ tsk->dt_task->dt_psinfo = NULL; -+ -+ dtrace_psinfo_put(tmp); -+ } -+ -+ psinfo = kmem_cache_alloc(dtrace_psinfo_cachep, GFP_KERNEL); -+ if (psinfo == NULL) -+ goto fail; -+ -+ mm = get_task_mm(tsk); -+ if (mm) { -+ size_t len = mm->arg_end - mm->arg_start; -+ int i = 0; -+ char *p; -+ -+ /* -+ * Construct the psargs string. -+ */ -+ if (len > 0) { -+ if (len >= PR_PSARGS_SZ) -+ len = PR_PSARGS_SZ - 1; -+ -+ i = access_process_vm(tsk, mm->arg_start, -+ psinfo->dtps_psargs, len, 0); -+ -+ if (i > 0) { -+ if (i < len) -+ len = i; -+ -+ for (i = 0, --len; i < len; i++) { -+ if (psinfo->dtps_psargs[i] == '\0') -+ psinfo->dtps_psargs[i] = ' '; -+ } -+ } -+ } -+ -+ if (i < 0) -+ i = 0; -+ -+ while (i < PR_PSARGS_SZ) -+ psinfo->dtps_psargs[i++] = 0; -+ -+ /* -+ * Determine the number of arguments. -+ */ -+ psinfo->dtps_argc = 0; -+ for (p = (char *)mm->arg_start; p < (char *)mm->arg_end; -+ psinfo->dtps_argc++) { -+ size_t l = strnlen_user(p, MAX_ARG_STRLEN); -+ -+ if (!l) -+ break; -+ -+ p += l + 1; -+ } -+ -+ /* -+ * Limit the number of stored argument pointers. -+ */ -+ len = psinfo->dtps_argc; -+ if (len >= PR_ARGV_SZ) -+ len = PR_ARGV_SZ - 1; -+ -+ psinfo->dtps_argv = kmalloc((len + 1) * sizeof(char *), -+ GFP_KERNEL); -+ if (psinfo->dtps_argv == NULL) -+ goto fail; -+ -+ /* -+ * Now populate the array of argument strings. -+ */ -+ for (i = 0, p = (char *)mm->arg_start; i < len; i++) { -+ psinfo->dtps_argv[i] = p; -+ p += strnlen_user(p, MAX_ARG_STRLEN) + 1; -+ } -+ psinfo->dtps_argv[len] = NULL; -+ -+ /* -+ * Determine the number of environment variables. -+ */ -+ psinfo->dtps_envc = 0; -+ for (p = (char *)mm->env_start; p < (char *)mm->env_end; -+ psinfo->dtps_envc++) { -+ size_t l = strnlen_user(p, MAX_ARG_STRLEN); -+ -+ if (!l) -+ break; -+ -+ p += l + 1; -+ } -+ -+ /* -+ * Limit the number of stored environment pointers. -+ */ -+ len = psinfo->dtps_envc; -+ if (len >= PR_ENVP_SZ) -+ len = PR_ENVP_SZ - 1; -+ -+ psinfo->dtps_envp = kmalloc((len + 1) * sizeof(char *), -+ GFP_KERNEL); -+ if (psinfo->dtps_envp == NULL) -+ goto fail; -+ -+ /* -+ * Now populate the array of environment variable strings. -+ */ -+ for (i = 0, p = (char *)mm->env_start; i < len; i++) { -+ psinfo->dtps_envp[i] = p; -+ p += strnlen_user(p, MAX_ARG_STRLEN) + 1; -+ } -+ psinfo->dtps_envp[len] = NULL; -+ -+ mmput(mm); -+ } else { -+ size_t len = min(TASK_COMM_LEN, PR_PSARGS_SZ); -+ int i; -+ -+ /* -+ * We end up here for tasks that do not have managed memory at -+ * all, which generally means that this is a kernel thread. -+ * If it is not, this is still safe because we know that tasks -+ * always have the comm member populated with something (even -+ * if it would be an empty string). -+ */ -+ memcpy(psinfo->dtps_psargs, tsk->comm, len); -+ for (i = len; i < PR_PSARGS_SZ; i++) -+ psinfo->dtps_psargs[i] = 0; -+ -+ psinfo->dtps_argc = 0; -+ psinfo->dtps_argv = kmalloc(sizeof(char *), GFP_KERNEL); -+ psinfo->dtps_argv[0] = NULL; -+ psinfo->dtps_envc = 0; -+ psinfo->dtps_envp = kmalloc(sizeof(char *), GFP_KERNEL); -+ psinfo->dtps_envp[0] = NULL; -+ } -+ -+ atomic_set(&psinfo->dtps_usage, 1); -+ tsk->dt_task->dt_psinfo = psinfo; /* new one */ -+ -+ return; -+ -+fail: -+ if (mm) -+ mmput(mm); -+ -+ if (psinfo) -+ dtrace_psinfo_free(psinfo); -+} -+ -+/* -+ * Initialize DTrace's psinfo subsystem. -+ */ -+void __init dtrace_psinfo_os_init(void) -+{ -+ dtrace_psinfo_cachep = kmem_cache_create("dtrace_psinfo_cache", -+ sizeof(struct dtrace_psinfo), 0, -+ SLAB_HWCACHE_ALIGN | SLAB_PANIC, -+ NULL); -+ -+} -diff --git a/kernel/dtrace/dtrace_task.c b/kernel/dtrace/dtrace_task.c -new file mode 100644 -index 000000000000..02bcc6b7e0a2 ---- /dev/null -+++ b/kernel/dtrace/dtrace_task.c -@@ -0,0 +1,237 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_task.c -+ * DESCRIPTION: DTrace - per-task data -+ * -+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/dtrace_task_impl.h> -+#include <linux/sched/mm.h> -+#include <linux/slab.h> -+ -+struct kmem_cache *dtrace_task_cachep; -+ -+void (*dtrace_helpers_fork)(struct task_struct *, struct task_struct *); -+EXPORT_SYMBOL(dtrace_helpers_fork); -+ -+/* -+ * Reset per-task sate to default values. Modifies only part of -+ * the state that does not persist across process forks. -+ */ -+static void dtrace_task_reinit(struct dtrace_task *dtsk) -+{ -+ dtsk->dt_predcache = 0; -+ dtsk->dt_stop = 0; -+ dtsk->dt_sig = 0; -+ -+ dtsk->dt_helpers = NULL; -+ dtsk->dt_probes = 0; -+ dtsk->dt_tp_count = 0; -+} -+ -+/* -+ * Allocate new per-task structure and initialize it with default -+ * values. -+ */ -+static struct dtrace_task *dtrace_task_alloc(void) -+{ -+ struct dtrace_task *dtsk; -+ -+ /* Try to allocate new task. */ -+ dtsk = kmem_cache_alloc(dtrace_task_cachep, GFP_KERNEL); -+ if (dtsk == NULL) -+ return NULL; -+ -+ /* Initialize new task. */ -+ dtrace_task_reinit(dtsk); -+ -+ dtsk->dt_vtime = ktime_set(0, 0); -+ dtsk->dt_start = ktime_set(0, 0); -+ dtsk->dt_psinfo = NULL; -+ dtsk->dt_ustack = NULL; -+ -+ return dtsk; -+} -+ -+/* -+ * Cleans all attached resources to the per-task structure so it is ready to be -+ * reused or freed. -+ */ -+static void dtrace_task_cleanup(struct task_struct *tsk) -+{ -+ struct dtrace_psinfo *psinfo; -+ -+ /* Nothing to remove. */ -+ if (tsk->dt_task == NULL) -+ return; -+ -+ /* Release psinfo if any. */ -+ psinfo = tsk->dt_task->dt_psinfo; -+ if (psinfo != NULL) { -+ tsk->dt_task->dt_psinfo = NULL; -+ dtrace_psinfo_put(psinfo); -+ } -+} -+ -+/* -+ * Kernel hooks for per-task events. -+ */ -+ -+/* -+ * Called when a new task has been created. -+ * -+ * It tries to allocate new per-task data strcture and initialize -+ * it with default values. -+ */ -+void dtrace_task_init(struct task_struct *tsk) -+{ -+ struct mm_struct *mm = NULL; -+ -+ /* Initialize new task structure */ -+ tsk->dt_task = dtrace_task_alloc(); -+ if (tsk->dt_task == NULL) -+ return; -+ -+ /* Try to setup initial userspace stack. */ -+ mm = get_task_mm(tsk); -+ if (mm) { -+ tsk->dt_task->dt_ustack = (void *)mm->start_stack; -+ mmput(mm); -+ } -+} -+ -+/* -+ * Called when a task has been duplicated. -+ * -+ * When a task is duplicated this is called early to provide new instance -+ * of per-task data. This hook is called very early after a dup has been -+ * performed. The new task shares almost everything with its parent and -+ * locking performed must be aligned with locking of the kernel. -+ * -+ * DTrace resets new task to its default values. -+ */ -+void dtrace_task_dup(struct task_struct *src, struct task_struct *dst) -+{ -+ struct dtrace_psinfo *psinfo; -+ struct dtrace_task *dtsk; -+ -+ /* Nothing to clone. */ -+ if (src->dt_task == NULL) -+ return; -+ -+ /* Allocate and reinitialize new task. */ -+ dtsk = dtrace_task_alloc(); -+ if (dtsk == NULL) { -+ dst->dt_task = NULL; -+ return; -+ } -+ dtrace_task_reinit(dtsk); -+ -+ /* Share psinfo if it is available. */ -+ psinfo = src->dt_task->dt_psinfo; -+ if (psinfo != NULL) { -+ dtrace_psinfo_get(psinfo); -+ dtsk->dt_psinfo = psinfo; -+ } -+ -+ /* Copy remaining attributes of the source task. */ -+ dtsk->dt_ustack = src->dt_task->dt_ustack; -+ dst->dt_task = dtsk; -+} -+ -+/* -+ * Called when a process has been copied. -+ * -+ * If the original task has helpers attached fork them too. -+ */ -+void dtrace_task_copy(struct task_struct *tsk, struct task_struct *child) -+{ -+ if (tsk->dt_task == NULL) -+ return; -+ -+ if (child->dt_task == NULL) -+ return; -+ -+ /* Handle helpers for this task. */ -+ if (likely(dtrace_helpers_fork == NULL)) -+ return; -+ -+ if (tsk->dt_task->dt_helpers != NULL) -+ (*dtrace_helpers_fork)(tsk, child); -+} -+ -+/* -+ * Called when a task has performed exec. -+ * -+ * If DTrace's per-task structure is already allocated it is reused for -+ * the new task. If it is not present an allocation attempt is made. -+ */ -+void dtrace_task_exec(struct task_struct *tsk) -+{ -+ struct mm_struct *mm = NULL; -+ -+ /* Try to reuse existing dtrace task. */ -+ if (tsk->dt_task != NULL) { -+ dtrace_task_cleanup(tsk); -+ dtrace_task_reinit(tsk->dt_task); -+ -+ /* Try to set up initial userspace stack. */ -+ mm = get_task_mm(tsk); -+ if (mm) { -+ tsk->dt_task->dt_ustack = (void *)mm->start_stack; -+ mmput(mm); -+ } -+ } else { -+ dtrace_task_init(tsk); -+ -+ /* No luck, we won't be able to trace this task. */ -+ if (tsk->dt_task == NULL) -+ return; -+ } -+ -+ /* Finalize init of the per-task structure. */ -+ dtrace_psinfo_alloc(tsk); -+} -+ -+/* -+ * Called when a task is about to be released. -+ * -+ * The DTrace's per-task data are disconnected and freed. -+ */ -+void dtrace_task_free(struct task_struct *tsk) -+{ -+ struct dtrace_task *dtsk = tsk->dt_task; -+ -+ /* Nothing to do. */ -+ if (dtsk == NULL) -+ return; -+ -+ /* Release the per-task data. */ -+ dtrace_task_cleanup(tsk); -+ tsk->dt_task = NULL; -+ kmem_cache_free(dtrace_task_cachep, dtsk); -+} -+ -+/* -+ * Initialize DTrace's task subsystem. -+ */ -+void __init dtrace_task_os_init(void) -+{ -+ /* Will panic if not initialized so no need to check for errors. */ -+ dtrace_task_cachep = kmem_cache_create("dtrace_task_cache", -+ sizeof(struct dtrace_task), 0, -+ SLAB_HWCACHE_ALIGN | SLAB_PANIC, -+ NULL); -+} -+ -diff --git a/kernel/exit.c b/kernel/exit.c -index 5c5859a9ba75..da498c5f029c 100644 ---- a/kernel/exit.c -+++ b/kernel/exit.c -@@ -64,6 +64,7 @@ - #include <linux/rcuwait.h> - #include <linux/compat.h> - #include <linux/io_uring.h> -+#include <linux/dtrace_os.h> - - #include <linux/uaccess.h> - #include <asm/unistd.h> -@@ -795,6 +796,9 @@ void __noreturn do_exit(long code) - tsk->exit_code = code; - taskstats_exit(tsk, group_dead); - -+ /* Remove DTrace state for this task */ -+ dtrace_task_free(tsk); -+ - exit_mm(); - - if (group_dead) -diff --git a/kernel/fork.c b/kernel/fork.c -index c675fdbd3dce..0d8a2b12fd90 100644 ---- a/kernel/fork.c -+++ b/kernel/fork.c -@@ -96,6 +96,7 @@ - #include <linux/kasan.h> - #include <linux/scs.h> - #include <linux/io_uring.h> -+#include <linux/dtrace_task_impl.h> - - #include <asm/pgalloc.h> - #include <linux/uaccess.h> -@@ -442,6 +443,7 @@ void put_task_stack(struct task_struct *tsk) - void free_task(struct task_struct *tsk) - { - scs_release(tsk); -+ dtrace_task_free(tsk); - - #ifndef CONFIG_THREAD_INFO_IN_TASK - /* -@@ -943,6 +945,8 @@ static struct task_struct *dup_task_struct(struct task_struct *orig, int node) - #ifdef CONFIG_MEMCG - tsk->active_memcg = NULL; - #endif -+ -+ dtrace_task_dup(orig, tsk); - return tsk; - - free_stack: -@@ -2300,6 +2304,25 @@ static __latent_entropy struct task_struct *copy_process( - syscall_tracepoint_update(p); - write_unlock_irq(&tasklist_lock); - -+#ifdef CONFIG_DTRACE -+ /* -+ * We make this call fairly late into the copy_process() handling, -+ * because we need to ensure that we can look up this task based on -+ * its pid using find_task_by_vpid(). We also must ensure that the -+ * tasklist_lock has been released. -+ */ -+ dtrace_task_copy(current, p); -+ -+ /* -+ * If we're called with stack_start != 0, this is almost certainly a -+ * thread being created in current. Make sure it gets its own psinfo -+ * data, because we need to record a new bottom of stack value. -+ */ -+ if (p->mm && args->stack) -+ if (p->dt_task != NULL) -+ p->dt_task->dt_ustack = (void *)args->stack; -+#endif -+ - proc_fork_connector(p); - sched_post_fork(p); - cgroup_post_fork(p, args); -diff --git a/kernel/module.c b/kernel/module.c -index 9e471dbedc83..f4269dabc638 100644 ---- a/kernel/module.c -+++ b/kernel/module.c -@@ -46,6 +46,7 @@ - #include <asm/mmu_context.h> - #include <linux/license.h> - #include <asm/sections.h> -+#include <linux/dtrace_os.h> - #include <linux/tracepoint.h> - #include <linux/ftrace.h> - #include <linux/livepatch.h> -@@ -90,6 +91,9 @@ - DEFINE_MUTEX(module_mutex); - EXPORT_SYMBOL_GPL(module_mutex); - static LIST_HEAD(modules); -+#ifdef CONFIG_DTRACE -+struct list_head *dtrace_modules = &modules; -+#endif /* CONFIG_DTRACE */ - - /* Work queue for freeing init sections in success case */ - static void do_free_init(struct work_struct *w); -@@ -1023,6 +1027,12 @@ SYSCALL_DEFINE2(delete_module, const char __user *, name_user, - } - } - -+ /* Try destroying DTrace provider. */ -+ if (!dtrace_destroy_prov(mod)) { -+ ret = -EBUSY; -+ goto out; -+ } -+ - /* Stop the machine so refcounts can't move and disable module. */ - ret = try_stop_module(mod, flags, &forced); - if (ret != 0) -@@ -2212,6 +2222,7 @@ void __weak module_arch_freeing_init(struct module *mod) - /* Free a module, remove from lists, etc. */ - static void free_module(struct module *mod) - { -+ dtrace_mod_pdata_free(mod); - trace_module_free(mod); - - mod_sysfs_teardown(mod); -@@ -3943,6 +3954,9 @@ static int load_module(struct load_info *info, const char __user *uargs, - /* Ftrace init must be called in the MODULE_STATE_UNFORMED state */ - ftrace_module_init(mod); - -+ /* Allocate DTrace per-module data. */ -+ dtrace_mod_pdata_alloc(mod); -+ - /* Finally it's fully formed, ready to start executing. */ - err = complete_formation(mod, info); - if (err) -diff --git a/kernel/sched/core.c b/kernel/sched/core.c -index 77aa0e788b9b..db893818f3ea 100644 ---- a/kernel/sched/core.c -+++ b/kernel/sched/core.c -@@ -13,6 +13,7 @@ - #include "sched.h" - - #include <linux/nospec.h> -+#include <linux/dtrace_os.h> - - #include <linux/kcov.h> - #include <linux/scs.h> -@@ -3600,6 +3601,11 @@ static struct rq *finish_task_switch(struct task_struct *prev) - - rq->prev_mm = NULL; - -+#ifdef CONFIG_DTRACE -+ if (dtrace_vtime_active) -+ dtrace_vtime_switch(prev, current); -+#endif -+ - /* - * A task struct has one reference for the use as "current". - * If a task dies, then it sets TASK_DEAD in tsk->state and calls -@@ -7195,6 +7201,10 @@ void __init sched_init(void) - #endif /* CONFIG_SMP */ - hrtick_rq_init(rq); - atomic_set(&rq->nr_iowait, 0); -+ -+#ifdef CONFIG_DTRACE -+ rq->dtrace_cpu_info = per_cpu_info(i); -+#endif - } - - set_load_weight(&init_task, false); -diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h -index c122176c627e..f917e368e4f8 100644 ---- a/kernel/sched/sched.h -+++ b/kernel/sched/sched.h -@@ -345,6 +345,7 @@ extern bool dl_cpu_busy(unsigned int cpu); - #ifdef CONFIG_CGROUP_SCHED - - #include <linux/cgroup.h> -+#include <linux/dtrace_cpu.h> - #include <linux/psi.h> - - struct cfs_rq; -@@ -1042,6 +1043,9 @@ struct rq { - /* Must be inspected within a rcu lock section */ - struct cpuidle_state *idle_state; - #endif -+#ifdef CONFIG_DTRACE -+ struct cpuinfo *dtrace_cpu_info; -+#endif - }; - - #ifdef CONFIG_FAIR_GROUP_SCHED -diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c -index 6858a31364b6..b74807546fba 100644 ---- a/kernel/time/timekeeping.c -+++ b/kernel/time/timekeeping.c -@@ -22,6 +22,7 @@ - #include <linux/pvclock_gtod.h> - #include <linux/compiler.h> - #include <linux/audit.h> -+#include <linux/dtrace_os.h> - - #include "tick-internal.h" - #include "ntp_internal.h" -@@ -743,6 +744,7 @@ static void timekeeping_update(struct timekeeper *tk, unsigned int action) - tk_update_ktime_data(tk); - - update_vsyscall(tk); -+ dtrace_update_time(tk); - update_pvclock_gtod(tk, action & TK_CLOCK_WAS_SET); - - tk->tkr_mono.base_real = tk->tkr_mono.base + tk->offs_real; -diff --git a/scripts/coccinelle/dtrace/enum-elision.cocci b/scripts/coccinelle/dtrace/enum-elision.cocci -new file mode 100644 -index 000000000000..77a5b33bd166 ---- /dev/null -+++ b/scripts/coccinelle/dtrace/enum-elision.cocci -@@ -0,0 +1,29 @@ -+/// Reduce uses of typedefs of named enums to the name of the enum -+ -+virtual patch -+virtual context -+virtual org -+virtual report -+ -+@td@ -+type T; -+identifier E; -+@@ -+- typedef enum E -++ enum E -+ { ... -+- } T; -++ }; -+@@ -+type td.T; -+identifier td.E; -+@@ -+- T -++ enum E -+ -+@@ -+type td.T; -+identifier td.E; -+@@ -+- const T -++ const enum E -diff --git a/scripts/coccinelle/dtrace/typedef-elision.cocci b/scripts/coccinelle/dtrace/typedef-elision.cocci -new file mode 100644 -index 000000000000..bc4caf375b60 ---- /dev/null -+++ b/scripts/coccinelle/dtrace/typedef-elision.cocci -@@ -0,0 +1,83 @@ -+/// Reduce uses of typedefs of named structures to the name of the structure -+ -+virtual patch -+virtual context -+virtual org -+virtual report -+ -+@td@ -+type T; -+identifier S; -+@@ -+( -+- typedef struct S -++ struct S -+ { ... -+- } T; -++ }; -+| -+ struct S; -+- typedef struct S T; -+) -+@@ -+type td.T; -+identifier td.S; -+@@ -+- T -++ struct S -+ -+@@ -+type td.T; -+identifier td.S; -+@@ -+- const T -++ const struct S -+ -+/// Now structures declared with typedefs of opaque structs, one by one -+@@ -+typedef dtrace_ecb_t; -+@@ -+- dtrace_ecb_t -++ struct dtrace_ecb -+ -+@@ -+typedef dtrace_actdesc_t; -+@@ -+- dtrace_actdesc_t -++ struct dtrace_actdesc -+ -+@@ -+typedef dtrace_state_t; -+@@ -+- dtrace_state_t -++ struct dtrace_state -+ -+@@ -+typedef dtrace_vstate_t; -+@@ -+- dtrace_vstate_t -++ struct dtrace_vstate -+ -+@@ -+typedef dtrace_mstate_t; -+@@ -+- dtrace_mstate_t -++ struct dtrace_mstate -+ -+@@ -+typedef dtrace_task_t; -+@@ -+- dtrace_task_t -++ struct dtrace_task -+ -+@@ -+typedef dtrace_psinfo_t; -+@@ -+- dtrace_psinfo_t -++ struct dtrace_psinfo -+ -+@@ -+typedef dt_fbt_bl_entry_t; -+@@ -+- dt_fbt_bl_entry_t -++ struct dt_fbt_bl_entry -diff --git a/scripts/package/mkspec b/scripts/package/mkspec -index e9ff22c6fb4c..cba5be72adb9 100755 ---- a/scripts/package/mkspec -+++ b/scripts/package/mkspec -@@ -150,6 +150,7 @@ $M %exclude /lib/modules/$KERNELRELEASE/source - %files headers - %defattr (-, root, root) - /usr/include -+ %exclude /usr/include/linux/dtrace - $S$M - $S$M %files devel - $S$M %defattr (-, root, root) --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/dtrace-patches/0005-dtrace-modular-components-and-x86-support.patch b/sys-kernel/cairn-sources/files/5.10.13/dtrace-patches/0005-dtrace-modular-components-and-x86-support.patch deleted file mode 100644 index 9513abc33965..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/dtrace-patches/0005-dtrace-modular-components-and-x86-support.patch +++ /dev/null @@ -1,18392 +0,0 @@ -From 4b3eec83a54c9bd853648e4b256fb28a078a36aa Mon Sep 17 00:00:00 2001 -From: Kris Van Hees <kris.van.hees@oracle.com> -Date: Mon, 19 Nov 2018 17:52:54 +0000 -Subject: [PATCH 05/19] dtrace: modular components and x86 support - -This implements the core DTrace module (including the entire DIF -interpreter and support for all built-in D variables and functions) and -one test provider, dt_test.ko. It uses the machinery added in the last -few commits. An x86 implementation of the architecture-dependent parts -is also added so that one platform at least can compile it. - -At this stage, almost no probes will exist: they are added by the -following commits, that add providers and SDT probes. - -Signed-off-by: Kris Van Hees <kris.van.hees@oracle.com> -Signed-off-by: Nick Alcock <nick.alcock@oracle.com> -Signed-off-by: Tomas Jedlicka <tomas.jedlicka@oracle.com> -Signed-off-by: Eugene Loh <eugene.loh@oracle.com> -Signed-off-by: David Mc Lean <david.mclean@oracle.com> -Signed-off-by: Vincent Lim <vincent.lim@oracle.com> ---- - Makefile | 1 + - arch/x86/dtrace/Makefile.arch | 11 + - arch/x86/dtrace/dtrace_asm_x86_64.S | 228 ++ - arch/x86/dtrace/dtrace_isa_x86_64.c | 228 ++ - dtrace/Makefile | 19 + - dtrace/ctf_api.h | 33 + - dtrace/dt_test.h | 30 + - dtrace/dt_test_dev.c | 176 + - dtrace/dt_test_mod.c | 52 + - dtrace/dtrace.h | 35 + - dtrace/dtrace_actdesc.c | 91 + - dtrace/dtrace_anon.c | 144 + - dtrace/dtrace_buffer.c | 490 +++ - dtrace/dtrace_debug.h | 118 + - dtrace/dtrace_dev.c | 1599 +++++++++ - dtrace/dtrace_dev.h | 35 + - dtrace/dtrace_dif.c | 4905 +++++++++++++++++++++++++++ - dtrace/dtrace_dof.c | 2504 ++++++++++++++ - dtrace/dtrace_ecb.c | 936 +++++ - dtrace/dtrace_enable.c | 449 +++ - dtrace/dtrace_fmt.c | 104 + - dtrace/dtrace_hash.c | 266 ++ - dtrace/dtrace_isa.c | 361 ++ - dtrace/dtrace_match.c | 364 ++ - dtrace/dtrace_mod.c | 45 + - dtrace/dtrace_predicate.c | 80 + - dtrace/dtrace_priv.c | 120 + - dtrace/dtrace_probe.c | 1542 +++++++++ - dtrace/dtrace_probe_ctx.c | 659 ++++ - dtrace/dtrace_ptofapi.c | 649 ++++ - dtrace/dtrace_spec.c | 434 +++ - dtrace/dtrace_state.c | 1108 ++++++ - dtrace/dtrace_util.c | 282 ++ - 33 files changed, 18098 insertions(+) - create mode 100644 arch/x86/dtrace/Makefile.arch - create mode 100644 arch/x86/dtrace/dtrace_asm_x86_64.S - create mode 100644 arch/x86/dtrace/dtrace_isa_x86_64.c - create mode 100644 dtrace/Makefile - create mode 100644 dtrace/ctf_api.h - create mode 100644 dtrace/dt_test.h - create mode 100644 dtrace/dt_test_dev.c - create mode 100644 dtrace/dt_test_mod.c - create mode 100644 dtrace/dtrace.h - create mode 100644 dtrace/dtrace_actdesc.c - create mode 100644 dtrace/dtrace_anon.c - create mode 100644 dtrace/dtrace_buffer.c - create mode 100644 dtrace/dtrace_debug.h - create mode 100644 dtrace/dtrace_dev.c - create mode 100644 dtrace/dtrace_dev.h - create mode 100644 dtrace/dtrace_dif.c - create mode 100644 dtrace/dtrace_dof.c - create mode 100644 dtrace/dtrace_ecb.c - create mode 100644 dtrace/dtrace_enable.c - create mode 100644 dtrace/dtrace_fmt.c - create mode 100644 dtrace/dtrace_hash.c - create mode 100644 dtrace/dtrace_isa.c - create mode 100644 dtrace/dtrace_match.c - create mode 100644 dtrace/dtrace_mod.c - create mode 100644 dtrace/dtrace_predicate.c - create mode 100644 dtrace/dtrace_priv.c - create mode 100644 dtrace/dtrace_probe.c - create mode 100644 dtrace/dtrace_probe_ctx.c - create mode 100644 dtrace/dtrace_ptofapi.c - create mode 100644 dtrace/dtrace_spec.c - create mode 100644 dtrace/dtrace_state.c - create mode 100644 dtrace/dtrace_util.c - -diff --git a/Makefile b/Makefile -index fb9393fa10f0..4b25be692ac1 100644 ---- a/Makefile -+++ b/Makefile -@@ -651,6 +651,7 @@ drivers-y := drivers/ sound/ - drivers-$(CONFIG_SAMPLES) += samples/ - drivers-y += net/ virt/ - libs-y := lib/ -+dtrace-y := dtrace/ - endif # KBUILD_EXTMOD - - # The all: target is the default when no target is given on the -diff --git a/arch/x86/dtrace/Makefile.arch b/arch/x86/dtrace/Makefile.arch -new file mode 100644 -index 000000000000..ffb9ef4d1722 ---- /dev/null -+++ b/arch/x86/dtrace/Makefile.arch -@@ -0,0 +1,11 @@ -+# -+# Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. -+# -+ -+DTARCHDIR = ../arch/x86/dtrace -+ -+ccflags-y += -I$(srctree)/arch/x86/dtrace/include -Idtrace -+ -+dtrace-obj += dtrace_asm_x86_64.o dtrace_isa_x86_64.o -+ -+dtrace-y += $(addprefix $(DTARCHDIR)/, $(dtrace-obj)) -diff --git a/arch/x86/dtrace/dtrace_asm_x86_64.S b/arch/x86/dtrace/dtrace_asm_x86_64.S -new file mode 100644 -index 000000000000..46d3fe1b9703 ---- /dev/null -+++ b/arch/x86/dtrace/dtrace_asm_x86_64.S -@@ -0,0 +1,228 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Dynamic Tracing for Linux - x86 specific assembly -+ * -+ * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/linkage.h> -+#include <asm/smap.h> -+ -+#define CPU_DTRACE_BADADDR 0x0004 /* DTrace fault: bad address */ -+ -+#if defined(__x86_64__) -+ SYM_CODE_START(dtrace_caller) -+ movq $-1, %rax -+ ret -+ SYM_CODE_END(dtrace_caller) -+ -+#elif defined(__i386__) -+ -+ SYM_CODE_START(dtrace_caller) -+ movl $-1, %eax -+ ret -+ SYM_CODE_END(dtrace_caller) -+ -+#endif /* __i386__ */ -+ -+#if defined(__x86_64__) -+ -+ SYM_FUNC_START(dtrace_copy) -+ pushq %rbp -+ movq %rsp, %rbp -+ -+ ASM_STAC -+ xchgq %rdi, %rsi # make %rsi source, %rdi dest -+ movq %rdx, %rcx # load count -+ repz # repeat for count ... -+ smovb # move from %ds:rsi to %ed:rdi -+ ASM_CLAC -+ leave -+ ret -+ SYM_FUNC_END(dtrace_copy) -+ -+#elif defined(__i386__) -+ -+ SYM_FUNC_START(dtrace_copy) -+ pushl %ebp -+ movl %esp, %ebp -+ pushl %esi -+ pushl %edi -+ -+ movl 8(%ebp), %esi # Load source address -+ movl 12(%ebp), %edi # Load destination address -+ movl 16(%ebp), %ecx # Load count -+ repz # Repeat for count... -+ smovb # move from %ds:si to %es:di -+ -+ popl %edi -+ popl %esi -+ movl %ebp, %esp -+ popl %ebp -+ ret -+ SYM_FUNC_END(dtrace_copy) -+ -+#endif /* __i386__ */ -+ -+#if defined(__x86_64__) -+ -+ SYM_FUNC_START(dtrace_copystr) -+ pushq %rbp -+ movq %rsp, %rbp -+ -+ ASM_STAC -+0: -+ movb (%rdi), %al # load from source -+ movb %al, (%rsi) # store to destination -+ addq $1, %rdi # increment source pointer -+ addq $1, %rsi # increment destination pointer -+ subq $1, %rdx # decrement remaining count -+ cmpb $0, %al -+ je 2f -+ testq $0xfff, %rdx # test if count is 4k-aligned -+ jnz 1f # if not, continue with copying -+ testq $CPU_DTRACE_BADADDR, (%rcx) # load and test dtrace flags -+ jnz 2f -+1: -+ cmpq $0, %rdx -+ jne 0b -+2: -+ ASM_CLAC -+ leave -+ ret -+ -+ SYM_FUNC_END(dtrace_copystr) -+ -+#elif defined(__i386__) -+ -+ SYM_FUNC_START(dtrace_copystr) -+ -+ pushl %ebp # Setup stack frame -+ movl %esp, %ebp -+ pushl %ebx # Save registers -+ -+ movl 8(%ebp), %ebx # Load source address -+ movl 12(%ebp), %edx # Load destination address -+ movl 16(%ebp), %ecx # Load count -+ -+0: -+ movb (%ebx), %al # Load from source -+ movb %al, (%edx) # Store to destination -+ incl %ebx # Increment source pointer -+ incl %edx # Increment destination pointer -+ decl %ecx # Decrement remaining count -+ cmpb $0, %al -+ je 2f -+ testl $0xfff, %ecx # Check if count is 4k-aligned -+ jnz 1f -+ movl 20(%ebp), %eax # load flags pointer -+ testl $CPU_DTRACE_BADADDR, (%eax) # load and test dtrace flags -+ jnz 2f -+1: -+ cmpl $0, %ecx -+ jne 0b -+ -+2: -+ popl %ebx -+ movl %ebp, %esp -+ popl %ebp -+ ret -+ -+ SYM_FUNC_END(dtrace_copystr) -+ -+#endif /* __i386__ */ -+ -+#if defined(__x86_64__) -+ -+ SYM_CODE_START(dtrace_fuword8_nocheck) -+ xorq %rax, %rax -+ ASM_STAC -+ movb (%rdi), %al -+ ASM_CLAC -+ ret -+ SYM_CODE_END(dtrace_fuword8_nocheck) -+ -+#elif defined(__i386__) -+ -+ SYM_CODE_START(dtrace_fuword8_nocheck) -+ movl 4(%esp), %ecx -+ xorl %eax, %eax -+ movzbl (%ecx), %eax -+ ret -+ SYM_CODE_END(dtrace_fuword8_nocheck) -+ -+#endif /* __i386__ */ -+ -+#if defined(__x86_64__) -+ -+ SYM_CODE_START(dtrace_fuword16_nocheck) -+ xorq %rax, %rax -+ ASM_STAC -+ movw (%rdi), %ax -+ ASM_CLAC -+ ret -+ SYM_CODE_END(dtrace_fuword16_nocheck) -+ -+#elif defined(__i386__) -+ -+ SYM_CODE_START(dtrace_fuword16_nocheck) -+ movl 4(%esp), %ecx -+ xorl %eax, %eax -+ movzwl (%ecx), %eax -+ ret -+ SYM_CODE_END(dtrace_fuword16_nocheck) -+ -+#endif /* __i386__ */ -+ -+#if defined(__x86_64__) -+ -+ SYM_CODE_START(dtrace_fuword32_nocheck) -+ xorq %rax, %rax -+ ASM_STAC -+ movl (%rdi), %eax -+ ASM_CLAC -+ ret -+ SYM_CODE_END(dtrace_fuword32_nocheck) -+ -+#elif defined(__i386__) -+ -+ SYM_CODE_START(dtrace_fuword32_nocheck) -+ movl 4(%esp), %ecx -+ xorl %eax, %eax -+ movl (%ecx), %eax -+ ret -+ SYM_CODE_END(dtrace_fuword32_nocheck) -+ -+#endif /* __i386__ */ -+ -+#if defined(__x86_64__) -+ -+ SYM_CODE_START(dtrace_fuword64_nocheck) -+ ASM_STAC -+ movq (%rdi), %rax -+ ASM_CLAC -+ ret -+ SYM_CODE_END(dtrace_fuword64_nocheck) -+ -+#elif defined(__i386__) -+ -+ SYM_CODE_START(dtrace_fuword64_nocheck) -+ movl 4(%esp), %ecx -+ xorl %eax, %eax -+ xorl %edx, %edx -+ movl (%ecx), %eax -+ movl 4(%ecx), %edx -+ ret -+ SYM_CODE_END(dtrace_fuword64_nocheck) -+ -+#endif /* __i386__ */ -diff --git a/arch/x86/dtrace/dtrace_isa_x86_64.c b/arch/x86/dtrace/dtrace_isa_x86_64.c -new file mode 100644 -index 000000000000..5accadc9f121 ---- /dev/null -+++ b/arch/x86/dtrace/dtrace_isa_x86_64.c -@@ -0,0 +1,228 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_isa_x86_64.c -+ * DESCRIPTION: DTrace - x86_64 architecture specific support functions -+ * -+ * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/dtrace_cpu.h> -+#include <asm/unwind.h> -+ -+#include "dtrace.h" -+ -+/* Register indices */ -+#define REG_TRAPNO 25 -+#define REG_GS 24 -+#define REG_FS 23 -+#define REG_ES 22 -+#define REG_DS 21 -+#define REG_SS 20 -+#define REG_RSP 19 -+#define REG_RFL 18 -+#define REG_CS 17 -+#define REG_RIP 16 -+#define REG_ERR 15 -+#define REG_RDI 14 -+#define REG_RSI 13 -+#define REG_RDX 12 -+#define REG_RCX 11 -+#define REG_RAX 10 -+#define REG_R8 9 -+#define REG_R9 8 -+#define REG_R10 7 -+#define REG_R11 6 -+#define REG_RBX 5 -+#define REG_RBP 4 -+#define REG_R12 3 -+#define REG_R13 2 -+#define REG_R14 1 -+#define REG_R15 0 -+ -+extern void dtrace_copy(uintptr_t, uintptr_t, size_t); -+extern void dtrace_copystr(uintptr_t, uintptr_t, size_t, -+ volatile uint16_t *); -+ -+uintptr_t _userlimit = 0x00007fffffffffffLL; -+uintptr_t kernelbase = 0xffff880000000000LL; -+ -+static int dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size) -+{ -+#ifdef FIXME -+ ASSERT(kaddr >= kernelbase && kaddr + size >= kaddr); -+#else -+ if (kaddr < kernelbase || kaddr + size < kaddr) { -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); -+ this_cpu_core->cpuc_dtrace_illval = kaddr; -+ return 0; -+ } -+#endif -+ -+ if (uaddr + size >= kernelbase || uaddr + size < uaddr) { -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); -+ this_cpu_core->cpuc_dtrace_illval = uaddr; -+ return 0; -+ } -+ -+ return 1; -+} -+ -+void dtrace_copyin_arch(uintptr_t uaddr, uintptr_t kaddr, size_t size, -+ volatile uint16_t *flags) -+{ -+ if (dtrace_copycheck(uaddr, kaddr, size)) -+ dtrace_copy(uaddr, kaddr, size); -+} -+ -+void dtrace_copyout(uintptr_t uaddr, uintptr_t kaddr, size_t size, -+ volatile uint16_t *flags) -+{ -+ if (dtrace_copycheck(uaddr, kaddr, size)) -+ dtrace_copy(kaddr, uaddr, size); -+} -+ -+void dtrace_copyinstr_arch(uintptr_t uaddr, uintptr_t kaddr, size_t size, -+ volatile uint16_t *flags) -+{ -+ if (dtrace_copycheck(uaddr, kaddr, size)) -+ dtrace_copystr(uaddr, kaddr, size, flags); -+} -+ -+void dtrace_copyoutstr(uintptr_t uaddr, uintptr_t kaddr, size_t size, -+ volatile uint16_t *flags) -+{ -+ if (dtrace_copycheck(uaddr, kaddr, size)) -+ dtrace_copystr(kaddr, uaddr, size, flags); -+} -+ -+#define DTRACE_FUWORD(bits) \ -+ uint##bits##_t dtrace_fuword##bits(void *uaddr) \ -+ { \ -+ extern uint##bits##_t dtrace_fuword##bits##_nocheck(void *);\ -+ \ -+ if ((uintptr_t)uaddr > _userlimit) { \ -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); \ -+ this_cpu_core->cpuc_dtrace_illval = (uintptr_t)uaddr; \ -+ return 0; \ -+ } \ -+ \ -+ return dtrace_fuword##bits##_nocheck(uaddr); \ -+ } -+ -+DTRACE_FUWORD(8) -+DTRACE_FUWORD(16) -+DTRACE_FUWORD(32) -+DTRACE_FUWORD(64) -+ -+uint64_t dtrace_getarg(int argno, int aframes) -+{ -+ unsigned long bp; -+ uint64_t *st; -+ uint64_t val; -+ int i; -+ struct unwind_state state; -+ -+ if (this_cpu_core->cpu_dtrace_regs) -+ bp = this_cpu_core->cpu_dtrace_regs->bp; -+ else { -+ unwind_start(&state, current, NULL, NULL); -+ for (i = 0; !unwind_done(&state) && i < aframes; -+ unwind_next_frame(&state)) { -+ i++; -+ } -+ -+ bp = (unsigned long)state.bp; -+ } -+ -+ ASSERT(argno >= 5); -+ -+ /* -+ * The first 5 arguments (arg0 through arg4) are passed in registers -+ * to dtrace_probe(). The remaining arguments (arg5 through arg9) are -+ * passed on the stack. -+ * -+ * Stack layout: -+ * bp[0] = pushed bp from caller -+ * bp[1] = return address -+ * bp[2] = 6th argument (arg5 -> argno = 5) -+ * bp[3] = 7th argument (arg6 -> argno = 6) -+ * ... -+ */ -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); -+ st = (uint64_t *)bp; -+ val = st[2 + (argno - 5)]; -+ DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); -+ -+ return val; -+} -+ -+ulong_t dtrace_getreg(struct task_struct *task, uint_t reg) -+{ -+ struct pt_regs *rp = task_pt_regs(task); -+ -+ int regmap[] = { -+ REG_RBX, /* 0 -> EBX */ -+ REG_RCX, /* 1 -> ECX */ -+ REG_RDX, /* 2 -> EDX */ -+ REG_RSI, /* 3 -> ESI */ -+ REG_RDI, /* 4 -> EDI */ -+ REG_RBP, /* 5 -> EBP */ -+ REG_RAX, /* 6 -> EAX */ -+ REG_DS, /* 7 -> DS */ -+ REG_ES, /* 8 -> ES */ -+ REG_FS, /* 9 -> FS */ -+ REG_GS, /* 10 -> GS */ -+ REG_TRAPNO, /* 11 -> TRAPNO */ -+ REG_RIP, /* 12 -> EIP */ -+ REG_CS, /* 13 -> CS */ -+ REG_RFL, /* 14 -> EFL */ -+ REG_RSP, /* 15 -> UESP */ -+ REG_SS, /* 16 -> SS */ -+ }; -+ -+ if (reg > REG_TRAPNO) { -+ /* -+ * Convert register alias index into register mapping index. -+ */ -+ reg -= REG_GS + 1; -+ -+ if (reg >= sizeof(regmap) / sizeof(int)) { -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); -+ return 0; -+ } -+ -+ reg = regmap[reg]; -+ } -+ -+ /* -+ * Most common case: direct index into pt_regs structure. -+ */ -+ if (reg <= REG_SS) -+ return (&rp->r15)[reg]; -+ -+ switch (reg) { -+ case REG_DS: -+ return task->thread.ds; -+ case REG_ES: -+ return task->thread.es; -+ case REG_FS: -+ return task->thread.fsbase; -+ case REG_GS: -+ return task->thread.gsbase; -+ case REG_TRAPNO: -+ return task->thread.trap_nr; -+ default: -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); -+ return 0; -+ } -+} -diff --git a/dtrace/Makefile b/dtrace/Makefile -new file mode 100644 -index 000000000000..36a4b97b922c ---- /dev/null -+++ b/dtrace/Makefile -@@ -0,0 +1,19 @@ -+# -+# Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. -+# -+ -+obj-$(CONFIG_DT_CORE) += dtrace.o -+obj-$(CONFIG_DT_DT_TEST) += dt_test.o -+ -+dtrace-y := dtrace_mod.o dtrace_dev.o \ -+ dtrace_actdesc.o dtrace_anon.o \ -+ dtrace_buffer.o dtrace_dif.o dtrace_dof.o \ -+ dtrace_ecb.o dtrace_enable.o \ -+ dtrace_fmt.o dtrace_hash.o dtrace_isa.o \ -+ dtrace_match.o dtrace_priv.o \ -+ dtrace_probe.o dtrace_probe_ctx.o \ -+ dtrace_ptofapi.o dtrace_predicate.o \ -+ dtrace_spec.o dtrace_state.o dtrace_util.o -+dt_test-y := dt_test_mod.o dt_test_dev.o -+ -+-include arch/$(SRCARCH)/dtrace/Makefile.arch -diff --git a/dtrace/ctf_api.h b/dtrace/ctf_api.h -new file mode 100644 -index 000000000000..e09bafc676f4 ---- /dev/null -+++ b/dtrace/ctf_api.h -@@ -0,0 +1,33 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Compact C Type format -+ * -+ * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#ifndef __CTF_API_H_ -+#define __CTF_API_H_ -+ -+/* -+ * The CTF data model is inferred to be the caller's data model or the data -+ * model of the given object, unless ctf_setmodel() is explicitly called. -+ */ -+#define CTF_MODEL_ILP32 1 /* object data model is ILP32 */ -+#define CTF_MODEL_LP64 2 /* object data model is LP64 */ -+#ifdef CONFIG_64BIT -+# define CTF_MODEL_NATIVE CTF_MODEL_LP64 -+#else -+# define CTF_MODEL_NATIVE CTF_MODEL_ILP32 -+#endif -+ -+#endif /* __CTF_API_H_ */ -diff --git a/dtrace/dt_test.h b/dtrace/dt_test.h -new file mode 100644 -index 000000000000..6efe4656001b ---- /dev/null -+++ b/dtrace/dt_test.h -@@ -0,0 +1,30 @@ -+/* -+ * Dynamic Tracing for Linux - test provider -+ * -+ * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#ifndef _DT_TEST_H_ -+#define _DT_TEST_H_ -+ -+extern void dt_test_provide(void *, const struct dtrace_probedesc *); -+extern int dt_test_enable(void *arg, dtrace_id_t, void *); -+extern void dt_test_disable(void *arg, dtrace_id_t, void *); -+extern void dt_test_destroy(void *, dtrace_id_t, void *); -+ -+extern dtrace_provider_id_t dt_test_id; -+ -+extern int dt_test_dev_init(void); -+extern void dt_test_dev_exit(void); -+ -+#endif /* _DT_TEST_H_ */ -diff --git a/dtrace/dt_test_dev.c b/dtrace/dt_test_dev.c -new file mode 100644 -index 000000000000..8e1f5bab8a12 ---- /dev/null -+++ b/dtrace/dt_test_dev.c -@@ -0,0 +1,176 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dt_test_dev.c -+ * DESCRIPTION: DTrace - test provider device driver -+ * -+ * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/fs.h> -+#include <linux/miscdevice.h> -+#include <linux/types.h> -+#include <trace/syscall.h> -+#include <asm/unistd.h> -+ -+#include "dtrace.h" -+#include "dtrace_dev.h" -+#include "dt_test.h" -+ -+static dtrace_id_t pid = DTRACE_IDNONE; -+static int enabled; -+ -+/* -+ * Some arrays of structures of different sizes populated with -+ * unchanging randomly-chosen numbers, for padding tests. -+ */ -+ -+static struct dt_test_int_char -+{ -+ int foo; -+ char bar; -+} intish[2] __attribute__((used)) = { { 47204473, 48 }, -+ { 18472, 62 } }; -+ -+static struct dt_test_long_int -+{ -+ long foo; -+ int bar; -+} longish[2] __attribute__((used)) = { { 43737975, 240724 }, -+ { 24924709, 526 } }; -+ -+static struct dt_test_longlong_long -+{ -+ long long foo; -+ long bar; -+} longlongish[2] __attribute__((used)) = { { 4294479287, 4395957 }, -+ { 5239637, 249750 } }; -+ -+static struct dt_test_like_a_scatterlist -+{ -+ unsigned long a; -+ unsigned int b; -+ unsigned int c; -+ u64 d; -+ unsigned int e; -+} scatter_failure[2] __attribute__((used)) = { { .a = 1, .b = 2, -+ .c = 3, .d = 4, .e = 5 }, -+ { .a = 6, .b = 7, -+ .c = 8, .d = 9, .e = 10 } }; -+ -+void dt_test_provide(void *arg, const struct dtrace_probedesc *desc) -+{ -+ dtrace_id_t probe; -+ -+ probe = dtrace_probe_lookup(dt_test_id, "dt_test", NULL, "test"); -+ if (probe != DTRACE_IDNONE) -+ return; -+ -+ pid = dtrace_probe_create(dt_test_id, "dt_test", NULL, "test", 1, NULL); -+} -+ -+int dt_test_enable(void *arg, dtrace_id_t id, void *parg) -+{ -+ enabled = 1; -+ -+ return 0; -+} -+ -+void dt_test_disable(void *arg, dtrace_id_t id, void *parg) -+{ -+ enabled = 0; -+} -+ -+void dt_test_destroy(void *arg, dtrace_id_t id, void *parg) -+{ -+} -+ -+void probe_p(dtrace_id_t pid, uintptr_t arg0, uintptr_t arg1, uintptr_t arg2, -+ uintptr_t arg3, uintptr_t arg4, uintptr_t arg5, uintptr_t arg6, -+ uintptr_t arg7, uintptr_t arg8, uintptr_t arg9) -+{ -+} -+ -+/* -+ * Direct calling into dtrace_probe() when passing more than 5 parameters to -+ * the probe requires a stub function. Otherwise we may not be able to get -+ * to the value of all arguments correctly. -+ */ -+void dt_test_probe(uintptr_t arg0, uintptr_t arg1, uintptr_t arg2, -+ uintptr_t arg3, uintptr_t arg4, uintptr_t arg5, -+ uintptr_t arg6, uintptr_t arg7, uintptr_t arg8, -+ uintptr_t arg9) -+{ -+ /* -+ * Yes, this is not nice. -+ * Not at all... -+ * But we're doing it anyway... -+ */ -+ typeof(probe_p) *probe_fn = (void *)&dtrace_probe; -+ -+ probe_fn(pid, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, -+ arg9); -+} -+ -+static long dt_test_ioctl(struct file *file, -+ unsigned int cmd, unsigned long arg) -+{ -+ if (enabled) { -+ dt_test_probe(cmd, arg, 2ULL, 3ULL, 4ULL, 5ULL, 6ULL, 7ULL, -+ 8ULL, 9ULL); -+ -+ return 0; -+ } -+ -+ return -EAGAIN; -+} -+ -+static int dt_test_open(struct inode *inode, struct file *file) -+{ -+ return 0; -+} -+ -+static int dt_test_close(struct inode *inode, struct file *file) -+{ -+ return 0; -+} -+ -+static const struct file_operations dt_test_fops = { -+ .owner = THIS_MODULE, -+ .unlocked_ioctl = dt_test_ioctl, -+ .open = dt_test_open, -+ .release = dt_test_close, -+}; -+ -+static struct miscdevice dt_test_dev = { -+ .minor = DT_DEV_DT_TEST_MINOR, -+ .name = "dt_test", -+ .nodename = "dtrace/provider/dt_test", -+ .fops = &dt_test_fops, -+}; -+ -+int dt_test_dev_init(void) -+{ -+ int ret = 0; -+ -+ ret = misc_register(&dt_test_dev); -+ if (ret) -+ pr_err("%s: Can't register misc device %d\n", -+ dt_test_dev.name, dt_test_dev.minor); -+ -+ return ret; -+} -+ -+void dt_test_dev_exit(void) -+{ -+ misc_deregister(&dt_test_dev); -+} -diff --git a/dtrace/dt_test_mod.c b/dtrace/dt_test_mod.c -new file mode 100644 -index 000000000000..d8af71665a37 ---- /dev/null -+++ b/dtrace/dt_test_mod.c -@@ -0,0 +1,52 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dt_test_mod.c -+ * DESCRIPTION: DTrace - test provider kernel module -+ * -+ * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/module.h> -+ -+#include "dtrace.h" -+#include "dtrace_dev.h" -+#include "dt_test.h" -+ -+MODULE_AUTHOR("Kris Van Hees (kris.van.hees@oracle.com)"); -+MODULE_DESCRIPTION("DTrace Test Probe"); -+MODULE_VERSION("v0.1"); -+MODULE_LICENSE("GPL"); -+ -+static const struct dtrace_pattr dt_test_attr = { -+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA }, -+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA }, -+}; -+ -+static struct dtrace_pops dt_test_pops = { -+ .dtps_provide = dt_test_provide, -+ .dtps_provide_module = NULL, -+ .dtps_destroy_module = NULL, -+ .dtps_enable = dt_test_enable, -+ .dtps_disable = dt_test_disable, -+ .dtps_suspend = NULL, -+ .dtps_resume = NULL, -+ .dtps_getargdesc = NULL, -+ .dtps_getargval = NULL, -+ .dtps_usermode = NULL, -+ .dtps_destroy = dt_test_destroy -+}; -+ -+DT_PROVIDER_MODULE(dt_test, DTRACE_PRIV_USER) -diff --git a/dtrace/dtrace.h b/dtrace/dtrace.h -new file mode 100644 -index 000000000000..f632b910ac30 ---- /dev/null -+++ b/dtrace/dtrace.h -@@ -0,0 +1,35 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Dynamic Tracing for Linux -+ * -+ * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#ifndef _DTRACE_H_ -+#define _DTRACE_H_ -+ -+#include <linux/dtrace_cpu.h> -+#include <linux/dtrace_os.h> -+#include <linux/sched.h> -+#include <linux/types.h> -+ -+#include "dtrace_debug.h" -+ -+#include <dtrace/types.h> -+ -+#include <linux/dtrace/dtrace.h> -+ -+#include <dtrace/provider.h> -+#include <dtrace/dtrace_impl.h> -+ -+#endif /* _DTRACE_H_ */ -diff --git a/dtrace/dtrace_actdesc.c b/dtrace/dtrace_actdesc.c -new file mode 100644 -index 000000000000..fada47a6e5eb ---- /dev/null -+++ b/dtrace/dtrace_actdesc.c -@@ -0,0 +1,91 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_actdesc.c -+ * DESCRIPTION: DTrace - action implementation -+ * -+ * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/slab.h> -+#include <linux/vmalloc.h> -+ -+#include "dtrace.h" -+ -+struct dtrace_actdesc *dtrace_actdesc_create(dtrace_actkind_t kind, -+ uint32_t ntuple, -+ uint64_t uarg, uint64_t arg) -+{ -+ struct dtrace_actdesc *act; -+ -+#ifdef FIXME -+ ASSERT(!DTRACEACT_ISPRINTFLIKE(kind) || -+ (arg != 0 && (uintptr_t)arg >= KERNELBASE) || -+ (arg == 0 && kind == DTRACEACT_PRINTA)); -+#else -+ ASSERT(!DTRACEACT_ISPRINTFLIKE(kind) || -+ (arg != 0) || -+ (arg == 0 && kind == DTRACEACT_PRINTA)); -+#endif -+ -+ act = kzalloc(sizeof(struct dtrace_actdesc), GFP_KERNEL); -+ if (act == NULL) -+ return NULL; -+ -+ act->dtad_kind = kind; -+ act->dtad_ntuple = ntuple; -+ act->dtad_uarg = uarg; -+ act->dtad_arg = arg; -+ act->dtad_refcnt = 1; -+ -+ return act; -+} -+ -+void dtrace_actdesc_hold(struct dtrace_actdesc *act) -+{ -+ ASSERT(act->dtad_refcnt >= 1); -+ -+ act->dtad_refcnt++; -+} -+ -+void dtrace_actdesc_release(struct dtrace_actdesc *act, -+ struct dtrace_vstate *vstate) -+{ -+ dtrace_actkind_t kind = act->dtad_kind; -+ struct dtrace_difo *dp; -+ -+ ASSERT(act->dtad_refcnt >= 1); -+ -+ if (--act->dtad_refcnt != 0) -+ return; -+ -+ dp = act->dtad_difo; -+ if (dp != NULL) -+ dtrace_difo_release(dp, vstate); -+ -+ if (DTRACEACT_ISPRINTFLIKE(kind)) { -+ char *str = (char *)(uintptr_t)act->dtad_arg; -+ -+#ifdef FIXME -+ ASSERT((str != NULL && (uintptr_t)str >= KERNELBASE) || -+ (str == NULL && act->dtad_kind == DTRACEACT_PRINTA)); -+#else -+ ASSERT((str != NULL) || -+ (str == NULL && act->dtad_kind == DTRACEACT_PRINTA)); -+#endif -+ -+ if (str != NULL) -+ vfree(str); -+ } -+ -+ kfree(act); -+} -diff --git a/dtrace/dtrace_anon.c b/dtrace/dtrace_anon.c -new file mode 100644 -index 000000000000..80d0d9c1a9fd ---- /dev/null -+++ b/dtrace/dtrace_anon.c -@@ -0,0 +1,144 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_anon.c -+ * DESCRIPTION: DTrace - Anonymous state implementation -+ * -+ * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include "dtrace.h" -+ -+struct dtrace_anon dtrace_anon; -+ -+struct dtrace_state *dtrace_anon_grab(void) -+{ -+ struct dtrace_state *state; -+ -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ -+ state = dtrace_anon.dta_state; -+ if (state == NULL) { -+ ASSERT(dtrace_anon.dta_enabling == NULL); -+ -+ return NULL; -+ } -+ -+ ASSERT(dtrace_anon.dta_enabling != NULL); -+ ASSERT(dtrace_retained != NULL); -+ -+ dtrace_enabling_destroy(dtrace_anon.dta_enabling); -+ dtrace_anon.dta_enabling = NULL; -+ dtrace_anon.dta_state = NULL; -+ -+ return state; -+} -+ -+void dtrace_anon_property(void) -+{ -+ int i, rv; -+ struct dtrace_state *state; -+ struct dof_hdr *dof; -+ char c[32]; /* enough for "dof-data-" + digits */ -+ -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ ASSERT(MUTEX_HELD(&cpu_lock)); -+ -+ for (i = 0; ; i++) { -+ snprintf(c, sizeof(c), "dof-data-%d", i); -+ -+ dtrace_err_verbose = 1; -+ -+ dof = dtrace_dof_property(c); -+ if (dof == NULL) { -+ dtrace_err_verbose = 0; -+ break; -+ } -+ -+#ifdef FIXME -+ /* -+ * We want to create anonymous state, so we need to transition -+ * the kernel debugger to indicate that DTrace is active. If -+ * this fails (e.g. because the debugger has modified text in -+ * some way), we won't continue with the processing. -+ */ -+ if (kdi_dtrace_set(KDI_DTSET_DTRACE_ACTIVATE) != 0) { -+ pr_info("kernel debugger active; " -+ "anonymous enabling ignored."); -+ dtrace_dof_destroy(dof); -+ break; -+ } -+#endif -+ -+ /* -+ * If we haven't allocated an anonymous state, we'll do so now. -+ */ -+ state = dtrace_anon.dta_state; -+ if (state == NULL) { -+ state = dtrace_state_create(NULL); -+ dtrace_anon.dta_state = state; -+ -+ if (state == NULL) { -+ /* -+ * This basically shouldn't happen: there is no -+ * failure mode from dtrace_state_create(). -+ * Still, the interface allows for a failure -+ * mode, and we want to fail as gracefully as -+ * possible: we'll emit an error message and -+ * cease processing anonymous state in this -+ * case. -+ */ -+ pr_warn("failed to create anonymous state"); -+ dtrace_dof_destroy(dof); -+ break; -+ } -+ } -+ -+ rv = dtrace_dof_slurp(dof, &state->dts_vstate, current_cred(), -+ &dtrace_anon.dta_enabling, 0, TRUE); -+ -+ if (rv == 0) -+ rv = dtrace_dof_options(dof, state); -+ -+ dtrace_err_verbose = 0; -+ dtrace_dof_destroy(dof); -+ -+ if (rv != 0) { -+ /* -+ * This is malformed DOF; chuck any anonymous state -+ * that we created. -+ */ -+ ASSERT(dtrace_anon.dta_enabling == NULL); -+ dtrace_state_destroy(state); -+ dtrace_anon.dta_state = NULL; -+ break; -+ } -+ -+ ASSERT(dtrace_anon.dta_enabling != NULL); -+ } -+ -+ if (dtrace_anon.dta_enabling != NULL) { -+ int rval; -+ -+ /* -+ * dtrace_enabling_retain() can only fail because we are -+ * trying to retain more enablings than are allowed -- but -+ * we only have one anonymous enabling, and we are guaranteed -+ * to be allowed at least one retained enabling; we assert -+ * that dtrace_enabling_retain() returns success. -+ */ -+ rval = dtrace_enabling_retain(dtrace_anon.dta_enabling); -+ ASSERT(rval == 0); -+ -+ dtrace_enabling_dump(dtrace_anon.dta_enabling); -+ } -+} -diff --git a/dtrace/dtrace_buffer.c b/dtrace/dtrace_buffer.c -new file mode 100644 -index 000000000000..9e7faebc51b7 ---- /dev/null -+++ b/dtrace/dtrace_buffer.c -@@ -0,0 +1,490 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_buffer.c -+ * DESCRIPTION: DTrace - buffer implementation -+ * -+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/vmalloc.h> -+ -+#include "dtrace.h" -+ -+dtrace_optval_t dtrace_nonroot_maxsize = (16 * 1024 * 1024); -+ -+/* -+ * Note: called from cross call context. This function switches the two -+ * buffers on a given CPU. The atomicity of this operation is assured by -+ * disabling interrupts while the actual switch takes place; the disabling of -+ * interrupts serializes the execution with any execution of dtrace_probe() on -+ * the same CPU. -+ */ -+void dtrace_buffer_switch(struct dtrace_buffer *buf) -+{ -+ caddr_t tomax = buf->dtb_tomax; -+ caddr_t xamot = buf->dtb_xamot; -+ dtrace_icookie_t cookie; -+ -+ ASSERT(!(buf->dtb_flags & DTRACEBUF_NOSWITCH)); -+ ASSERT(!(buf->dtb_flags & DTRACEBUF_RING)); -+ -+ local_irq_save(cookie); -+ -+ dt_dbg_buf("Switch (CPU %d): tomax %p (%lld) <-> xamot %p (%lld)\n", -+ smp_processor_id(), tomax, buf->dtb_offset, -+ xamot, buf->dtb_xamot_offset); -+ -+ buf->dtb_tomax = xamot; -+ buf->dtb_xamot = tomax; -+ buf->dtb_xamot_drops = buf->dtb_drops; -+ buf->dtb_xamot_offset = buf->dtb_offset; -+ buf->dtb_xamot_errors = buf->dtb_errors; -+ buf->dtb_xamot_flags = buf->dtb_flags; -+ buf->dtb_offset = 0; -+ buf->dtb_drops = 0; -+ buf->dtb_errors = 0; -+ buf->dtb_flags &= ~(DTRACEBUF_ERROR | DTRACEBUF_DROPPED); -+ -+ local_irq_restore(cookie); -+} -+ -+/* -+ * Note: called from cross call context. This function activates a buffer -+ * on a CPU. As with dtrace_buffer_switch(), the atomicity of the operation -+ * is guaranteed by the disabling of interrupts. -+ */ -+void dtrace_buffer_activate(struct dtrace_state *state) -+{ -+ struct dtrace_buffer *buf; -+ dtrace_icookie_t cookie; -+ -+ local_irq_save(cookie); -+ -+ buf = &state->dts_buffer[smp_processor_id()]; -+ -+ if (buf->dtb_tomax != NULL) -+ /* -+ * We might like to assert that the buffer is marked inactive, -+ * but this isn't necessarily true: the buffer for the CPU -+ * that processes the BEGIN probe has its buffer activated -+ * manually. In this case, we take the (harmless) action -+ * re-clearing the bit INACTIVE bit. -+ */ -+ buf->dtb_flags &= ~DTRACEBUF_INACTIVE; -+ -+ local_irq_restore(cookie); -+} -+ -+int dtrace_buffer_alloc(struct dtrace_buffer *bufs, size_t size, int flags, -+ processorid_t cpuid) -+{ -+ processorid_t cpu; -+ struct dtrace_buffer *buf; -+ -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ ASSERT(MUTEX_HELD(&cpu_lock)); -+ -+#ifdef FIXME -+ if (size > dtrace_nonroot_maxsize && -+ !PRIV_POLICY_CHOICE(current_cred(), PRIV_ALL, FALSE)) -+ return -EFBIG; -+#endif -+ -+ for_each_online_cpu(cpu) { -+ if (cpuid != DTRACE_CPUALL && cpuid != cpu) -+ continue; -+ -+ buf = &bufs[cpu]; -+ -+ /* -+ * If there is already a buffer allocated for this CPU, it -+ * is only possible that this is a DR event. In this case, -+ * the buffer size must match our specified size. -+ */ -+ if (buf->dtb_tomax != NULL) { -+ ASSERT(buf->dtb_size == size); -+ continue; -+ } -+ -+ ASSERT(buf->dtb_xamot == NULL); -+ -+ buf->dtb_tomax = dtrace_vzalloc_try(size); -+ if (buf->dtb_tomax == NULL) -+ goto err; -+ -+ buf->dtb_size = size; -+ buf->dtb_flags = flags; -+ buf->dtb_offset = 0; -+ buf->dtb_drops = 0; -+ -+ if (flags & DTRACEBUF_NOSWITCH) -+ continue; -+ -+ buf->dtb_xamot = dtrace_vzalloc_try(size); -+ if (buf->dtb_xamot == NULL) -+ goto err; -+ } -+ -+ return 0; -+ -+err: -+ for_each_online_cpu(cpu) { -+ if (cpuid != DTRACE_CPUALL && cpuid != cpu) -+ continue; -+ -+ buf = &bufs[cpu]; -+ -+ if (buf->dtb_xamot != NULL) { -+ ASSERT(buf->dtb_tomax != NULL); -+ ASSERT(buf->dtb_size == size); -+ vfree(buf->dtb_xamot); -+ } -+ -+ if (buf->dtb_tomax != NULL) { -+ ASSERT(buf->dtb_size == size); -+ vfree(buf->dtb_tomax); -+ } -+ -+ buf->dtb_tomax = NULL; -+ buf->dtb_xamot = NULL; -+ buf->dtb_size = 0; -+ } -+ -+ return -ENOMEM; -+} -+void dtrace_buffer_drop(struct dtrace_buffer *buf) -+{ -+ buf->dtb_drops++; -+} -+ -+intptr_t dtrace_buffer_reserve(struct dtrace_buffer *buf, size_t needed, -+ size_t align, struct dtrace_state *state, -+ struct dtrace_mstate *mstate) -+{ -+ intptr_t offs = buf->dtb_offset, soffs; -+ intptr_t woffs; -+ caddr_t tomax; -+ size_t total; -+ -+ if (buf->dtb_flags & DTRACEBUF_INACTIVE) -+ return -1; -+ -+ tomax = buf->dtb_tomax; -+ if (tomax == NULL) { -+ dtrace_buffer_drop(buf); -+ return -1; -+ } -+ -+ if (!(buf->dtb_flags & (DTRACEBUF_RING | DTRACEBUF_FILL))) { -+ while (offs & (align - 1)) { -+ /* -+ * Assert that our alignment is off by a number which -+ * is itself sizeof (uint32_t) aligned. -+ */ -+ ASSERT(!((align - (offs & (align - 1))) & -+ (sizeof(uint32_t) - 1))); -+ DTRACE_STORE(uint32_t, tomax, offs, DTRACE_EPIDNONE); -+ dt_dbg_buf(" Store: %p[%ld .. %ld] <- EPIDNONE " -+ "(from %s::%d)\n", -+ buf, offs, offs + sizeof(uint32_t) - 1, -+ __func__, __LINE__); -+ offs += sizeof(uint32_t); -+ } -+ -+ soffs = offs + needed; -+ if (soffs > buf->dtb_size) { -+ dtrace_buffer_drop(buf); -+ return -1; -+ } -+ -+ if (mstate == NULL) { -+ dt_dbg_buf(" Reserve: %p[%ld .. %ld]\n", -+ buf, offs, offs + needed - 1); -+ return offs; -+ } -+ -+ mstate->dtms_scratch_base = (uintptr_t)tomax + soffs; -+ mstate->dtms_scratch_size = buf->dtb_size - soffs; -+ mstate->dtms_scratch_ptr = mstate->dtms_scratch_base; -+ -+ dt_dbg_buf(" Reserve: %p[%ld .. %ld]\n", -+ buf, offs, offs + needed - 1); -+ return offs; -+ } -+ -+ if (buf->dtb_flags & DTRACEBUF_FILL) { -+ if (state->dts_activity != DTRACE_ACTIVITY_COOLDOWN && -+ (buf->dtb_flags & DTRACEBUF_FULL)) -+ return -1; -+ -+ goto out; -+ } -+ -+ total = needed + (offs & (align - 1)); -+ -+ /* -+ * For a ring buffer, life is quite a bit more complicated. Before -+ * we can store any padding, we need to adjust our wrapping offset. -+ * (If we've never before wrapped or we're not about to, no adjustment -+ * is required.) -+ */ -+ if ((buf->dtb_flags & DTRACEBUF_WRAPPED) || -+ offs + total > buf->dtb_size) { -+ woffs = buf->dtb_xamot_offset; -+ -+ if (offs + total > buf->dtb_size) { -+ /* -+ * We can't fit in the end of the buffer. First, a -+ * sanity check that we can fit in the buffer at all. -+ */ -+ if (total > buf->dtb_size) { -+ dtrace_buffer_drop(buf); -+ return -1; -+ } -+ -+ /* -+ * We're going to be storing at the top of the buffer, -+ * so now we need to deal with the wrapped offset. We -+ * only reset our wrapped offset to 0 if it is -+ * currently greater than the current offset. If it -+ * is less than the current offset, it is because a -+ * previous allocation induced a wrap -- but the -+ * allocation didn't subsequently take the space due -+ * to an error or false predicate evaluation. In this -+ * case, we'll just leave the wrapped offset alone: if -+ * the wrapped offset hasn't been advanced far enough -+ * for this allocation, it will be adjusted in the -+ * lower loop. -+ */ -+ if (buf->dtb_flags & DTRACEBUF_WRAPPED) { -+ if (woffs >= offs) -+ woffs = 0; -+ } else -+ woffs = 0; -+ -+ /* -+ * Now we know that we're going to be storing to the -+ * top of the buffer and that there is room for us -+ * there. We need to clear the buffer from the current -+ * offset to the end (there may be old gunk there). -+ */ -+ while (offs < buf->dtb_size) -+ tomax[offs++] = 0; -+ -+ /* -+ * We need to set our offset to zero. And because we -+ * are wrapping, we need to set the bit indicating as -+ * much. We can also adjust our needed space back -+ * down to the space required by the ECB -- we know -+ * that the top of the buffer is aligned. -+ */ -+ offs = 0; -+ total = needed; -+ buf->dtb_flags |= DTRACEBUF_WRAPPED; -+ } else { -+ /* -+ * There is room for us in the buffer, so we simply -+ * need to check the wrapped offset. -+ */ -+ if (woffs < offs) { -+ /* -+ * The wrapped offset is less than the offset. -+ * This can happen if we allocated buffer space -+ * that induced a wrap, but then we didn't -+ * subsequently take the space due to an error -+ * or false predicate evaluation. This is -+ * okay; we know that _this_ allocation isn't -+ * going to induce a wrap. We still can't -+ * reset the wrapped offset to be zero, -+ * however: the space may have been trashed in -+ * the previous failed probe attempt. But at -+ * least the wrapped offset doesn't need to -+ * be adjusted at all... -+ */ -+ goto out; -+ } -+ } -+ -+ while (offs + total > woffs) { -+ dtrace_epid_t epid = *(uint32_t *)(tomax + woffs); -+ size_t size; -+ -+ if (epid == DTRACE_EPIDNONE) -+ size = sizeof(uint32_t); -+ else { -+ ASSERT(epid <= state->dts_necbs); -+ ASSERT(state->dts_ecbs[epid - 1] != NULL); -+ -+ size = state->dts_ecbs[epid - 1]->dte_size; -+ } -+ -+ ASSERT(woffs + size <= buf->dtb_size); -+ ASSERT(size != 0); -+ -+ if (woffs + size == buf->dtb_size) { -+ /* -+ * We've reached the end of the buffer; we want -+ * to set the wrapped offset to 0 and break -+ * out. However, if the offs is 0, then we're -+ * in a strange edge-condition: the amount of -+ * space that we want to reserve plus the size -+ * of the record that we're overwriting is -+ * space but subsequently don't consume it (due -+ * to a failed predicate or error) the wrapped -+ * offset will be 0 -- yet the EPID at offset 0 -+ * will not be committed. This situation is -+ * relatively easy to deal with: if we're in -+ * this case, the buffer is indistinguishable -+ * from one that hasn't wrapped; we need only -+ * finish the job by clearing the wrapped bit, -+ * explicitly setting the offset to be 0, and -+ * zero'ing out the old data in the buffer. -+ */ -+ if (offs == 0) { -+ buf->dtb_flags &= ~DTRACEBUF_WRAPPED; -+ buf->dtb_offset = 0; -+ woffs = total; -+ -+ while (woffs < buf->dtb_size) -+ tomax[woffs++] = 0; -+ } -+ -+ woffs = 0; -+ break; -+ } -+ -+ woffs += size; -+ } -+ -+ /* -+ * We have a wrapped offset. It may be that the wrapped offset -+ * has become zero -- that's okay. -+ */ -+ buf->dtb_xamot_offset = woffs; -+ } -+ -+out: -+ /* -+ * Now we can plow the buffer with any necessary padding. -+ */ -+ while (offs & (align - 1)) { -+ /* -+ * Assert that our alignment is off by a number which -+ * is itself sizeof(uint32_t) aligned. -+ */ -+ ASSERT(!((align - (offs & (align - 1))) & -+ (sizeof(uint32_t) - 1))); -+ DTRACE_STORE(uint32_t, tomax, offs, DTRACE_EPIDNONE); -+ dt_dbg_buf(" Store: %p[%ld .. %ld] <- EPIDNONE " -+ "(from %s::%d)\n", -+ buf, offs, offs + sizeof(uint32_t) - 1, -+ __func__, __LINE__); -+ offs += sizeof(uint32_t); -+ } -+ -+ if (buf->dtb_flags & DTRACEBUF_FILL) { -+ if (offs + needed > buf->dtb_size - state->dts_reserve) { -+ buf->dtb_flags |= DTRACEBUF_FULL; -+ return -1; -+ } -+ } -+ -+ if (mstate == NULL) { -+ dt_dbg_buf(" Reserve: %p[%ld .. %ld]\n", -+ buf, offs, offs + needed - 1); -+ return offs; -+ } -+ -+ /* -+ * For ring buffers and fill buffers, the scratch space is always -+ * the inactive buffer. -+ */ -+ mstate->dtms_scratch_base = (uintptr_t)buf->dtb_xamot; -+ mstate->dtms_scratch_size = buf->dtb_size; -+ mstate->dtms_scratch_ptr = mstate->dtms_scratch_base; -+ -+ dt_dbg_buf(" Reserve: %p[%ld .. %ld]\n", -+ buf, offs, offs + needed - 1); -+ return offs; -+} -+ -+void dtrace_buffer_polish(struct dtrace_buffer *buf) -+{ -+ ASSERT(buf->dtb_flags & DTRACEBUF_RING); -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ -+ if (!(buf->dtb_flags & DTRACEBUF_WRAPPED)) -+ return; -+ -+ /* -+ * We need to polish the ring buffer. There are three cases: -+ * -+ * - The first (and presumably most common) is that there is no gap -+ * between the buffer offset and the wrapped offset. In this case, -+ * there is nothing in the buffer that isn't valid data; we can -+ * mark the buffer as polished and return. -+ * -+ * - The second (less common than the first but still more common -+ * than the third) is that there is a gap between the buffer offset -+ * and the wrapped offset, and the wrapped offset is larger than the -+ * buffer offset. This can happen because of an alignment issue, or -+ * can happen because of a call to dtrace_buffer_reserve() that -+ * didn't subsequently consume the buffer space. In this case, -+ * we need to zero the data from the buffer offset to the wrapped -+ * offset. -+ * -+ * - The third (and least common) is that there is a gap between the -+ * buffer offset and the wrapped offset, but the wrapped offset is -+ * _less_ than the buffer offset. This can only happen because a -+ * call to dtrace_buffer_reserve() induced a wrap, but the space -+ * was not subsequently consumed. In this case, we need to zero the -+ * space from the offset to the end of the buffer _and_ from the -+ * top of the buffer to the wrapped offset. -+ */ -+ if (buf->dtb_offset < buf->dtb_xamot_offset) -+ memset(buf->dtb_tomax + buf->dtb_offset, 0, -+ buf->dtb_xamot_offset - buf->dtb_offset); -+ -+ if (buf->dtb_offset > buf->dtb_xamot_offset) { -+ memset(buf->dtb_tomax + buf->dtb_offset, 0, -+ buf->dtb_size - buf->dtb_offset); -+ memset(buf->dtb_tomax, 0, buf->dtb_xamot_offset); -+ } -+} -+ -+void dtrace_buffer_free(struct dtrace_buffer *bufs) -+{ -+ int cpu; -+ -+ for_each_online_cpu(cpu) { -+ struct dtrace_buffer *buf = &bufs[cpu]; -+ -+ if (buf->dtb_tomax == NULL) { -+ ASSERT(buf->dtb_xamot == NULL); -+ ASSERT(buf->dtb_size == 0); -+ -+ continue; -+ } -+ -+ if (buf->dtb_xamot != NULL) { -+ ASSERT(!(buf->dtb_flags & DTRACEBUF_NOSWITCH)); -+ -+ vfree(buf->dtb_xamot); -+ buf->dtb_xamot = NULL; -+ } -+ -+ vfree(buf->dtb_tomax); -+ buf->dtb_size = 0; -+ buf->dtb_tomax = NULL; -+ } -+} -diff --git a/dtrace/dtrace_debug.h b/dtrace/dtrace_debug.h -new file mode 100644 -index 000000000000..a55fd1a0436f ---- /dev/null -+++ b/dtrace/dtrace_debug.h -@@ -0,0 +1,118 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Dynamic Tracing for Linux -+ * -+ * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#ifndef _DTRACE_DEBUG_H_ -+#define _DTRACE_DEBUG_H_ -+ -+#ifdef CONFIG_DT_DEBUG -+ -+/* -+ * Enable all output and use dynamic debug when supported. -+ */ -+# ifdef CONFIG_DYNAMIC_DEBUG -+ -+# define DT_DBG_AGG -+# define DT_DBG_BUF -+# define DT_DBG_DIF -+# define DT_DBG_DOF -+# define DT_DBG_ENABLE -+# define DT_DBG_IOCTL -+# define DT_DBG_PROBE -+# define DT_DBG_PROVIDER -+ -+# define dt_dbg_print(fmt, ...) pr_debug(fmt, ## __VA_ARGS__) -+ -+# else /* CONFIG_DYNAMIC_DEBUG */ -+ -+# undef DT_DBG_AGG -+# undef DT_DBG_BUF -+# undef DT_DBG_DIF -+# undef DT_DBG_DOF -+# undef DT_DBG_ENABLE -+# undef DT_DBG_IOCTL -+# undef DT_DBG_PROBE -+# undef DT_DBG_PROVIDER -+ -+# define dt_dbg_print(fmt, ...) pr_info(fmt, ## __VA_ARGS__) -+ -+# endif /* CONFIG_DYNAMIC_DEBUG */ -+ -+#else /* CONFIG_DT_DEBUG */ -+ -+# undef DT_DBG_AGG -+# undef DT_DBG_BUF -+# undef DT_DBG_DIF -+# undef DT_DBG_DOF -+# undef DT_DBG_ENABLE -+# undef DT_DBG_IOCTL -+# undef DT_DBG_PROBE -+# undef DT_DBG_PROVIDER -+ -+#endif /* CONFIG_DT_DEBUG */ -+ -+/* -+ * Here are the actual actions for the various debug cases. -+ */ -+#ifdef DT_DBG_AGG -+# define dt_dbg_agg(fmt, ...) dt_dbg_print(fmt, ## __VA_ARGS__) -+#else -+# define dt_dbg_agg(fmt, ...) -+#endif -+ -+#ifdef DT_DBG_BUF -+# define dt_dbg_buf(fmt, ...) dt_dbg_print(fmt, ## __VA_ARGS__) -+#else -+# define dt_dbg_buf(fmt, ...) -+#endif -+ -+#ifdef DT_DBG_DIF -+# define dt_dbg_dif(fmt, ...) dt_dbg_print(fmt, ## __VA_ARGS__) -+#else -+# define dt_dbg_dif(fmt, ...) -+#endif -+ -+#ifdef DT_DBG_DOF -+# define dt_dbg_dof(fmt, ...) dt_dbg_print(fmt, ## __VA_ARGS__) -+#else -+# define dt_dbg_dof(fmt, ...) -+#endif -+ -+#ifdef DT_DBG_ENABLE -+# define dt_dbg_enable(fmt, ...) dt_dbg_print(fmt, ## __VA_ARGS__) -+#else -+# define dt_dbg_enable(fmt, ...) -+#endif -+ -+#ifdef DT_DBG_IOCTL -+# define dt_dbg_ioctl(fmt, ...) dt_dbg_print(fmt, ## __VA_ARGS__) -+#else -+# define dt_dbg_ioctl(fmt, ...) -+#endif -+ -+#ifdef DT_DBG_PROBE -+# define dt_dbg_probe(fmt, ...) dt_dbg_print(fmt, ## __VA_ARGS__) -+#else -+# define dt_dbg_probe(fmt, ...) -+#endif -+ -+#ifdef DT_DBG_PROVIDER -+# define dt_dbg_prov(fmt, ...) dt_dbg_print(fmt, ## __VA_ARGS__) -+#else -+# define dt_dbg_prov(fmt, ...) -+#endif -+ -+#endif /* _DTRACE_DEBUG_H_ */ -diff --git a/dtrace/dtrace_dev.c b/dtrace/dtrace_dev.c -new file mode 100644 -index 000000000000..0e52c936b9e0 ---- /dev/null -+++ b/dtrace/dtrace_dev.c -@@ -0,0 +1,1599 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_dev.c -+ * DESCRIPTION: DTrace - Framework device driver -+ * -+ * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/delay.h> -+#include <dtrace/types.h> -+#include <linux/dtrace/ioctl.h> -+#include <linux/fs.h> -+#include <linux/jiffies.h> -+#include <linux/kernel.h> -+#include <linux/miscdevice.h> -+#include <linux/slab.h> -+#include <linux/vmalloc.h> -+#include <linux/uaccess.h> -+ -+#include "ctf_api.h" -+#include "dtrace.h" -+#include "dtrace_dev.h" -+ -+extern char *dtrace_helptrace_buffer; -+extern int dtrace_helptrace_bufsize; -+extern int dtrace_helptrace_enabled; -+ -+int dtrace_opens; -+int dtrace_err_verbose; -+ -+struct dtrace_pops dtrace_provider_ops = { -+ (void (*)(void *, const struct dtrace_probedesc *))dtrace_nullop, -+ (void (*)(void *, struct module *))dtrace_nullop, -+ (int (*)(void *, dtrace_id_t, void *))dtrace_enable_nullop, -+ (void (*)(void *, dtrace_id_t, void *))dtrace_nullop, -+ (void (*)(void *, dtrace_id_t, void *))dtrace_nullop, -+ (void (*)(void *, dtrace_id_t, void *))dtrace_nullop, -+ NULL, -+ NULL, -+ NULL, -+ (void (*)(void *, dtrace_id_t, void *))dtrace_nullop, -+ (void (*)(void *, struct module *))dtrace_nullop, -+}; -+ -+static size_t dtrace_retain_max = 1024; -+ -+struct dtrace_toxrange *dtrace_toxrange; -+int dtrace_toxranges; -+static int dtrace_toxranges_max; -+ -+struct kmem_cache *dtrace_state_cachep; -+ -+struct user_namespace *init_user_namespace; -+ -+static struct dtrace_pattr dtrace_provider_attr = { -+{ DTRACE_STABILITY_STABLE, DTRACE_STABILITY_STABLE, DTRACE_CLASS_COMMON }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_STABLE, DTRACE_STABILITY_STABLE, DTRACE_CLASS_COMMON }, -+{ DTRACE_STABILITY_STABLE, DTRACE_STABILITY_STABLE, DTRACE_CLASS_COMMON }, -+}; -+ -+DEFINE_MUTEX(dtrace_lock); -+ -+void dtrace_nullop(void) -+{ -+} -+ -+int dtrace_enable_nullop(void) -+{ -+ return 0; -+} -+ -+ -+#ifdef CONFIG_DT_DEBUG -+static void dtrace_ioctl_sizes(void) -+{ -+#define DBG_PRINT(x) dt_dbg_ioctl("Size of %s: %lx\n", #x, sizeof(x)) -+ DBG_PRINT(struct dtrace_providerdesc); -+ DBG_PRINT(struct dtrace_probedesc); -+ DBG_PRINT(struct dtrace_bufdesc); -+ DBG_PRINT(struct dtrace_eprobedesc); -+ DBG_PRINT(struct dtrace_argdesc); -+ DBG_PRINT(struct dtrace_conf); -+ DBG_PRINT(struct dtrace_status); -+ DBG_PRINT(processorid_t); -+ DBG_PRINT(struct dtrace_aggdesc); -+ DBG_PRINT(struct dtrace_fmtdesc); -+ DBG_PRINT(struct dof_hdr); -+#undef DBG_PRINT -+} -+ -+#endif -+ -+static int dtrace_open(struct inode *inode, struct file *file) -+{ -+ struct dtrace_state *state; -+ uint32_t priv; -+ kuid_t uid; -+ -+ dtrace_cred2priv(file->f_cred, &priv, &uid); -+ if (priv == DTRACE_PRIV_NONE) -+ return -EACCES; -+ -+#ifdef CONFIG_DT_DEBUG -+ dtrace_ioctl_sizes(); -+#endif -+ mutex_lock(&module_mutex); -+ mutex_lock(&dtrace_provider_lock); -+ dtrace_probe_provide(NULL, NULL); -+ mutex_unlock(&dtrace_provider_lock); -+ mutex_unlock(&module_mutex); -+ -+ mutex_lock(&cpu_lock); -+ mutex_lock(&dtrace_lock); -+ -+ /* -+ * Do not let a consumer continue if it is not possible to enable -+ * DTrace. -+ */ -+ if (dtrace_enable() != 0) { -+ mutex_unlock(&dtrace_lock); -+ mutex_unlock(&cpu_lock); -+ return -EBUSY; -+ } -+ -+ dtrace_opens++; -+ dtrace_membar_producer(); -+ -+ state = dtrace_state_create(file); -+ mutex_unlock(&cpu_lock); -+ -+ if (state == NULL) { -+ if (--dtrace_opens == 0 && dtrace_anon.dta_enabling == NULL) -+ dtrace_disable(); -+ mutex_unlock(&dtrace_lock); -+ -+ return -EAGAIN; -+ } -+ -+ file->private_data = state; -+ mutex_unlock(&dtrace_lock); -+ -+ return 0; -+} -+ -+static long dtrace_ioctl(struct file *file, -+ unsigned int cmd, unsigned long arg) -+{ -+ struct dtrace_state *state; -+ int rval; -+ void __user *argp = (void __user *)arg; -+ -+ state = (struct dtrace_state *) file->private_data; -+ if (state->dts_anon) { -+ ASSERT(dtrace_anon.dta_state == NULL); -+ state = state->dts_anon; -+ } -+ -+ switch (cmd) { -+ case DTRACEIOC_PROVIDER: { -+ struct dtrace_providerdesc pvd; -+ struct dtrace_provider *pvp; -+ -+ dt_dbg_ioctl("IOCTL PROVIDER (cmd %#x), argp %p\n", cmd, argp); -+ -+ if (copy_from_user(&pvd, argp, sizeof(pvd)) != 0) -+ return -EFAULT; -+ -+ pvd.dtvd_name[DTRACE_PROVNAMELEN - 1] = '\0'; -+ mutex_lock(&dtrace_provider_lock); -+ -+ for (pvp = dtrace_provider; pvp != NULL; pvp = pvp->dtpv_next) { -+ if (strcmp(pvp->dtpv_name, pvd.dtvd_name) == 0) -+ break; -+ } -+ -+ mutex_unlock(&dtrace_provider_lock); -+ -+ dt_dbg_ioctl(" Provider '%s' %sfound\n", -+ pvd.dtvd_name, pvp ? "" : "not "); -+ if (pvp == NULL) -+ return -ESRCH; -+ -+ memcpy(&pvd.dtvd_priv, &pvp->dtpv_priv, -+ sizeof(struct dtrace_ppriv)); -+ memcpy(&pvd.dtvd_attr, &pvp->dtpv_attr, -+ sizeof(struct dtrace_pattr)); -+ -+ if (copy_to_user(argp, &pvd, sizeof(pvd)) != 0) -+ return -EFAULT; -+ -+ return 0; -+ } -+ -+ case DTRACEIOC_EPROBE: { -+ struct dtrace_eprobedesc epdesc; -+ struct dtrace_ecb *ecb; -+ struct dtrace_action *act; -+ void *buf; -+ size_t size; -+ uint8_t *dest; -+ int nrecs; -+ -+ dt_dbg_ioctl("IOCTL EPROBE (cmd %#x), argp %p\n", cmd, argp); -+ -+ if (copy_from_user(&epdesc, argp, sizeof(epdesc)) != 0) -+ return -EFAULT; -+ -+ mutex_lock(&dtrace_lock); -+ -+ ecb = dtrace_epid2ecb(state, epdesc.dtepd_epid); -+ if (ecb == NULL) { -+ mutex_unlock(&dtrace_lock); -+ return -EINVAL; -+ } -+ -+ if (ecb->dte_probe == NULL) { -+ mutex_unlock(&dtrace_lock); -+ return -EINVAL; -+ } -+ -+ epdesc.dtepd_probeid = ecb->dte_probe->dtpr_id; -+ epdesc.dtepd_uarg = ecb->dte_uarg; -+ epdesc.dtepd_size = ecb->dte_size; -+ -+ nrecs = epdesc.dtepd_nrecs; -+ epdesc.dtepd_nrecs = 0; -+ for (act = ecb->dte_action; act != NULL; act = act->dta_next) { -+ if (DTRACEACT_ISAGG(act->dta_kind) || act->dta_intuple) -+ continue; -+ -+ epdesc.dtepd_nrecs++; -+ } -+ -+ /* -+ * Now that we have the size, we need to allocate a temporary -+ * buffer in which to store the complete description. We need -+ * the temporary buffer to be able to drop dtrace_lock() -+ * across the copy_to_user(), below. -+ */ -+ size = sizeof(struct dtrace_eprobedesc) + -+ (epdesc.dtepd_nrecs * sizeof(struct dtrace_recdesc)); -+ -+ buf = vmalloc(size); -+ if (buf == NULL) -+ return -ENOMEM; -+ -+ dest = buf; -+ memcpy(dest, &epdesc, sizeof(epdesc)); -+ dest += offsetof(struct dtrace_eprobedesc, dtepd_rec[0]); -+ -+ for (act = ecb->dte_action; act != NULL; act = act->dta_next) { -+ if (DTRACEACT_ISAGG(act->dta_kind) || act->dta_intuple) -+ continue; -+ -+ if (nrecs-- == 0) -+ break; -+ -+ memcpy(dest, &act->dta_rec, -+ sizeof(struct dtrace_recdesc)); -+ dest += sizeof(struct dtrace_recdesc); -+ } -+ -+ mutex_unlock(&dtrace_lock); -+ -+ if (copy_to_user(argp, buf, -+ (uintptr_t)(dest - (uint8_t *)buf)) != 0) { -+ vfree(buf); -+ return -EFAULT; -+ } -+ -+ vfree(buf); -+ return 0; -+ } -+ -+ case DTRACEIOC_AGGDESC: { -+ struct dtrace_aggdesc aggdesc; -+ struct dtrace_action *act; -+ struct dtrace_aggregation *agg; -+ int nrecs; -+ uint32_t offs; -+ struct dtrace_recdesc *lrec; -+ void *buf; -+ size_t size; -+ uint8_t *dest; -+ -+ dt_dbg_ioctl("IOCTL AGGDESC (cmd %#x), argp %p\n", cmd, argp); -+ -+ if (copy_from_user(&aggdesc, argp, sizeof(aggdesc)) != 0) -+ return -EFAULT; -+ -+ mutex_lock(&dtrace_lock); -+ -+ agg = dtrace_aggid2agg(state, aggdesc.dtagd_id); -+ if (agg == NULL) { -+ mutex_unlock(&dtrace_lock); -+ return -EINVAL; -+ } -+ -+ aggdesc.dtagd_epid = agg->dtag_ecb->dte_epid; -+ -+ nrecs = aggdesc.dtagd_nrecs; -+ aggdesc.dtagd_nrecs = 0; -+ -+ offs = agg->dtag_base; -+ lrec = &agg->dtag_action.dta_rec; -+ aggdesc.dtagd_size = lrec->dtrd_offset + lrec->dtrd_size - -+ offs; -+ -+ for (act = agg->dtag_first; ; act = act->dta_next) { -+ ASSERT(act->dta_intuple || -+ DTRACEACT_ISAGG(act->dta_kind)); -+ -+ /* -+ * If this action has a record size of zero, it -+ * denotes an argument to the aggregating action. -+ * Because the presence of this record doesn't (or -+ * shouldn't) affect the way the data is interpreted, -+ * we don't copy it out to save user-level the -+ * confusion of dealing with a zero-length record. -+ */ -+ if (act->dta_rec.dtrd_size == 0) { -+ ASSERT(agg->dtag_hasarg); -+ continue; -+ } -+ -+ aggdesc.dtagd_nrecs++; -+ -+ if (act == &agg->dtag_action) -+ break; -+ } -+ -+ /* -+ * Now that we have the size, we need to allocate a temporary -+ * buffer in which to store the complete description. We need -+ * the temporary buffer to be able to drop dtrace_lock() -+ * across the copyout(), below. -+ */ -+ size = sizeof(struct dtrace_aggdesc) + -+ (aggdesc.dtagd_nrecs * sizeof(struct dtrace_recdesc)); -+ -+ buf = vmalloc(size); -+ if (buf == NULL) -+ return -ENOMEM; -+ -+ dest = buf; -+ memcpy(dest, &aggdesc, sizeof(aggdesc)); -+ dest += offsetof(struct dtrace_aggdesc, dtagd_rec[0]); -+ -+ for (act = agg->dtag_first; ; act = act->dta_next) { -+ struct dtrace_recdesc rec = act->dta_rec; -+ -+ /* -+ * See the comment in the above loop for why we pass -+ * over zero-length records. -+ */ -+ if (rec.dtrd_size == 0) { -+ ASSERT(agg->dtag_hasarg); -+ continue; -+ } -+ -+ if (nrecs-- == 0) -+ break; -+ -+ rec.dtrd_offset -= offs; -+ memcpy(dest, &rec, sizeof(rec)); -+ dest += sizeof(struct dtrace_recdesc); -+ -+ if (act == &agg->dtag_action) -+ break; -+ } -+ -+ mutex_unlock(&dtrace_lock); -+ -+ if (copy_to_user(argp, buf, -+ (uintptr_t)(dest - (uint8_t *)buf)) != 0) { -+ vfree(buf); -+ return -EFAULT; -+ } -+ -+ vfree(buf); -+ return 0; -+ } -+ -+ case DTRACEIOC_ENABLE: { -+ struct dof_hdr *dof; -+ struct dtrace_enabling *enab = NULL; -+ struct dtrace_vstate *vstate; -+ int err = 0; -+ int rv; -+ -+ dt_dbg_ioctl("IOCTL ENABLE (cmd %#x), argp %p\n", cmd, argp); -+ -+ rv = 0; -+ -+ /* -+ * If a NULL argument has been passed, we take this as our -+ * cue to reevaluate our enablings. -+ */ -+ if (argp == NULL) { -+ dtrace_enabling_matchall(); -+ -+ return 0; -+ } -+ -+ dof = dtrace_dof_copyin(argp, &rval); -+ if (dof == NULL) -+ return rval; -+ -+ mutex_lock(&cpu_lock); -+ mutex_lock(&dtrace_lock); -+ vstate = &state->dts_vstate; -+ -+ if (state->dts_activity != DTRACE_ACTIVITY_INACTIVE) { -+ mutex_unlock(&dtrace_lock); -+ mutex_unlock(&cpu_lock); -+ dtrace_dof_destroy(dof); -+ return -EBUSY; -+ } -+ -+ if (dtrace_dof_slurp(dof, vstate, file->f_cred, &enab, 0, -+ TRUE) != 0) { -+ mutex_unlock(&dtrace_lock); -+ mutex_unlock(&cpu_lock); -+ dtrace_dof_destroy(dof); -+ return -EINVAL; -+ } -+ -+ rval = dtrace_dof_options(dof, state); -+ if (rval != 0) { -+ dtrace_enabling_destroy(enab); -+ mutex_unlock(&dtrace_lock); -+ mutex_unlock(&cpu_lock); -+ dtrace_dof_destroy(dof); -+ return rval; -+ } -+ -+ err = dtrace_enabling_match(enab, &rv); -+ if (err == 0) -+ err = dtrace_enabling_retain(enab); -+ else -+ dtrace_enabling_destroy(enab); -+ -+ mutex_unlock(&dtrace_lock); -+ mutex_unlock(&cpu_lock); -+ dtrace_dof_destroy(dof); -+ -+ return err == 0 ? rv : err; -+ } -+ -+ case DTRACEIOC_REPLICATE: { -+ struct dtrace_repldesc desc; -+ struct dtrace_probedesc *match = &desc.dtrpd_match; -+ struct dtrace_probedesc *create = &desc.dtrpd_create; -+ int err; -+ -+ dt_dbg_ioctl("IOCTL REPLICATE (cmd %#x), argp %p\n", -+ cmd, argp); -+ -+ if (copy_from_user(&desc, argp, sizeof(desc)) != 0) -+ return -EFAULT; -+ -+ match->dtpd_provider[DTRACE_PROVNAMELEN - 1] = '\0'; -+ match->dtpd_mod[DTRACE_MODNAMELEN - 1] = '\0'; -+ match->dtpd_func[DTRACE_FUNCNAMELEN - 1] = '\0'; -+ match->dtpd_name[DTRACE_NAMELEN - 1] = '\0'; -+ -+ create->dtpd_provider[DTRACE_PROVNAMELEN - 1] = '\0'; -+ create->dtpd_mod[DTRACE_MODNAMELEN - 1] = '\0'; -+ create->dtpd_func[DTRACE_FUNCNAMELEN - 1] = '\0'; -+ create->dtpd_name[DTRACE_NAMELEN - 1] = '\0'; -+ -+ mutex_lock(&dtrace_lock); -+ err = dtrace_enabling_replicate(state, match, create); -+ mutex_unlock(&dtrace_lock); -+ -+ return err; -+ } -+ -+ case DTRACEIOC_PROBEMATCH: -+ case DTRACEIOC_PROBES: { -+ int id; -+ struct dtrace_probe *probe = NULL; -+ struct dtrace_probedesc desc; -+ struct dtrace_probekey pkey; -+ uint32_t priv; -+ kuid_t uid; -+ -+ dt_dbg_ioctl("IOCTL %s (cmd %#x), argp %p\n", -+ cmd == DTRACEIOC_PROBES ? "PROBES" -+ : "PROBEMATCH", -+ cmd, argp); -+ -+ if (copy_from_user(&desc, argp, sizeof(desc)) != 0) -+ return -EFAULT; -+ -+ desc.dtpd_provider[DTRACE_PROVNAMELEN - 1] = '\0'; -+ desc.dtpd_mod[DTRACE_MODNAMELEN - 1] = '\0'; -+ desc.dtpd_func[DTRACE_FUNCNAMELEN - 1] = '\0'; -+ desc.dtpd_name[DTRACE_NAMELEN - 1] = '\0'; -+ dt_dbg_ioctl(" Probe ID %d %s:%s:%s:%s\n", -+ desc.dtpd_id, desc.dtpd_provider, desc.dtpd_mod, -+ desc.dtpd_func, desc.dtpd_name); -+ -+ /* -+ * Before we attempt to match this probe, we want to give -+ * all providers the opportunity to provide it. -+ */ -+ if (desc.dtpd_id == DTRACE_IDNONE) { -+ mutex_lock(&module_mutex); -+ mutex_lock(&dtrace_provider_lock); -+ dtrace_probe_provide(&desc, NULL); -+ mutex_unlock(&dtrace_provider_lock); -+ mutex_unlock(&module_mutex); -+ } -+ -+ if (cmd == DTRACEIOC_PROBEMATCH) { -+ dtrace_probekey(&desc, &pkey); -+ pkey.dtpk_id = DTRACE_IDNONE; -+ } -+ -+ dtrace_cred2priv(file->f_cred, &priv, &uid); -+ -+ mutex_lock(&dtrace_lock); -+ -+ id = desc.dtpd_id; -+ if (cmd == DTRACEIOC_PROBEMATCH) { -+ int m = 0; -+ -+ while ((probe = dtrace_probe_get_next(&id)) -+ != NULL) { -+ m = dtrace_match_probe(probe, &pkey, priv, uid); -+ if (m) -+ break; -+ -+ id++; -+ } -+ -+ if (m < 0) { -+ mutex_unlock(&dtrace_lock); -+ return -EINVAL; -+ } -+ } else { -+ while ((probe = dtrace_probe_get_next(&id)) -+ != NULL) { -+ if (dtrace_match_priv(probe, priv, uid)) -+ break; -+ -+ id++; -+ } -+ } -+ -+ if (probe == NULL) { -+ mutex_unlock(&dtrace_lock); -+ return -ESRCH; -+ } -+ -+ dtrace_probe_description(probe, &desc); -+ mutex_unlock(&dtrace_lock); -+ -+ if (copy_to_user(argp, &desc, sizeof(desc)) != 0) -+ return -EFAULT; -+ -+ return 0; -+ } -+ -+ case DTRACEIOC_PROBEARG: { -+ struct dtrace_argdesc desc; -+ struct dtrace_probe *probe; -+ struct dtrace_provider *prov; -+ -+ dt_dbg_ioctl("IOCTL PROBEARG (cmd %#x), argp %p\n", cmd, argp); -+ -+ if (copy_from_user(&desc, argp, sizeof(desc)) != 0) -+ return -EFAULT; -+ -+ if (desc.dtargd_id == DTRACE_IDNONE) -+ return -EINVAL; -+ -+ if (desc.dtargd_ndx == DTRACE_ARGNONE) -+ return -EINVAL; -+ -+ mutex_lock(&module_mutex); -+ mutex_lock(&dtrace_provider_lock); -+ mutex_lock(&dtrace_lock); -+ -+ probe = dtrace_probe_lookup_id(desc.dtargd_id); -+ if (probe == NULL) { -+ mutex_unlock(&dtrace_lock); -+ mutex_unlock(&dtrace_provider_lock); -+ mutex_unlock(&module_mutex); -+ -+ return -EINVAL; -+ } -+ -+ mutex_unlock(&dtrace_lock); -+ -+ prov = probe->dtpr_provider; -+ -+ if (prov->dtpv_pops.dtps_getargdesc == NULL) { -+ /* -+ * There isn't any typed information for this probe. -+ * Set the argument number to DTRACE_ARGNONE. -+ */ -+ desc.dtargd_ndx = DTRACE_ARGNONE; -+ } else { -+ desc.dtargd_native[0] = '\0'; -+ desc.dtargd_xlate[0] = '\0'; -+ desc.dtargd_mapping = desc.dtargd_ndx; -+ -+ prov->dtpv_pops.dtps_getargdesc( -+ prov->dtpv_arg, probe->dtpr_id, -+ probe->dtpr_arg, &desc); -+ } -+ -+ mutex_unlock(&dtrace_provider_lock); -+ mutex_unlock(&module_mutex); -+ -+ if (copy_to_user(argp, &desc, sizeof(desc)) != 0) -+ return -EFAULT; -+ -+ return 0; -+ } -+ -+ case DTRACEIOC_GO: { -+ processorid_t cpuid; -+ -+ dt_dbg_ioctl("IOCTL GO (cmd %#x), argp %p\n", cmd, argp); -+ -+ rval = dtrace_state_go(state, &cpuid); -+ -+ if (rval != 0) -+ return rval; -+ -+ if (copy_to_user(argp, &cpuid, sizeof(cpuid)) != 0) -+ return -EFAULT; -+ -+ return 0; -+ } -+ -+ case DTRACEIOC_STOP: { -+ processorid_t cpuid; -+ -+ dt_dbg_ioctl("IOCTL STOP (cmd %#x), argp %p\n", cmd, argp); -+ -+ mutex_lock(&dtrace_lock); -+ rval = dtrace_state_stop(state, &cpuid); -+ mutex_unlock(&dtrace_lock); -+ -+ if (rval != 0) -+ return rval; -+ -+ if (copy_to_user(argp, &cpuid, sizeof(cpuid)) != 0) -+ return -EFAULT; -+ -+ return 0; -+ } -+ -+ case DTRACEIOC_DOFGET: { -+ struct dof_hdr hdr, *dof; -+ uint64_t len; -+ -+ dt_dbg_ioctl("IOCTL DOFGET (cmd %#x), argp %p\n", cmd, argp); -+ -+ if (copy_from_user(&hdr, argp, sizeof(hdr)) != 0) -+ return -EFAULT; -+ -+ mutex_lock(&dtrace_lock); -+ dof = dtrace_dof_create(state); -+ mutex_unlock(&dtrace_lock); -+ if (dof == NULL) -+ return -ENOMEM; -+ -+ len = min(hdr.dofh_loadsz, dof->dofh_loadsz); -+ rval = copy_to_user(argp, dof, len); -+ dtrace_dof_destroy(dof); -+ -+ return rval == 0 ? 0 : -EFAULT; -+ } -+ -+ case DTRACEIOC_AGGSNAP: -+ case DTRACEIOC_BUFSNAP: { -+ struct dtrace_bufdesc desc; -+ caddr_t cached; -+ struct dtrace_buffer *buf; -+ -+ dt_dbg_ioctl("IOCTL %s (cmd %#x), argp %p\n", -+ cmd == DTRACEIOC_AGGSNAP ? "AGGSNAP" -+ : "BUFSNAP", -+ cmd, argp); -+ -+ if (copy_from_user(&desc, argp, sizeof(desc)) != 0) -+ return -EFAULT; -+ -+ if (desc.dtbd_cpu < 0 || desc.dtbd_cpu >= NR_CPUS) -+ return -EINVAL; -+ -+ mutex_lock(&dtrace_lock); -+ -+ if (cmd == DTRACEIOC_BUFSNAP) -+ buf = &state->dts_buffer[desc.dtbd_cpu]; -+ else -+ buf = &state->dts_aggbuffer[desc.dtbd_cpu]; -+ -+ if (buf->dtb_flags & (DTRACEBUF_RING | DTRACEBUF_FILL)) { -+ size_t sz = buf->dtb_offset; -+ -+ if (state->dts_activity != DTRACE_ACTIVITY_STOPPED) { -+ mutex_unlock(&dtrace_lock); -+ return -EBUSY; -+ } -+ -+ /* -+ * If this buffer has already been consumed, we're -+ * going to indicate that there's nothing left here -+ * to consume. -+ */ -+ if (buf->dtb_flags & DTRACEBUF_CONSUMED) { -+ mutex_unlock(&dtrace_lock); -+ -+ desc.dtbd_size = 0; -+ desc.dtbd_drops = 0; -+ desc.dtbd_errors = 0; -+ desc.dtbd_oldest = 0; -+ sz = sizeof(desc); -+ -+ if (copy_to_user(argp, &desc, sz) != 0) -+ return -EFAULT; -+ -+ return 0; -+ } -+ -+ /* -+ * If this is a ring buffer that has wrapped, we want -+ * to copy the whole thing out. -+ */ -+ if (buf->dtb_flags & DTRACEBUF_WRAPPED) { -+ dtrace_buffer_polish(buf); -+ sz = buf->dtb_size; -+ } -+ -+ if (copy_to_user(desc.dtbd_data, buf->dtb_tomax, -+ sz) != 0) { -+ mutex_unlock(&dtrace_lock); -+ return -EFAULT; -+ } -+ -+ desc.dtbd_size = sz; -+ desc.dtbd_drops = buf->dtb_drops; -+ desc.dtbd_errors = buf->dtb_errors; -+ desc.dtbd_oldest = buf->dtb_xamot_offset; -+ -+ mutex_unlock(&dtrace_lock); -+ -+ if (copy_to_user(argp, &desc, sizeof(desc)) != 0) -+ return -EFAULT; -+ -+ buf->dtb_flags |= DTRACEBUF_CONSUMED; -+ -+ return 0; -+ } -+ -+ if (buf->dtb_tomax == NULL) { -+ ASSERT(buf->dtb_xamot == NULL); -+ mutex_unlock(&dtrace_lock); -+ return -ENOENT; -+ } -+ -+ cached = buf->dtb_tomax; -+ -+ dtrace_xcall(desc.dtbd_cpu, -+ (dtrace_xcall_t)dtrace_buffer_switch, buf); -+ -+ state->dts_errors += buf->dtb_xamot_errors; -+ -+ /* -+ * If the buffers did not actually switch, then the cross call -+ * did not take place -- presumably because the given CPU is -+ * not in the ready set. If this is the case, we'll return -+ * ENOENT. -+ */ -+ if (buf->dtb_tomax == cached) { -+ ASSERT(buf->dtb_xamot != cached); -+ mutex_unlock(&dtrace_lock); -+ return -ENOENT; -+ } -+ -+ ASSERT(cached == buf->dtb_xamot); -+ -+ /* -+ * We have our snapshot; now copy it out. -+ */ -+ if (copy_to_user(desc.dtbd_data, buf->dtb_xamot, -+ buf->dtb_xamot_offset) != 0) { -+ mutex_unlock(&dtrace_lock); -+ return -EFAULT; -+ } -+ -+ desc.dtbd_size = buf->dtb_xamot_offset; -+ desc.dtbd_drops = buf->dtb_xamot_drops; -+ desc.dtbd_errors = buf->dtb_xamot_errors; -+ desc.dtbd_oldest = 0; -+ -+ mutex_unlock(&dtrace_lock); -+ -+ /* -+ * Finally, copy out the buffer description. -+ */ -+ if (copy_to_user(argp, &desc, sizeof(desc)) != 0) -+ return -EFAULT; -+ -+ return 0; -+ } -+ -+ case DTRACEIOC_CONF: { -+ struct dtrace_conf conf; -+ -+ dt_dbg_ioctl("IOCTL CONF (cmd %#x), argp %p\n", cmd, argp); -+ -+ memset(&conf, 0, sizeof(conf)); -+ conf.dtc_difversion = DIF_VERSION; -+ conf.dtc_difintregs = DIF_DIR_NREGS; -+ conf.dtc_diftupregs = DIF_DTR_NREGS; -+ conf.dtc_ctfmodel = CTF_MODEL_NATIVE; -+ conf.dtc_maxbufs = nr_cpu_ids; -+ -+ if (copy_to_user(argp, &conf, sizeof(conf)) != 0) -+ return -EFAULT; -+ -+ return 0; -+ } -+ -+ case DTRACEIOC_STATUS: { -+ struct dtrace_status stat; -+ struct dtrace_dstate *dstate; -+ int i, j; -+ uint64_t nerrs; -+ -+ dt_dbg_ioctl("IOCTL STATUS (cmd %#x), argp %p\n", cmd, argp); -+ -+ /* -+ * See the comment in dtrace_state_deadman() for the reason -+ * for setting dts_laststatus to UINT64_MAX before setting -+ * it to the correct value. -+ */ -+ state->dts_laststatus = ns_to_ktime(UINT64_MAX); -+ dtrace_membar_producer(); -+ state->dts_laststatus = dtrace_gethrtime(); -+ -+ memset(&stat, 0, sizeof(stat)); -+ -+ mutex_lock(&dtrace_lock); -+ -+ if (state->dts_activity == DTRACE_ACTIVITY_INACTIVE) { -+ mutex_unlock(&dtrace_lock); -+ return -ENOENT; -+ } -+ -+ if (state->dts_activity == DTRACE_ACTIVITY_DRAINING) -+ stat.dtst_exiting = 1; -+ -+ nerrs = state->dts_errors; -+ dstate = &state->dts_vstate.dtvs_dynvars; -+ -+ for (i = 0; i < NR_CPUS; i++) { -+ struct dtrace_dstate_percpu *dcpu; -+ -+ dcpu = &dstate->dtds_percpu[i]; -+ stat.dtst_dyndrops += dcpu->dtdsc_drops; -+ stat.dtst_dyndrops_dirty += dcpu->dtdsc_dirty_drops; -+ stat.dtst_dyndrops_rinsing += dcpu->dtdsc_rinsing_drops; -+ -+ if (state->dts_buffer[i].dtb_flags & DTRACEBUF_FULL) -+ stat.dtst_filled++; -+ -+ nerrs += state->dts_buffer[i].dtb_errors; -+ -+ for (j = 0; j < state->dts_nspeculations; j++) { -+ struct dtrace_speculation *spec; -+ struct dtrace_buffer *buf; -+ -+ spec = &state->dts_speculations[j]; -+ buf = &spec->dtsp_buffer[i]; -+ stat.dtst_specdrops += buf->dtb_xamot_drops; -+ } -+ } -+ -+ stat.dtst_specdrops_busy = state->dts_speculations_busy; -+ stat.dtst_specdrops_unavail = state->dts_speculations_unavail; -+ stat.dtst_stkstroverflows = state->dts_stkstroverflows; -+ stat.dtst_dblerrors = state->dts_dblerrors; -+ stat.dtst_killed = (state->dts_activity == -+ DTRACE_ACTIVITY_KILLED); -+ stat.dtst_errors = nerrs; -+ -+ mutex_unlock(&dtrace_lock); -+ -+ if (copy_to_user(argp, &stat, sizeof(stat)) != 0) -+ return -EFAULT; -+ -+ return 0; -+ } -+ -+ case DTRACEIOC_FORMAT: { -+ struct dtrace_fmtdesc fmt; -+ char *str; -+ int len; -+ -+ dt_dbg_ioctl("IOCTL FORMAT (cmd %#x), argp %p\n", cmd, argp); -+ -+ if (copy_from_user(&fmt, argp, sizeof(fmt)) != 0) -+ return -EFAULT; -+ -+ mutex_lock(&dtrace_lock); -+ -+ if (fmt.dtfd_format == 0 || -+ fmt.dtfd_format > state->dts_nformats) { -+ mutex_unlock(&dtrace_lock); -+ return -EINVAL; -+ } -+ -+ /* -+ * Format strings are allocated contiguously and they are -+ * never freed; if a format index is less than the number -+ * of formats, we can assert that the format map is non-NULL -+ * and that the format for the specified index is non-NULL. -+ */ -+ ASSERT(state->dts_formats != NULL); -+ str = state->dts_formats[fmt.dtfd_format - 1]; -+ ASSERT(str != NULL); -+ -+ len = strlen(str) + 1; -+ -+ if (len > fmt.dtfd_length) { -+ fmt.dtfd_length = len; -+ -+ if (copy_to_user(argp, &fmt, sizeof(fmt)) != 0) { -+ mutex_unlock(&dtrace_lock); -+ return -EINVAL; -+ } -+ } else { -+ if (copy_to_user(fmt.dtfd_string, str, len) != 0) { -+ mutex_unlock(&dtrace_lock); -+ return -EINVAL; -+ } -+ } -+ -+ mutex_unlock(&dtrace_lock); -+ -+ return 0; -+ } -+ -+ default: -+ dt_dbg_ioctl("IOCTL ??? (cmd %#x), argp %p\n", -+ cmd, argp); -+ break; -+ } -+ -+ return -ENOTTY; -+} -+ -+static int dtrace_close(struct inode *inode, struct file *file) -+{ -+ struct dtrace_state *state = file->private_data; -+ -+ mutex_lock(&cpu_lock); -+ mutex_lock(&dtrace_lock); -+ -+ /* -+ * If there is anonymous state, destroy that first. -+ */ -+ if (state->dts_anon) { -+ ASSERT(dtrace_anon.dta_state == NULL); -+ dtrace_state_destroy(state->dts_anon); -+ } -+ -+ dtrace_state_destroy(state); -+ ASSERT(dtrace_opens > 0); -+ -+ if (--dtrace_opens == 0 && dtrace_anon.dta_enabling == NULL) -+ dtrace_disable(); -+ -+ mutex_unlock(&dtrace_lock); -+ mutex_unlock(&cpu_lock); -+ -+ return 0; -+} -+ -+static int dtrace_helper_open(struct inode *inode, struct file *file) -+{ -+ return 0; -+} -+ -+static long dtrace_helper_ioctl(struct file *file, -+ unsigned int cmd, unsigned long arg) -+{ -+ int rval; -+ struct dof_helper help, *dhp = NULL; -+ void __user *argp = (void __user *)arg; -+ -+ switch (cmd) { -+ case DTRACEHIOC_ADDDOF: -+ dt_dbg_ioctl("Helper IOCTL ADDDOF (cmd %#x), argp %p\n", -+ cmd, argp); -+ -+ if (copy_from_user(&help, argp, sizeof(help)) != 0) { -+ dtrace_dof_error(NULL, "failed to copy DOF helper"); -+ return -EFAULT; -+ } -+ -+ dhp = &help; -+ argp = (void __user *)help.dofhp_dof; -+ -+ /* fallthrough */ -+ -+ case DTRACEHIOC_ADD: { -+ struct dof_hdr *dof = dtrace_dof_copyin(argp, &rval); -+ -+ if (dof == NULL) -+ return rval; -+ -+ if (cmd == DTRACEHIOC_ADD) -+ dt_dbg_ioctl("Helper IOCTL ADD (cmd %#x), argp %p\n", -+ cmd, argp); -+ -+ mutex_lock(&dtrace_lock); -+ -+ /* -+ * The dtrace_helper_slurp() routine takes responsibility for -+ * the dof -- it may free it now, or it may save it and free it -+ * later. -+ */ -+ rval = dtrace_helper_slurp(dof, dhp); -+ if (rval == -1) -+ rval = -EINVAL; -+ -+ mutex_unlock(&dtrace_lock); -+ -+ dt_dbg_ioctl("Helper IOCTL %s returning %d\n", -+ cmd == DTRACEHIOC_ADD ? "ADD" -+ : "ADDDOF", -+ rval); -+ -+ return rval; -+ } -+ -+ case DTRACEHIOC_REMOVE: -+ dt_dbg_ioctl("Helper IOCTL REMOVE (cmd %#x), argp %p\n", -+ cmd, argp); -+ -+ mutex_lock(&dtrace_lock); -+ -+ rval = dtrace_helper_destroygen((uintptr_t)argp); -+ -+ mutex_unlock(&dtrace_lock); -+ -+ dt_dbg_ioctl("Helper IOCTL REMOVE returning %d\n", rval); -+ -+ return rval; -+ default: -+ dt_dbg_ioctl("Helper IOCTL ??? (cmd %#x), argp %p\n", -+ cmd, argp); -+ break; -+ } -+ -+ return -ENOTTY; -+} -+ -+static int dtrace_helper_close(struct inode *inode, struct file *file) -+{ -+ return 0; -+} -+ -+static const struct file_operations dtrace_fops = { -+ .owner = THIS_MODULE, -+ .unlocked_ioctl = dtrace_ioctl, -+ .open = dtrace_open, -+ .release = dtrace_close, -+}; -+ -+static const struct file_operations helper_fops = { -+ .owner = THIS_MODULE, -+ .unlocked_ioctl = dtrace_helper_ioctl, -+ .compat_ioctl = dtrace_helper_ioctl, -+ .open = dtrace_helper_open, -+ .release = dtrace_helper_close, -+}; -+ -+static struct miscdevice dtrace_dev = { -+ .minor = DT_DEV_DTRACE_MINOR, -+ .name = "dtrace", -+ .nodename = "dtrace/dtrace", -+ .fops = &dtrace_fops, -+}; -+ -+static struct miscdevice helper_dev = { -+ .minor = DT_DEV_HELPER_MINOR, -+ .name = "helper", -+ .nodename = "dtrace/helper", -+ .fops = &helper_fops, -+}; -+ -+static void dtrace_module_loaded(struct module *mp) -+{ -+ struct dtrace_provider *prv; -+ -+ mutex_lock(&module_mutex); -+ mutex_lock(&dtrace_provider_lock); -+ -+ /* -+ * Give all providers a chance to register probes for this module. -+ */ -+ for (prv = dtrace_provider; prv != NULL; prv = prv->dtpv_next) -+ prv->dtpv_pops.dtps_provide_module(prv->dtpv_arg, mp); -+ -+ mutex_unlock(&dtrace_provider_lock); -+ mutex_unlock(&module_mutex); -+ -+ /* -+ * If we have any retained enablings, we need to match against them. -+ */ -+ mutex_lock(&dtrace_lock); -+ -+ if (dtrace_retained == NULL) { -+ mutex_unlock(&dtrace_lock); -+ return; -+ } -+ -+ mutex_unlock(&dtrace_lock); -+ dtrace_enabling_matchall(); -+} -+ -+static void dtrace_module_unloaded(struct module *mp) -+{ -+ struct dtrace_probe template, *probe, *first, *next; -+ struct dtrace_provider *prv; -+ -+ template.dtpr_mod = mp->name; -+ -+ mutex_lock(&module_mutex); -+ mutex_lock(&dtrace_provider_lock); -+ mutex_lock(&dtrace_lock); -+ -+ if (dtrace_bymod == NULL) { -+ /* -+ * The DTrace module is loaded (obviously) but not attached; -+ * we don't have any work to do. -+ */ -+ mutex_unlock(&dtrace_lock); -+ mutex_unlock(&dtrace_provider_lock); -+ mutex_unlock(&module_mutex); -+ return; -+ } -+ -+ for (probe = first = dtrace_hash_lookup(dtrace_bymod, &template); -+ probe != NULL; probe = probe->dtpr_nextmod) { -+ if (probe->dtpr_ecb != NULL) { -+ mutex_unlock(&dtrace_lock); -+ mutex_unlock(&dtrace_provider_lock); -+ mutex_unlock(&module_mutex); -+ -+ /* -+ * This shouldn't _actually_ be possible -- we're -+ * unloading a module that has an enabled probe in it. -+ * (It's normally up to the provider to make sure that -+ * this can't happen.) However, because dtps_enable() -+ * doesn't have a failure mode, there can be an -+ * enable/unload race. Upshot: we don't want to -+ * assert, but we're not going to disable the -+ * probe, either. -+ */ -+ if (dtrace_err_verbose) { -+ pr_warn("unloaded module '%s' " -+ "had enabled probes", mp->name); -+ } -+ -+ return; -+ } -+ } -+ -+ probe = first; -+ -+ for (first = NULL; probe != NULL; probe = next) { -+ dtrace_probe_remove_id(probe->dtpr_id); -+ -+ next = probe->dtpr_nextmod; -+ dtrace_hash_remove(dtrace_bymod, probe); -+ dtrace_hash_remove(dtrace_byfunc, probe); -+ dtrace_hash_remove(dtrace_byname, probe); -+ -+ if (first == NULL) { -+ first = probe; -+ probe->dtpr_nextmod = NULL; -+ } else { -+ probe->dtpr_nextmod = first; -+ first = probe; -+ } -+ } -+ -+ /* -+ * We've removed all of the module's probes from the hash chains and -+ * from the probe array. Now issue a dtrace_sync() to be sure that -+ * everyone has cleared out from any probe array processing. -+ */ -+ dtrace_sync(); -+ -+ for (probe = first; probe != NULL; probe = first) { -+ first = probe->dtpr_nextmod; -+ prv = probe->dtpr_provider; -+ prv->dtpv_pops.dtps_destroy(prv->dtpv_arg, probe->dtpr_id, -+ probe->dtpr_arg); -+ kfree(probe->dtpr_mod); -+ kfree(probe->dtpr_func); -+ kfree(probe->dtpr_name); -+ kfree(probe); -+ } -+ -+ /* -+ * Notify providers to cleanup per-module data for this module. -+ */ -+ for (prv = dtrace_provider; prv != NULL; prv = prv->dtpv_next) -+ if (prv->dtpv_pops.dtps_destroy_module != NULL) -+ prv->dtpv_pops.dtps_destroy_module(prv->dtpv_arg, mp); -+ -+ mutex_unlock(&dtrace_lock); -+ mutex_unlock(&dtrace_provider_lock); -+ mutex_unlock(&module_mutex); -+} -+ -+/* -+ * Register a toxic range. -+ */ -+static void dtrace_toxrange_add(uintptr_t base, uintptr_t limit) -+{ -+ if (dtrace_toxranges >= dtrace_toxranges_max) { -+ int osize, nsize; -+ struct dtrace_toxrange *range; -+ -+ osize = dtrace_toxranges_max * sizeof(struct dtrace_toxrange); -+ -+ if (osize == 0) { -+ ASSERT(dtrace_toxrange == NULL); -+ ASSERT(dtrace_toxranges_max == 0); -+ -+ dtrace_toxranges_max = 1; -+ } else -+ dtrace_toxranges_max <<= 1; -+ -+ nsize = dtrace_toxranges_max * sizeof(struct dtrace_toxrange); -+ range = vzalloc(nsize); -+ if (range == NULL) { -+ pr_warn("Failed to add toxic range: out of memory\n"); -+ return; -+ } -+ -+ if (dtrace_toxrange != NULL) { -+ ASSERT(osize != 0); -+ -+ memcpy(range, dtrace_toxrange, osize); -+ vfree(dtrace_toxrange); -+ } -+ -+ dtrace_toxrange = range; -+ } -+ -+ ASSERT(dtrace_toxrange[dtrace_toxranges].dtt_base == (uintptr_t)NULL); -+ ASSERT(dtrace_toxrange[dtrace_toxranges].dtt_limit == (uintptr_t)NULL); -+ -+ dtrace_toxrange[dtrace_toxranges].dtt_base = base; -+ dtrace_toxrange[dtrace_toxranges].dtt_limit = limit; -+ dtrace_toxranges++; -+} -+ -+/* -+ * Check if an address falls within a toxic region. -+ */ -+int dtrace_istoxic(uintptr_t kaddr, size_t size) -+{ -+ uintptr_t taddr, tsize; -+ int i; -+ -+ for (i = 0; i < dtrace_toxranges; i++) { -+ taddr = dtrace_toxrange[i].dtt_base; -+ tsize = dtrace_toxrange[i].dtt_limit - taddr; -+ -+ if (kaddr - taddr < tsize) { -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); -+ this_cpu_core->cpuc_dtrace_illval = kaddr; -+ return 1; -+ } -+ -+ if (taddr - kaddr < size) { -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); -+ this_cpu_core->cpuc_dtrace_illval = kaddr; -+ return 1; -+ } -+ } -+ -+ return 0; -+} -+ -+static int dtrace_mod_notifier(struct notifier_block *nb, unsigned long val, -+ void *args) -+{ -+ struct module *mp = args; -+ -+ if (!mp) -+ return NOTIFY_DONE; -+ -+ switch (val) { -+ case MODULE_STATE_LIVE: -+ dtrace_module_loaded(mp); -+ break; -+ -+ case MODULE_STATE_GOING: -+ dtrace_module_unloaded(mp); -+ break; -+ } -+ -+ return NOTIFY_DONE; -+} -+ -+static struct notifier_block dtrace_modmgmt = { -+ .notifier_call = dtrace_mod_notifier, -+}; -+ -+/* -+ * Initialize the DTrace core. -+ * -+ * Equivalent to: dtrace_attach() -+ */ -+int dtrace_dev_init(void) -+{ -+ dtrace_provider_id_t id; -+ int rc = 0; -+ struct cred *cred; -+ -+ /* -+ * Register the device for the DTrace core. -+ */ -+ rc = misc_register(&dtrace_dev); -+ if (rc) { -+ pr_err("%s: Can't register misc device %d\n", -+ dtrace_dev.name, dtrace_dev.minor); -+ -+ return rc; -+ } -+ -+ /* -+ * Register the device for the DTrace helper. -+ */ -+ rc = misc_register(&helper_dev); -+ if (rc) { -+ pr_err("%s: Can't register misc device %d\n", -+ helper_dev.name, helper_dev.minor); -+ -+ misc_deregister(&dtrace_dev); -+ return rc; -+ } -+ -+ mutex_lock(&cpu_lock); -+ mutex_lock(&module_mutex); -+ mutex_lock(&dtrace_provider_lock); -+ mutex_lock(&dtrace_lock); -+ -+ rc = dtrace_probe_init(); -+ if (rc) { -+ pr_err("Failed to initialize DTrace core\n"); -+ -+ goto errout; -+ } -+ -+#if IS_ENABLED(CONFIG_DT_FASTTRAP) -+ dtrace_helpers_cleanup = dtrace_helpers_destroy; -+ dtrace_helpers_fork = dtrace_helpers_duplicate; -+#endif -+#ifdef FIXME -+ dtrace_cpu_init = dtrace_cpu_setup_initial; -+ dtrace_cpustart_init = dtrace_suspend; -+ dtrace_cpustart_fini = dtrace_resume; -+ dtrace_debugger_init = dtrace_suspend; -+ dtrace_debugger_fini = dtrace_resume; -+ -+ register_cpu_setup_func((cpu_setup_func_t *)dtrace_cpu_setup, NULL); -+#endif -+ -+#ifdef FIXME -+ dtrace_taskq = taskq_create("dtrace_taskq", 1, maxclsyspri, 1, INT_MAX, -+ 0); -+#endif -+ -+ dtrace_state_cachep = kmem_cache_create("dtrace_state_cache", -+ sizeof(struct dtrace_dstate_percpu) * NR_CPUS, -+ 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); -+ -+ /* From now on the failures are results of failed allocations. */ -+ rc = -ENOMEM; -+ -+ /* -+ * Create the probe hashtables. -+ */ -+ dtrace_bymod = dtrace_hash_create( -+ offsetof(struct dtrace_probe, dtpr_mod), -+ offsetof(struct dtrace_probe, dtpr_nextmod), -+ offsetof(struct dtrace_probe, dtpr_prevmod)); -+ if (dtrace_bymod == NULL) -+ goto errout; -+ -+ dtrace_byfunc = dtrace_hash_create( -+ offsetof(struct dtrace_probe, dtpr_func), -+ offsetof(struct dtrace_probe, dtpr_nextfunc), -+ offsetof(struct dtrace_probe, dtpr_prevfunc)); -+ if (dtrace_byfunc == NULL) -+ goto errout; -+ -+ dtrace_byname = dtrace_hash_create( -+ offsetof(struct dtrace_probe, dtpr_name), -+ offsetof(struct dtrace_probe, dtpr_nextname), -+ offsetof(struct dtrace_probe, dtpr_prevname)); -+ if (dtrace_byname == NULL) -+ goto errout; -+ -+ /* -+ * Initialize cred. -+ */ -+ cred = prepare_kernel_cred(NULL); -+ if (cred == NULL) -+ goto errout; -+ -+ init_user_namespace = cred->user_ns; -+ put_cred(cred); -+ -+ /* -+ * Ensure that the X configuration parameter has a legal value. -+ */ -+ if (dtrace_retain_max < 1) { -+ pr_warn("Illegal value (%lu) for dtrace_retain_max; " -+ "setting to 1", (unsigned long)dtrace_retain_max); -+ -+ dtrace_retain_max = 1; -+ } -+ -+ /* -+ * Discover our toxic ranges. -+ */ -+ dtrace_toxic_ranges(dtrace_toxrange_add); -+ -+ /* -+ * Register ourselves as a provider. -+ */ -+ dtrace_register("dtrace", &dtrace_provider_attr, DTRACE_PRIV_NONE, 0, -+ &dtrace_provider_ops, NULL, &id); -+ -+ ASSERT(dtrace_provider != NULL); -+ ASSERT((dtrace_provider_id_t)dtrace_provider == id); -+ -+ /* -+ * Create BEGIN, END, and ERROR probes. -+ */ -+ dtrace_probeid_begin = dtrace_probe_create( -+ (dtrace_provider_id_t)dtrace_provider, NULL, -+ NULL, "BEGIN", 0, NULL); -+ if (dtrace_probeid_begin == DTRACE_IDNONE) -+ goto errout; -+ -+ dtrace_probeid_end = dtrace_probe_create( -+ (dtrace_provider_id_t)dtrace_provider, NULL, -+ NULL, "END", 0, NULL); -+ if (dtrace_probeid_end == DTRACE_IDNONE) -+ goto errout; -+ -+ dtrace_probeid_error = dtrace_probe_create( -+ (dtrace_provider_id_t)dtrace_provider, NULL, -+ NULL, "ERROR", 1, NULL); -+ if (dtrace_probeid_error == DTRACE_IDNONE) -+ goto errout; -+ -+ dtrace_anon_property(); -+ -+ /* -+ * If DTrace helper tracing is enabled, we need to allocate a trace -+ * buffer. -+ */ -+ if (dtrace_helptrace_enabled) { -+ ASSERT(dtrace_helptrace_buffer == NULL); -+ -+ dtrace_helptrace_buffer = vzalloc(dtrace_helptrace_bufsize); -+ -+ if (dtrace_helptrace_buffer == NULL) { -+ pr_warn("Cannot allocate helptrace buffer; " -+ "disabling dtrace_helptrace\n"); -+ dtrace_helptrace_enabled = 0; -+ } -+ } -+ -+#ifdef FIXME -+ /* -+ * There is usually code here to handle the case where there already -+ * are providers when we get to this code. On Linux, that does not -+ * seem to be possible since the DTrace core module (this code) is -+ * loaded as a dependency for each provider, and thus this -+ * initialization code is executed prior to the initialization code of -+ * the first provider causing the core to be loaded. -+ */ -+#endif -+ -+ if (register_module_notifier(&dtrace_modmgmt)) -+ goto errout; -+ -+ mutex_unlock(&dtrace_lock); -+ mutex_unlock(&dtrace_provider_lock); -+ mutex_unlock(&module_mutex); -+ mutex_unlock(&cpu_lock); -+ -+ return 0; -+ -+errout: -+ if (dtrace_provider != NULL) -+ (void) dtrace_unregister((dtrace_provider_id_t)dtrace_provider); -+ -+ dtrace_hash_destroy(dtrace_bymod); -+ dtrace_hash_destroy(dtrace_byfunc); -+ dtrace_hash_destroy(dtrace_byname); -+ -+ misc_deregister(&helper_dev); -+ misc_deregister(&dtrace_dev); -+ -+ mutex_unlock(&dtrace_lock); -+ mutex_unlock(&dtrace_provider_lock); -+ mutex_unlock(&module_mutex); -+ mutex_unlock(&cpu_lock); -+ -+ return rc; -+} -+ -+void dtrace_dev_exit(void) -+{ -+ mutex_lock(&cpu_lock); -+ mutex_lock(&module_mutex); -+ mutex_lock(&dtrace_provider_lock); -+ mutex_lock(&dtrace_lock); -+ -+ dtrace_unregister((dtrace_provider_id_t)dtrace_provider); -+ dtrace_provider = NULL; -+ -+ dtrace_probe_exit(); -+ -+ unregister_module_notifier(&dtrace_modmgmt); -+ -+#if IS_ENABLED(CONFIG_DT_FASTTRAP) -+ dtrace_helpers_cleanup = NULL; -+ dtrace_helpers_fork = NULL; -+#endif -+#ifdef FIXME -+ dtrace_cpu_init = NULL; -+ dtrace_cpustart_init = NULL; -+ dtrace_cpustart_fini = NULL; -+ dtrace_debugger_init = NULL; -+ dtrace_debugger_fini = NULL; -+ -+ unregister_cpu_setup_func((cpu_setup_func_t *)dtrace_cpu_setup, NULL); -+#endif -+ -+ mutex_unlock(&cpu_lock); -+ -+ dtrace_hash_destroy(dtrace_bymod); -+ dtrace_hash_destroy(dtrace_byfunc); -+ dtrace_hash_destroy(dtrace_byname); -+ dtrace_bymod = NULL; -+ dtrace_byfunc = NULL; -+ dtrace_byname = NULL; -+ -+ /* -+ * If DTrace helper tracing is enabled, we need to free the trace -+ * buffer. -+ */ -+ if (dtrace_helptrace_enabled || dtrace_helptrace_buffer) -+ vfree(dtrace_helptrace_buffer); -+ -+ kmem_cache_destroy(dtrace_state_cachep); -+ -+ mutex_unlock(&dtrace_lock); -+ mutex_unlock(&dtrace_provider_lock); -+ mutex_unlock(&module_mutex); -+ -+ misc_deregister(&helper_dev); -+ misc_deregister(&dtrace_dev); -+} -diff --git a/dtrace/dtrace_dev.h b/dtrace/dtrace_dev.h -new file mode 100644 -index 000000000000..11ae2deb17a1 ---- /dev/null -+++ b/dtrace/dtrace_dev.h -@@ -0,0 +1,35 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Dynamic Tracing for Linux -+ * -+ * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#ifndef _DTRACE_DEV_H_ -+#define _DTRACE_DEV_H_ -+ -+#define DT_DEV_DTRACE_MINOR (16) -+#define DT_DEV_HELPER_MINOR (DT_DEV_DTRACE_MINOR + 1) -+#define DT_DEV_PROFILE_MINOR (DT_DEV_HELPER_MINOR + 1) -+#define DT_DEV_SYSTRACE_MINOR (DT_DEV_PROFILE_MINOR + 1) -+#define DT_DEV_FBT_MINOR (DT_DEV_SYSTRACE_MINOR + 1) -+#define DT_DEV_SDT_MINOR (DT_DEV_FBT_MINOR + 1) -+#define DT_DEV_FASTTRAP_MINOR (DT_DEV_SDT_MINOR + 1) -+#define DT_DEV_LOCKSTAT_MINOR (DT_DEV_FASTTRAP_MINOR + 1) -+#define DT_DEV_DT_TEST_MINOR (DT_DEV_LOCKSTAT_MINOR + 1) -+#define DT_DEV_DT_PERF_MINOR (DT_DEV_DT_TEST_MINOR + 1) -+ -+extern int dtrace_dev_init(void); -+extern void dtrace_dev_exit(void); -+ -+#endif /* _DTRACE_DEV_H_ */ -diff --git a/dtrace/dtrace_dif.c b/dtrace/dtrace_dif.c -new file mode 100644 -index 000000000000..ae7f01b4ed9b ---- /dev/null -+++ b/dtrace/dtrace_dif.c -@@ -0,0 +1,4905 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_dif.c -+ * DESCRIPTION: DTrace - DIF object implementation -+ * -+ * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/dtrace_cpu.h> -+#include <linux/dtrace_task_impl.h> -+#include <linux/fdtable.h> -+#include <linux/hardirq.h> -+#include <linux/if_arp.h> -+#include <linux/if_ether.h> -+#include <linux/if_infiniband.h> -+#include <linux/in6.h> -+#include <linux/inet.h> -+#include <linux/kdev_t.h> -+#include <linux/slab.h> -+#include <linux/socket.h> -+#include <linux/vmalloc.h> -+#include <net/ipv6.h> -+#include <asm/byteorder.h> -+ -+#include <linux/mount.h> -+ -+#include "dtrace.h" -+ -+size_t dtrace_global_maxsize = 16 * 1024; -+ -+/* -+ * This externally visible variable (accessible through the backtick (`) -+ * syntax is provided as a source of well-known, zero-filled memory. Some -+ * translators use this in their implementation. -+ */ -+const char dtrace_zero[256] = { 0, }; -+ -+uint64_t dtrace_vtime_references; -+ -+static const char hexdigits[] = "0123456789abcdef"; -+ -+static int dtrace_difo_err(uint_t pc, const char *format, ...) -+{ -+ char buf[256]; -+ -+ if (dtrace_err_verbose) { -+ va_list alist; -+ size_t len = strlen(format); -+ -+ pr_err("dtrace DIF object error: [%u]: ", pc); -+ -+ if (len >= 256 - sizeof(KERN_ERR)) { -+ pr_err("<invalid format string>"); -+ return 1; -+ } -+ -+ memcpy(buf, KERN_ERR, sizeof(KERN_ERR)); -+ memcpy(buf + sizeof(KERN_ERR), format, len); -+ -+ va_start(alist, format); -+ vprintk(buf, alist); -+ va_end(alist); -+ } -+ -+ return 1; -+} -+ -+/* -+ * Validate a DTrace DIF object by checking the IR instructions. The following -+ * rules are currently enforced by dtrace_difo_validate(): -+ * -+ * 1. Each instruction must have a valid opcode -+ * 2. Each register, string, variable, or subroutine reference must be valid -+ * 3. No instruction can modify register %r0 (must be zero) -+ * 4. All instruction reserved bits must be set to zero -+ * 5. The last instruction must be a "ret" instruction -+ * 6. All branch targets must reference a valid instruction _after_ the branch -+ */ -+int dtrace_difo_validate(struct dtrace_difo *dp, struct dtrace_vstate *vstate, -+ uint_t nregs, const struct cred *cr) -+{ -+ int err = 0, i; -+ int (*efunc)(uint_t pc, const char *, ...) = dtrace_difo_err; -+ int kcheckload = 0; -+ uint_t pc; -+ -+ kcheckload = cr == NULL || -+ (vstate->dtvs_state->dts_cred.dcr_visible & -+ DTRACE_CRV_KERNEL) == 0; -+ -+ dp->dtdo_destructive = 0; -+ -+ for (pc = 0; pc < dp->dtdo_len && err == 0; pc++) { -+ dif_instr_t instr = dp->dtdo_buf[pc]; -+ uint_t r1 = DIF_INSTR_R1(instr); -+ uint_t r2 = DIF_INSTR_R2(instr); -+ uint_t rd = DIF_INSTR_RD(instr); -+ uint_t rs = DIF_INSTR_RS(instr); -+ uint_t label = DIF_INSTR_LABEL(instr); -+ uint_t v = DIF_INSTR_VAR(instr); -+ uint_t subr = DIF_INSTR_SUBR(instr); -+ uint_t diftype = DIF_INSTR_TYPE(instr); -+ uint_t op = DIF_INSTR_OP(instr); -+ -+ switch (op) { -+ case DIF_OP_OR: -+ case DIF_OP_XOR: -+ case DIF_OP_AND: -+ case DIF_OP_SLL: -+ case DIF_OP_SRL: -+ case DIF_OP_SRA: -+ case DIF_OP_SUB: -+ case DIF_OP_ADD: -+ case DIF_OP_MUL: -+ case DIF_OP_SDIV: -+ case DIF_OP_UDIV: -+ case DIF_OP_SREM: -+ case DIF_OP_UREM: -+ case DIF_OP_COPYS: -+ if (r1 >= nregs) -+ err += efunc(pc, "invalid register %u\n", r1); -+ if (r2 >= nregs) -+ err += efunc(pc, "invalid register %u\n", r2); -+ if (rd >= nregs) -+ err += efunc(pc, "invalid register %u\n", rd); -+ if (rd == 0) -+ err += efunc(pc, "cannot write to %r0\n"); -+ break; -+ case DIF_OP_NOT: -+ case DIF_OP_MOV: -+ case DIF_OP_ALLOCS: -+ if (r1 >= nregs) -+ err += efunc(pc, "invalid register %u\n", r1); -+ if (r2 != 0) -+ err += efunc(pc, "non-zero reserved bits\n"); -+ if (rd >= nregs) -+ err += efunc(pc, "invalid register %u\n", rd); -+ if (rd == 0) -+ err += efunc(pc, "cannot write to %r0\n"); -+ break; -+ case DIF_OP_LDSB: -+ case DIF_OP_LDSH: -+ case DIF_OP_LDSW: -+ case DIF_OP_LDUB: -+ case DIF_OP_LDUH: -+ case DIF_OP_LDUW: -+ case DIF_OP_LDX: -+ if (r1 >= nregs) -+ err += efunc(pc, "invalid register %u\n", r1); -+ if (r2 != 0) -+ err += efunc(pc, "non-zero reserved bits\n"); -+ if (rd >= nregs) -+ err += efunc(pc, "invalid register %u\n", rd); -+ if (rd == 0) -+ err += efunc(pc, "cannot write to %r0\n"); -+ if (kcheckload) -+ dp->dtdo_buf[pc] = DIF_INSTR_LOAD( -+ op + DIF_OP_RLDSB - -+ DIF_OP_LDSB, -+ r1, rd); -+ break; -+ case DIF_OP_RLDSB: -+ case DIF_OP_RLDSH: -+ case DIF_OP_RLDSW: -+ case DIF_OP_RLDUB: -+ case DIF_OP_RLDUH: -+ case DIF_OP_RLDUW: -+ case DIF_OP_RLDX: -+ if (r1 >= nregs) -+ err += efunc(pc, "invalid register %u\n", r1); -+ if (r2 != 0) -+ err += efunc(pc, "non-zero reserved bits\n"); -+ if (rd >= nregs) -+ err += efunc(pc, "invalid register %u\n", rd); -+ if (rd == 0) -+ err += efunc(pc, "cannot write to %r0\n"); -+ break; -+ case DIF_OP_ULDSB: -+ case DIF_OP_ULDSH: -+ case DIF_OP_ULDSW: -+ case DIF_OP_ULDUB: -+ case DIF_OP_ULDUH: -+ case DIF_OP_ULDUW: -+ case DIF_OP_ULDX: -+ if (r1 >= nregs) -+ err += efunc(pc, "invalid register %u\n", r1); -+ if (r2 != 0) -+ err += efunc(pc, "non-zero reserved bits\n"); -+ if (rd >= nregs) -+ err += efunc(pc, "invalid register %u\n", rd); -+ if (rd == 0) -+ err += efunc(pc, "cannot write to %r0\n"); -+ break; -+ case DIF_OP_STB: -+ case DIF_OP_STH: -+ case DIF_OP_STW: -+ case DIF_OP_STX: -+ if (r1 >= nregs) -+ err += efunc(pc, "invalid register %u\n", r1); -+ if (r2 != 0) -+ err += efunc(pc, "non-zero reserved bits\n"); -+ if (rd >= nregs) -+ err += efunc(pc, "invalid register %u\n", rd); -+ if (rd == 0) -+ err += efunc(pc, "cannot write to 0 address\n"); -+ break; -+ case DIF_OP_CMP: -+ case DIF_OP_SCMP: -+ if (r1 >= nregs) -+ err += efunc(pc, "invalid register %u\n", r1); -+ if (r2 >= nregs) -+ err += efunc(pc, "invalid register %u\n", r2); -+ if (rd != 0) -+ err += efunc(pc, "non-zero reserved bits\n"); -+ break; -+ case DIF_OP_TST: -+ if (r1 >= nregs) -+ err += efunc(pc, "invalid register %u\n", r1); -+ if (r2 != 0 || rd != 0) -+ err += efunc(pc, "non-zero reserved bits\n"); -+ break; -+ case DIF_OP_BA: -+ case DIF_OP_BE: -+ case DIF_OP_BNE: -+ case DIF_OP_BG: -+ case DIF_OP_BGU: -+ case DIF_OP_BGE: -+ case DIF_OP_BGEU: -+ case DIF_OP_BL: -+ case DIF_OP_BLU: -+ case DIF_OP_BLE: -+ case DIF_OP_BLEU: -+ if (label >= dp->dtdo_len) -+ err += efunc(pc, "invalid branch target %u\n", -+ label); -+ if (label <= pc) -+ err += efunc(pc, "backward branch to %u\n", -+ label); -+ break; -+ case DIF_OP_RET: -+ if (r1 != 0 || r2 != 0) -+ err += efunc(pc, "non-zero reserved bits\n"); -+ if (rd >= nregs) -+ err += efunc(pc, "invalid register %u\n", rd); -+ break; -+ case DIF_OP_NOP: -+ case DIF_OP_POPTS: -+ case DIF_OP_FLUSHTS: -+ if (r1 != 0 || r2 != 0 || rd != 0) -+ err += efunc(pc, "non-zero reserved bits\n"); -+ break; -+ case DIF_OP_SETX: -+ if (DIF_INSTR_INTEGER(instr) >= dp->dtdo_intlen) -+ err += efunc(pc, "invalid integer ref %u\n", -+ DIF_INSTR_INTEGER(instr)); -+ if (rd >= nregs) -+ err += efunc(pc, "invalid register %u\n", rd); -+ if (rd == 0) -+ err += efunc(pc, "cannot write to %r0\n"); -+ break; -+ case DIF_OP_SETS: -+ if (DIF_INSTR_STRING(instr) >= dp->dtdo_strlen) -+ err += efunc(pc, "invalid string ref %u\n", -+ DIF_INSTR_STRING(instr)); -+ if (rd >= nregs) -+ err += efunc(pc, "invalid register %u\n", rd); -+ if (rd == 0) -+ err += efunc(pc, "cannot write to %r0\n"); -+ break; -+ case DIF_OP_LDGA: -+ case DIF_OP_LDTA: -+ if (r1 > DIF_VAR_ARRAY_MAX) -+ err += efunc(pc, "invalid array %u\n", r1); -+ if (r2 >= nregs) -+ err += efunc(pc, "invalid register %u\n", r2); -+ if (rd >= nregs) -+ err += efunc(pc, "invalid register %u\n", rd); -+ if (rd == 0) -+ err += efunc(pc, "cannot write to %r0\n"); -+ break; -+ case DIF_OP_LDGS: -+ case DIF_OP_LDTS: -+ case DIF_OP_LDLS: -+ case DIF_OP_LDGAA: -+ case DIF_OP_LDTAA: -+ if (v < DIF_VAR_OTHER_MIN || v > DIF_VAR_OTHER_MAX) -+ err += efunc(pc, "invalid variable %u\n", v); -+ if (rd >= nregs) -+ err += efunc(pc, "invalid register %u\n", rd); -+ if (rd == 0) -+ err += efunc(pc, "cannot write to %r0\n"); -+ break; -+ case DIF_OP_STGS: -+ case DIF_OP_STTS: -+ case DIF_OP_STLS: -+ case DIF_OP_STGAA: -+ case DIF_OP_STTAA: -+ if (v < DIF_VAR_OTHER_UBASE || v > DIF_VAR_OTHER_MAX) -+ err += efunc(pc, "invalid variable %u\n", v); -+ if (rs >= nregs) -+ err += efunc(pc, "invalid register %u\n", rd); -+ break; -+ case DIF_OP_CALL: -+ if (subr > DIF_SUBR_MAX) -+ err += efunc(pc, "invalid subr %u\n", subr); -+ if (rd >= nregs) -+ err += efunc(pc, "invalid register %u\n", rd); -+ if (rd == 0) -+ err += efunc(pc, "cannot write to %r0\n"); -+ -+ if (subr == DIF_SUBR_COPYOUT || -+ subr == DIF_SUBR_COPYOUTSTR) -+ dp->dtdo_destructive = 1; -+ break; -+ case DIF_OP_PUSHTR: -+ if (diftype != DIF_TYPE_STRING && diftype != DIF_TYPE_CTF) -+ err += efunc(pc, "invalid ref type %u\n", -+ diftype); -+ if (r2 >= nregs) -+ err += efunc(pc, "invalid register %u\n", r2); -+ if (rs >= nregs) -+ err += efunc(pc, "invalid register %u\n", rs); -+ break; -+ case DIF_OP_PUSHTV: -+ if (diftype != DIF_TYPE_CTF) -+ err += efunc(pc, "invalid val type %u\n", -+ diftype); -+ if (r2 >= nregs) -+ err += efunc(pc, "invalid register %u\n", r2); -+ if (rs >= nregs) -+ err += efunc(pc, "invalid register %u\n", rs); -+ break; -+ default: -+ err += efunc(pc, "invalid opcode %u\n", -+ DIF_INSTR_OP(instr)); -+ } -+ } -+ -+ if (dp->dtdo_len != 0 && -+ DIF_INSTR_OP(dp->dtdo_buf[dp->dtdo_len - 1]) != DIF_OP_RET) { -+ err += efunc(dp->dtdo_len - 1, -+ "expected 'ret' as last DIF instruction\n"); -+ } -+ -+ if (!(dp->dtdo_rtype.dtdt_flags & DIF_TF_BYREF)) { -+ /* -+ * If we're not returning by reference, the size must be either -+ * 0 or the size of one of the base types. -+ */ -+ switch (dp->dtdo_rtype.dtdt_size) { -+ case 0: -+ case sizeof(uint8_t): -+ case sizeof(uint16_t): -+ case sizeof(uint32_t): -+ case sizeof(uint64_t): -+ break; -+ -+ default: -+ err += efunc(dp->dtdo_len - 1, "bad return size\n"); -+ } -+ } -+ -+ for (i = 0; i < dp->dtdo_varlen && err == 0; i++) { -+ struct dtrace_difv *v = &dp->dtdo_vartab[i], -+ *existing = NULL; -+ struct dtrace_diftype *vt, *et; -+ uint_t id, ndx; -+ -+ if (v->dtdv_scope != DIFV_SCOPE_GLOBAL && -+ v->dtdv_scope != DIFV_SCOPE_THREAD && -+ v->dtdv_scope != DIFV_SCOPE_LOCAL) { -+ err += efunc(i, "unrecognized variable scope %d\n", -+ v->dtdv_scope); -+ break; -+ } -+ -+ if (v->dtdv_kind != DIFV_KIND_ARRAY && -+ v->dtdv_kind != DIFV_KIND_SCALAR) { -+ err += efunc(i, "unrecognized variable type %d\n", -+ v->dtdv_kind); -+ break; -+ } -+ -+ id = v->dtdv_id; -+ if (id > DIF_VARIABLE_MAX) { -+ err += efunc(i, "%d exceeds variable id limit\n", id); -+ break; -+ } -+ -+ if (id < DIF_VAR_OTHER_UBASE) -+ continue; -+ -+ /* -+ * For user-defined variables, we need to check that this -+ * definition is identical to any previous definition that we -+ * encountered. -+ */ -+ ndx = id - DIF_VAR_OTHER_UBASE; -+ -+ switch (v->dtdv_scope) { -+ case DIFV_SCOPE_GLOBAL: -+ if (ndx < vstate->dtvs_nglobals) { -+ struct dtrace_statvar *svar; -+ -+ svar = vstate->dtvs_globals[ndx]; -+ if (svar != NULL) -+ existing = &svar->dtsv_var; -+ } -+ -+ break; -+ -+ case DIFV_SCOPE_THREAD: -+ if (ndx < vstate->dtvs_ntlocals) -+ existing = &vstate->dtvs_tlocals[ndx]; -+ break; -+ -+ case DIFV_SCOPE_LOCAL: -+ if (ndx < vstate->dtvs_nlocals) { -+ struct dtrace_statvar *svar; -+ -+ svar = vstate->dtvs_locals[ndx]; -+ if (svar != NULL) -+ existing = &svar->dtsv_var; -+ } -+ -+ break; -+ } -+ -+ vt = &v->dtdv_type; -+ -+ if (vt->dtdt_flags & DIF_TF_BYREF) { -+ if (vt->dtdt_size == 0) { -+ err += efunc(i, "zero-sized variable\n"); -+ break; -+ } -+ -+ if (v->dtdv_scope == DIFV_SCOPE_GLOBAL && -+ vt->dtdt_size > dtrace_global_maxsize) { -+ err += efunc(i, "oversized by-ref global\n"); -+ break; -+ } -+ } -+ -+ if (existing == NULL || existing->dtdv_id == 0) -+ continue; -+ -+ ASSERT(existing->dtdv_id == v->dtdv_id); -+ ASSERT(existing->dtdv_scope == v->dtdv_scope); -+ -+ if (existing->dtdv_kind != v->dtdv_kind) -+ err += efunc(i, "%d changed variable kind\n", id); -+ -+ et = &existing->dtdv_type; -+ -+ if (vt->dtdt_flags != et->dtdt_flags) { -+ err += efunc(i, "%d changed variable type flags\n", id); -+ break; -+ } -+ -+ if (vt->dtdt_size != 0 && vt->dtdt_size != et->dtdt_size) { -+ err += efunc(i, "%d changed variable type size\n", id); -+ break; -+ } -+ } -+ -+ return err; -+} -+ -+/* -+ * Validate a DTrace DIF object that it is to be used as a helper. Helpers -+ * are much more constrained than normal DIFOs. Specifically, they may -+ * not: -+ * -+ * 1. Make calls to subroutines other than copyin(), copyinstr() or -+ * miscellaneous string routines -+ * 2. Access DTrace variables other than the args[] array, and the -+ * curthread, pid, ppid, tid, execname, zonename, uid and gid variables. -+ * 3. Have thread-local variables. -+ * 4. Have dynamic variables. -+ */ -+int dtrace_difo_validate_helper(struct dtrace_difo *dp) -+{ -+ int (*efunc)(uint_t pc, const char *, ...) = dtrace_difo_err; -+ int err = 0; -+ uint_t pc; -+ -+ for (pc = 0; pc < dp->dtdo_len; pc++) { -+ dif_instr_t instr = dp->dtdo_buf[pc]; -+ uint_t v = DIF_INSTR_VAR(instr); -+ uint_t subr = DIF_INSTR_SUBR(instr); -+ uint_t op = DIF_INSTR_OP(instr); -+ -+ switch (op) { -+ case DIF_OP_OR: -+ case DIF_OP_XOR: -+ case DIF_OP_AND: -+ case DIF_OP_SLL: -+ case DIF_OP_SRL: -+ case DIF_OP_SRA: -+ case DIF_OP_SUB: -+ case DIF_OP_ADD: -+ case DIF_OP_MUL: -+ case DIF_OP_SDIV: -+ case DIF_OP_UDIV: -+ case DIF_OP_SREM: -+ case DIF_OP_UREM: -+ case DIF_OP_COPYS: -+ case DIF_OP_NOT: -+ case DIF_OP_MOV: -+ case DIF_OP_RLDSB: -+ case DIF_OP_RLDSH: -+ case DIF_OP_RLDSW: -+ case DIF_OP_RLDUB: -+ case DIF_OP_RLDUH: -+ case DIF_OP_RLDUW: -+ case DIF_OP_RLDX: -+ case DIF_OP_ULDSB: -+ case DIF_OP_ULDSH: -+ case DIF_OP_ULDSW: -+ case DIF_OP_ULDUB: -+ case DIF_OP_ULDUH: -+ case DIF_OP_ULDUW: -+ case DIF_OP_ULDX: -+ case DIF_OP_STB: -+ case DIF_OP_STH: -+ case DIF_OP_STW: -+ case DIF_OP_STX: -+ case DIF_OP_ALLOCS: -+ case DIF_OP_CMP: -+ case DIF_OP_SCMP: -+ case DIF_OP_TST: -+ case DIF_OP_BA: -+ case DIF_OP_BE: -+ case DIF_OP_BNE: -+ case DIF_OP_BG: -+ case DIF_OP_BGU: -+ case DIF_OP_BGE: -+ case DIF_OP_BGEU: -+ case DIF_OP_BL: -+ case DIF_OP_BLU: -+ case DIF_OP_BLE: -+ case DIF_OP_BLEU: -+ case DIF_OP_RET: -+ case DIF_OP_NOP: -+ case DIF_OP_POPTS: -+ case DIF_OP_FLUSHTS: -+ case DIF_OP_SETX: -+ case DIF_OP_SETS: -+ case DIF_OP_LDGA: -+ case DIF_OP_LDLS: -+ case DIF_OP_STGS: -+ case DIF_OP_STLS: -+ case DIF_OP_PUSHTR: -+ case DIF_OP_PUSHTV: -+ break; -+ -+ case DIF_OP_LDGS: -+ if (v >= DIF_VAR_OTHER_UBASE) -+ break; -+ -+ if (v >= DIF_VAR_ARG0 && v <= DIF_VAR_ARG9) -+ break; -+ -+ if (v == DIF_VAR_CURTHREAD || v == DIF_VAR_PID || -+ v == DIF_VAR_PPID || v == DIF_VAR_TID || -+ v == DIF_VAR_EXECNAME || v == DIF_VAR_ZONENAME || -+ v == DIF_VAR_UID || v == DIF_VAR_GID) -+ break; -+ -+ err += efunc(pc, "illegal variable %u\n", v); -+ break; -+ -+ case DIF_OP_LDTA: -+ case DIF_OP_LDGAA: -+ case DIF_OP_LDTAA: -+ err += efunc(pc, "illegal dynamic variable load\n"); -+ break; -+ -+ case DIF_OP_STTS: -+ case DIF_OP_STGAA: -+ case DIF_OP_STTAA: -+ err += efunc(pc, "illegal dynamic variable store\n"); -+ break; -+ -+ case DIF_OP_CALL: -+ if (subr == DIF_SUBR_ALLOCA || -+ subr == DIF_SUBR_BCOPY || -+ subr == DIF_SUBR_COPYIN || -+ subr == DIF_SUBR_COPYINTO || -+ subr == DIF_SUBR_COPYINSTR || -+ subr == DIF_SUBR_INDEX || -+ subr == DIF_SUBR_INET_NTOA || -+ subr == DIF_SUBR_INET_NTOA6 || -+ subr == DIF_SUBR_INET_NTOP || -+ subr == DIF_SUBR_LINK_NTOP || -+ subr == DIF_SUBR_LLTOSTR || -+ subr == DIF_SUBR_RINDEX || -+ subr == DIF_SUBR_STRCHR || -+ subr == DIF_SUBR_STRJOIN || -+ subr == DIF_SUBR_STRRCHR || -+ subr == DIF_SUBR_STRSTR || -+ subr == DIF_SUBR_HTONS || -+ subr == DIF_SUBR_HTONL || -+ subr == DIF_SUBR_HTONLL || -+ subr == DIF_SUBR_NTOHS || -+ subr == DIF_SUBR_NTOHL || -+ subr == DIF_SUBR_NTOHLL) -+ break; -+ -+ err += efunc(pc, "invalid subr %u\n", subr); -+ break; -+ -+ default: -+ err += efunc(pc, "invalid opcode %u\n", -+ DIF_INSTR_OP(instr)); -+ } -+ } -+ -+ return err; -+} -+ -+/* -+ * Returns 1 if the expression in the DIF object can be cached on a per-thread -+ * basis; 0 if not. -+ */ -+int dtrace_difo_cacheable(struct dtrace_difo *dp) -+{ -+ int i; -+ -+ if (dp == NULL) -+ return 0; -+ -+ for (i = 0; i < dp->dtdo_varlen; i++) { -+ struct dtrace_difv *v = &dp->dtdo_vartab[i]; -+ -+ if (v->dtdv_scope != DIFV_SCOPE_GLOBAL) -+ continue; -+ -+ switch (v->dtdv_id) { -+ case DIF_VAR_CURTHREAD: -+ case DIF_VAR_PID: -+ case DIF_VAR_TID: -+ case DIF_VAR_EXECNAME: -+ case DIF_VAR_ZONENAME: -+ break; -+ -+ default: -+ return 0; -+ } -+ } -+ -+ /* -+ * This DIF object may be cacheable. Now we need to look for any -+ * array loading instructions, any memory loading instructions, or -+ * any stores to thread-local variables. -+ */ -+ for (i = 0; i < dp->dtdo_len; i++) { -+ uint_t op = DIF_INSTR_OP(dp->dtdo_buf[i]); -+ -+ if ((op >= DIF_OP_LDSB && op <= DIF_OP_LDX) || -+ (op >= DIF_OP_ULDSB && op <= DIF_OP_ULDX) || -+ (op >= DIF_OP_RLDSB && op <= DIF_OP_RLDX) || -+ op == DIF_OP_LDGA || op == DIF_OP_STTS) -+ return 0; -+ } -+ -+ return 1; -+} -+ -+/* -+ * This routine calculates the dynamic variable chunksize for a given DIF -+ * object. The calculation is not fool-proof, and can probably be tricked by -+ * malicious DIF -- but it works for all compiler-generated DIF. Because this -+ * calculation is likely imperfect, dtrace_dynvar() is able to gracefully fail -+ * if a dynamic variable size exceeds the chunksize. -+ */ -+static void dtrace_difo_chunksize(struct dtrace_difo *dp, -+ struct dtrace_vstate *vstate) -+{ -+ uint64_t sval = 0; -+ struct dtrace_key tupregs[DIF_DTR_NREGS + 2]; /* + thread + id */ -+ const dif_instr_t *text = dp->dtdo_buf; -+ uint_t pc, srd = 0; -+ uint_t ttop = 0; -+ size_t size, ksize; -+ uint_t id, i; -+ -+ for (pc = 0; pc < dp->dtdo_len; pc++) { -+ dif_instr_t instr = text[pc]; -+ uint_t op = DIF_INSTR_OP(instr); -+ uint_t rd = DIF_INSTR_RD(instr); -+ uint_t r1 = DIF_INSTR_R1(instr); -+ uint_t nkeys = 0; -+ uchar_t scope; -+ struct dtrace_key *key = tupregs; -+ -+ switch (op) { -+ case DIF_OP_SETX: -+ sval = dp->dtdo_inttab[DIF_INSTR_INTEGER(instr)]; -+ srd = rd; -+ continue; -+ -+ case DIF_OP_STTS: -+ key = &tupregs[DIF_DTR_NREGS]; -+ key[0].dttk_size = 0; -+ key[1].dttk_size = 0; -+ nkeys = 2; -+ scope = DIFV_SCOPE_THREAD; -+ break; -+ -+ case DIF_OP_STGAA: -+ case DIF_OP_STTAA: -+ nkeys = ttop; -+ -+ if (DIF_INSTR_OP(instr) == DIF_OP_STTAA) -+ key[nkeys++].dttk_size = 0; -+ -+ key[nkeys++].dttk_size = 0; -+ -+ if (op == DIF_OP_STTAA) -+ scope = DIFV_SCOPE_THREAD; -+ else -+ scope = DIFV_SCOPE_GLOBAL; -+ -+ break; -+ -+ case DIF_OP_PUSHTR: -+ if (ttop == DIF_DTR_NREGS) -+ return; -+ -+ /* -+ * If the register for the size of the "pushtr" is %r0 -+ * (or the value is 0) and the type is a string, we'll -+ * use the system-wide default string size. -+ */ -+ if ((srd == 0 || sval == 0) && r1 == DIF_TYPE_STRING) -+ tupregs[ttop++].dttk_size = -+ dtrace_strsize_default; -+ else { -+ if (srd == 0) -+ return; -+ -+ tupregs[ttop++].dttk_size = sval; -+ } -+ -+ break; -+ -+ case DIF_OP_PUSHTV: -+ if (ttop == DIF_DTR_NREGS) -+ return; -+ -+ tupregs[ttop++].dttk_size = 0; -+ break; -+ -+ case DIF_OP_FLUSHTS: -+ ttop = 0; -+ break; -+ -+ case DIF_OP_POPTS: -+ if (ttop != 0) -+ ttop--; -+ break; -+ } -+ -+ sval = 0; -+ srd = 0; -+ -+ if (nkeys == 0) -+ continue; -+ -+ /* -+ * We have a dynamic variable allocation; calculate its size. -+ */ -+ for (ksize = 0, i = 0; i < nkeys; i++) -+ ksize += P2ROUNDUP(key[i].dttk_size, sizeof(uint64_t)); -+ -+ size = sizeof(struct dtrace_dynvar); -+ size += sizeof(struct dtrace_key) * (nkeys - 1); -+ size += ksize; -+ -+ /* -+ * Now we need to determine the size of the stored data. -+ */ -+ id = DIF_INSTR_VAR(instr); -+ -+ for (i = 0; i < dp->dtdo_varlen; i++) { -+ struct dtrace_difv *v = &dp->dtdo_vartab[i]; -+ -+ if (v->dtdv_id == id && v->dtdv_scope == scope) { -+ size += v->dtdv_type.dtdt_size; -+ break; -+ } -+ } -+ -+ if (i == dp->dtdo_varlen) -+ return; -+ -+ /* -+ * We have the size. If this is larger than the chunk size -+ * for our dynamic variable state, reset the chunk size. -+ */ -+ size = P2ROUNDUP(size, sizeof(uint64_t)); -+ -+ if (size > vstate->dtvs_dynvars.dtds_chunksize) -+ vstate->dtvs_dynvars.dtds_chunksize = size; -+ } -+} -+ -+void dtrace_difo_hold(struct dtrace_difo *dp) -+{ -+ int i; -+ -+ dp->dtdo_refcnt++; -+ ASSERT(dp->dtdo_refcnt != 0); -+ -+ for (i = 0; i < dp->dtdo_varlen; i++) { -+ struct dtrace_difv *v = &dp->dtdo_vartab[i]; -+ -+ if (v->dtdv_id != DIF_VAR_VTIMESTAMP) -+ continue; -+ -+ if (dtrace_vtime_references++ == 0) -+ dtrace_vtime_enable(); -+ } -+} -+ -+void dtrace_difo_init(struct dtrace_difo *dp, struct dtrace_vstate *vstate) -+{ -+ int i, oldsvars, osz, nsz, otlocals, ntlocals; -+ uint_t id; -+ -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ ASSERT(dp->dtdo_buf != NULL && dp->dtdo_len != 0); -+ -+ for (i = 0; i < dp->dtdo_varlen; i++) { -+ struct dtrace_difv *v = &dp->dtdo_vartab[i]; -+ struct dtrace_statvar *svar, ***svarp; -+ size_t dsize = 0; -+ uint8_t scope = v->dtdv_scope; -+ int *np; -+ -+ id = v->dtdv_id; -+ if (id < DIF_VAR_OTHER_UBASE) -+ continue; -+ -+ id -= DIF_VAR_OTHER_UBASE; -+ -+ switch (scope) { -+ case DIFV_SCOPE_THREAD: -+ while (id >= (otlocals = vstate->dtvs_ntlocals)) { -+ struct dtrace_difv *tlocals; -+ -+ ntlocals = otlocals << 1; -+ if (ntlocals == 0) -+ ntlocals = 1; -+ -+ osz = otlocals * sizeof(struct dtrace_difv); -+ nsz = ntlocals * sizeof(struct dtrace_difv); -+ -+ tlocals = vzalloc(nsz); -+ -+ if (osz != 0) { -+ memcpy(tlocals, vstate->dtvs_tlocals, -+ osz); -+ vfree(vstate->dtvs_tlocals); -+ } -+ -+ vstate->dtvs_tlocals = tlocals; -+ vstate->dtvs_ntlocals = ntlocals; -+ } -+ -+ vstate->dtvs_tlocals[id] = *v; -+ continue; -+ -+ case DIFV_SCOPE_LOCAL: -+ np = &vstate->dtvs_nlocals; -+ svarp = &vstate->dtvs_locals; -+ -+ if (v->dtdv_type.dtdt_flags & DIF_TF_BYREF) -+ dsize = NR_CPUS * -+ (v->dtdv_type.dtdt_size + -+ sizeof(uint64_t)); -+ else -+ dsize = NR_CPUS * sizeof(uint64_t); -+ -+ break; -+ -+ case DIFV_SCOPE_GLOBAL: -+ np = &vstate->dtvs_nglobals; -+ svarp = &vstate->dtvs_globals; -+ -+ if (v->dtdv_type.dtdt_flags & DIF_TF_BYREF) -+ dsize = v->dtdv_type.dtdt_size + -+ sizeof(uint64_t); -+ -+ break; -+ -+ default: -+ ASSERT(0); -+ continue; /* not reached */ -+ } -+ -+ while (id >= (oldsvars = *np)) { -+ struct dtrace_statvar **statics; -+ int newsvars, oldsize, newsize; -+ -+ newsvars = oldsvars << 1; -+ if (newsvars == 0) -+ newsvars = 1; -+ -+ oldsize = oldsvars * sizeof(struct dtrace_statvar *); -+ newsize = newsvars * sizeof(struct dtrace_statvar *); -+ -+ statics = vzalloc(newsize); -+ -+ if (oldsize != 0) { -+ memcpy(statics, *svarp, oldsize); -+ vfree(*svarp); -+ } -+ -+ *svarp = statics; -+ *np = newsvars; -+ } -+ -+ svar = (*svarp)[id]; -+ if (svar == NULL) { -+ svar = kzalloc(sizeof(struct dtrace_statvar), -+ GFP_KERNEL); -+ svar->dtsv_var = *v; -+ -+ svar->dtsv_size = dsize; -+ if (svar->dtsv_size != 0) { -+ svar->dtsv_data = -+ (uint64_t)(uintptr_t)vzalloc(dsize); -+ } -+ -+ (*svarp)[id] = svar; -+ } -+ -+ svar->dtsv_refcnt++; -+ } -+ -+ dtrace_difo_chunksize(dp, vstate); -+ dtrace_difo_hold(dp); -+} -+ -+struct dtrace_difo *dtrace_difo_duplicate(struct dtrace_difo *dp, -+ struct dtrace_vstate *vstate) -+{ -+ struct dtrace_difo *new; -+ size_t sz; -+ -+ ASSERT(dp->dtdo_buf != NULL); -+ ASSERT(dp->dtdo_refcnt != 0); -+ -+ new = kzalloc(sizeof(struct dtrace_difo), GFP_KERNEL); -+ -+ ASSERT(dp->dtdo_buf != NULL); -+ sz = dp->dtdo_len * sizeof(dif_instr_t); -+ new->dtdo_buf = vmalloc(sz); -+ memcpy(new->dtdo_buf, dp->dtdo_buf, sz); -+ new->dtdo_len = dp->dtdo_len; -+ -+ if (dp->dtdo_strtab != NULL) { -+ ASSERT(dp->dtdo_strlen != 0); -+ new->dtdo_strtab = vmalloc(dp->dtdo_strlen); -+ memcpy(new->dtdo_strtab, dp->dtdo_strtab, dp->dtdo_strlen); -+ new->dtdo_strlen = dp->dtdo_strlen; -+ } -+ -+ if (dp->dtdo_inttab != NULL) { -+ ASSERT(dp->dtdo_intlen != 0); -+ sz = dp->dtdo_intlen * sizeof(uint64_t); -+ new->dtdo_inttab = vmalloc(sz); -+ memcpy(new->dtdo_inttab, dp->dtdo_inttab, sz); -+ new->dtdo_intlen = dp->dtdo_intlen; -+ } -+ -+ if (dp->dtdo_vartab != NULL) { -+ ASSERT(dp->dtdo_varlen != 0); -+ sz = dp->dtdo_varlen * sizeof(struct dtrace_difv); -+ new->dtdo_vartab = vmalloc(sz); -+ memcpy(new->dtdo_vartab, dp->dtdo_vartab, sz); -+ new->dtdo_varlen = dp->dtdo_varlen; -+ } -+ -+ dtrace_difo_init(new, vstate); -+ -+ return new; -+} -+ -+void dtrace_difo_destroy(struct dtrace_difo *dp, struct dtrace_vstate *vstate) -+{ -+ int i; -+ -+ ASSERT(dp->dtdo_refcnt == 0); -+ -+ for (i = 0; i < dp->dtdo_varlen; i++) { -+ struct dtrace_difv *v = &dp->dtdo_vartab[i]; -+ struct dtrace_statvar *svar, **svarp; -+ uint_t id; -+ uint8_t scope = v->dtdv_scope; -+ int *np; -+ -+ switch (scope) { -+ case DIFV_SCOPE_THREAD: -+ continue; -+ -+ case DIFV_SCOPE_LOCAL: -+ np = &vstate->dtvs_nlocals; -+ svarp = vstate->dtvs_locals; -+ break; -+ -+ case DIFV_SCOPE_GLOBAL: -+ np = &vstate->dtvs_nglobals; -+ svarp = vstate->dtvs_globals; -+ break; -+ -+ default: -+ BUG(); -+ } -+ -+ id = v->dtdv_id; -+ if (id < DIF_VAR_OTHER_UBASE) -+ continue; -+ -+ id -= DIF_VAR_OTHER_UBASE; -+ ASSERT(id < *np); -+ -+ svar = svarp[id]; -+ ASSERT(svar != NULL); -+ ASSERT(svar->dtsv_refcnt > 0); -+ -+ if (--svar->dtsv_refcnt > 0) -+ continue; -+ -+ if (svar->dtsv_size != 0) { -+ ASSERT((void *)(uintptr_t)svar->dtsv_data != NULL); -+ vfree((void *)(uintptr_t)svar->dtsv_data); -+ } -+ -+ kfree(svar); -+ svarp[id] = NULL; -+ } -+ -+ vfree(dp->dtdo_buf); -+ vfree(dp->dtdo_inttab); -+ vfree(dp->dtdo_strtab); -+ vfree(dp->dtdo_vartab); -+ kfree(dp); -+} -+ -+void dtrace_difo_release(struct dtrace_difo *dp, struct dtrace_vstate *vstate) -+{ -+ int i; -+ -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ ASSERT(dp->dtdo_refcnt != 0); -+ -+ for (i = 0; i < dp->dtdo_varlen; i++) { -+ struct dtrace_difv *v = &dp->dtdo_vartab[i]; -+ -+ if (v->dtdv_id != DIF_VAR_VTIMESTAMP) -+ continue; -+ -+ ASSERT(dtrace_vtime_references > 0); -+ -+ if (--dtrace_vtime_references == 0) -+ dtrace_vtime_disable(); -+ } -+ -+ if (--dp->dtdo_refcnt == 0) -+ dtrace_difo_destroy(dp, vstate); -+} -+ -+/* -+ * The key for a thread-local variable consists of the lower 60 bits of the -+ * task pid, prefixed by a 4 bits indicating whether a hard_irq is active. -+ * This accounts for a case where some older drivers re-enable interrupts -+ * and can nest in hard irq context. -+ * -+ * All per-cpu idle threads share same pid 0. In this special case we replace -+ * the pid with cpu id (an idle thread is bound to a single cpu). If pid is -+ * not 0 then a NR_CPUS is added. This assures that the thread key for idle -+ * thread never conflicts with regular pids in range 0..NR_CPUS. -+ * -+ * We add DIF_VARIABLE_MAX to the pid to assure that the thread key is never -+ * equal to a variable identifier. This is necessary (but not sufficient) to -+ * assure that global associative arrays never collide with thread-local -+ * variables. To guarantee that they cannot collide, we must also define the -+ * order for keying dynamic variables. That order is: -+ * -+ * [ key0 ] ... [ keyn ] [ variable-key ] [ tls-key ] -+ * -+ * Because the variable-key and the tls-key are in orthogonal spaces, there is -+ * no way for a global variable key signature to match a thread-local key -+ * signature. -+ */ -+#define DTRACE_TLS_THRKEY(where) \ -+ { \ -+ uint_t intr = hardirq_count() >> HARDIRQ_SHIFT; \ -+ uint_t cpu = (current->flags & PF_IDLE) ? \ -+ smp_processor_id() : NR_CPUS; \ -+ \ -+ (where) = ((current->pid + cpu + DIF_VARIABLE_MAX) & \ -+ (((uint64_t)1 << 60) - 1)) | \ -+ ((uint64_t)intr << 60); \ -+ } -+ -+#ifndef FIXME -+# define DTRACE_ALIGNCHECK(addr, size, flags) -+#endif -+ -+/* -+ * Test whether a range of memory starting at testaddr of size testsz falls -+ * within the range of memory described by addr, sz. We take care to avoid -+ * problems with overflow and underflow of the unsigned quantities, and -+ * disallow all negative sizes. Ranges of size 0 are allowed. -+ */ -+#define DTRACE_INRANGE(testaddr, testsz, baseaddr, basesz) \ -+ ((testaddr) - (baseaddr) < (basesz) && \ -+ (testaddr) + (testsz) - (baseaddr) <= (basesz) && \ -+ (testaddr) + (testsz) >= (testaddr)) -+ -+#define DTRACE_LOADFUNC(bits) \ -+ uint##bits##_t dtrace_load##bits(uintptr_t addr) \ -+ { \ -+ size_t size = bits / NBBY; \ -+ uint##bits##_t rval; \ -+ int i; \ -+ volatile uint16_t *flags = (volatile uint16_t *) \ -+ &this_cpu_core->cpuc_dtrace_flags; \ -+ \ -+ /* \ -+ * Deviation from the OpenSolaris code... Protect \ -+ * against dereferencing the NULL pointer since that \ -+ * really causes us a lot of grief (crash). \ -+ */ \ -+ if (addr == 0) { \ -+ *flags |= CPU_DTRACE_BADADDR; \ -+ this_cpu_core->cpuc_dtrace_illval = addr; \ -+ return 0; \ -+ } \ -+ \ -+ DTRACE_ALIGNCHECK(addr, size, flags); \ -+ \ -+ for (i = 0; i < dtrace_toxranges; i++) { \ -+ if (addr >= dtrace_toxrange[i].dtt_limit) \ -+ continue; \ -+ \ -+ if (addr + size <= dtrace_toxrange[i].dtt_base) \ -+ continue; \ -+ \ -+ /* \ -+ * This address falls within a toxic region. \ -+ */ \ -+ *flags |= CPU_DTRACE_BADADDR; \ -+ this_cpu_core->cpuc_dtrace_illval = addr; \ -+ return 0; \ -+ } \ -+ \ -+ *flags |= CPU_DTRACE_NOFAULT; \ -+ rval = *((volatile uint##bits##_t *)addr); \ -+ *flags &= ~CPU_DTRACE_NOFAULT; \ -+ \ -+ return !(*flags & CPU_DTRACE_FAULT) ? rval : 0; \ -+ } -+ -+/* -+ * Use the DTRACE_LOADFUNC macro to define functions for each of loading a -+ * uint8_t, a uint16_t, a uint32_t and a uint64_t. -+ */ -+DTRACE_LOADFUNC(8) -+DTRACE_LOADFUNC(16) -+DTRACE_LOADFUNC(32) -+DTRACE_LOADFUNC(64) -+ -+#define DT_BSWAP_8(x) ((x) & 0xff) -+#define DT_BSWAP_16(x) ((DT_BSWAP_8(x) << 8) | DT_BSWAP_8((x) >> 8)) -+#define DT_BSWAP_32(x) ((DT_BSWAP_16(x) << 16) | DT_BSWAP_16((x) >> 16)) -+#define DT_BSWAP_64(x) ((DT_BSWAP_32(x) << 32) | DT_BSWAP_32((x) >> 32)) -+ -+static int dtrace_inscratch(uintptr_t dest, size_t size, -+ struct dtrace_mstate *mstate) -+{ -+ if (dest < mstate->dtms_scratch_base) -+ return 0; -+ -+ if (dest + size < dest) -+ return 0; -+ -+ if (dest + size > mstate->dtms_scratch_ptr) -+ return 0; -+ -+ return 1; -+} -+ -+static int dtrace_canstore_statvar(uint64_t addr, size_t sz, -+ struct dtrace_statvar **svars, int nsvars) -+{ -+ int i; -+ -+ for (i = 0; i < nsvars; i++) { -+ struct dtrace_statvar *svar = svars[i]; -+ -+ if (svar == NULL || svar->dtsv_size == 0) -+ continue; -+ -+ if (DTRACE_INRANGE(addr, sz, svar->dtsv_data, svar->dtsv_size)) -+ return 1; -+ } -+ -+ return 0; -+} -+ -+/* -+ * Check to see if the address is within a memory region to which a store may -+ * be issued. This includes the DTrace scratch areas, and any DTrace variable -+ * region. The caller of dtrace_canstore() is responsible for performing any -+ * alignment checks that are needed before stores are actually executed. -+ */ -+static int dtrace_canstore(uint64_t addr, size_t sz, -+ struct dtrace_mstate *mstate, -+ struct dtrace_vstate *vstate) -+{ -+ /* -+ * First, check to see if the address is in scratch space... -+ */ -+ if (DTRACE_INRANGE(addr, sz, mstate->dtms_scratch_base, -+ mstate->dtms_scratch_size)) -+ return 1; -+ -+ /* -+ * Now check to see if it's a dynamic variable. This check will pick -+ * up both thread-local variables and any global dynamically-allocated -+ * variables. -+ */ -+ if (DTRACE_INRANGE(addr, sz, (uintptr_t)vstate->dtvs_dynvars.dtds_base, -+ vstate->dtvs_dynvars.dtds_size)) { -+ struct dtrace_dstate *dstate = &vstate->dtvs_dynvars; -+ uintptr_t base = (uintptr_t)dstate->dtds_base + -+ (dstate->dtds_hashsize * -+ sizeof(struct dtrace_dynhash)); -+ uintptr_t chunkoffs; -+ uint64_t num; -+ -+ /* -+ * Before we assume that we can store here, we need to make -+ * sure that it isn't in our metadata -- storing to our -+ * dynamic variable metadata would corrupt our state. For -+ * the range to not include any dynamic variable metadata, -+ * it must: -+ * -+ * (1) Start above the hash table that is at the base of -+ * the dynamic variable space -+ * -+ * (2) Have a starting chunk offset that is beyond the -+ * dtrace_dynvar_t that is at the base of every chunk -+ * -+ * (3) Not span a chunk boundary -+ */ -+ if (addr < base) -+ return 0; -+ -+ num = addr - base; -+ chunkoffs = do_div(num, dstate->dtds_chunksize); -+ -+ if (chunkoffs < sizeof(struct dtrace_dynvar)) -+ return 0; -+ -+ if (chunkoffs + sz > dstate->dtds_chunksize) -+ return 0; -+ -+ return 1; -+ } -+ -+ /* -+ * Finally, check the static local and global variables. These checks -+ * take the longest, so we perform them last. -+ */ -+ if (dtrace_canstore_statvar(addr, sz, vstate->dtvs_locals, -+ vstate->dtvs_nlocals)) -+ return 1; -+ -+ if (dtrace_canstore_statvar(addr, sz, vstate->dtvs_globals, -+ vstate->dtvs_nglobals)) -+ return 1; -+ -+ return 0; -+} -+ -+/* -+ * Convenience routine to check to see if the address is within a memory -+ * region in which a load may be issued given the user's privilege level; -+ * if not, it sets the appropriate error flags and loads 'addr' into the -+ * illegal value slot. -+ * -+ * DTrace subroutines (DIF_SUBR_*) should use this helper to implement -+ * appropriate memory access protection. -+ */ -+int -+dtrace_canload(uintptr_t addr, size_t sz, struct dtrace_mstate *mstate, -+ struct dtrace_vstate *vstate) -+{ -+ volatile uintptr_t *illval = &this_cpu_core->cpuc_dtrace_illval; -+ -+ /* -+ * If we hold the privilege to read from kernel memory, then -+ * everything is readable. -+ */ -+ if ((mstate->dtms_access & DTRACE_ACCESS_KERNEL) != 0) -+ return 1; -+ -+ /* -+ * You can obviously read that which you can store. -+ */ -+ if (dtrace_canstore(addr, sz, mstate, vstate)) -+ return 1; -+ -+ /* -+ * We're allowed to read from our own string table. -+ */ -+ if (DTRACE_INRANGE(addr, sz, (uintptr_t)mstate->dtms_difo->dtdo_strtab, -+ mstate->dtms_difo->dtdo_strlen)) -+ return 1; -+ -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_KPRIV); -+ *illval = addr; -+ -+ return 0; -+} -+ -+/* -+ * Convenience routine to check to see if a given string is within a memory -+ * region in which a load may be issued given the user's privilege level; -+ * this exists so that we don't need to issue unnecessary dtrace_strlen() -+ * calls in the event that the user has all privileges. -+ */ -+static int -+dtrace_strcanload(uint64_t addr, size_t sz, struct dtrace_mstate *mstate, -+ struct dtrace_vstate *vstate) -+{ -+ size_t strsz; -+ -+ /* -+ * If we hold the privilege to read from kernel memory, then -+ * everything is readable. -+ */ -+ if ((mstate->dtms_access & DTRACE_ACCESS_KERNEL) != 0) -+ return 1; -+ -+ strsz = 1 + dtrace_strlen((char *)(uintptr_t)addr, sz); -+ if (dtrace_canload(addr, strsz, mstate, vstate)) -+ return 1; -+ -+ return 0; -+} -+ -+/* -+ * Convenience routine to check to see if a given variable is within a memory -+ * region in which a load may be issued given the user's privilege level. -+ */ -+int dtrace_vcanload(void *src, struct dtrace_diftype *diftype, -+ struct dtrace_mstate *mstate, -+ struct dtrace_vstate *vstate) -+{ -+ size_t sz; -+ -+ ASSERT(diftype->dtdt_flags & DIF_TF_BYREF); -+ -+ /* -+ * If we hold the privilege to read from kernel memory, then -+ * everything is readable. -+ */ -+ if ((mstate->dtms_access & DTRACE_ACCESS_KERNEL) != 0) -+ return 1; -+ -+ if (diftype->dtdt_kind == DIF_TYPE_STRING) -+ sz = dtrace_strlen( -+ src, -+ vstate->dtvs_state->dts_options[DTRACEOPT_STRSIZE] -+ ) + 1; -+ else -+ sz = diftype->dtdt_size; -+ -+ return dtrace_canload((uintptr_t)src, sz, mstate, vstate); -+} -+ -+/* -+ * Copy src to dst using safe memory accesses. The src is assumed to be unsafe -+ * memory specified by the DIF program. The dst is assumed to be safe memory -+ * that we can store to directly because it is managed by DTrace. As with -+ * standard bcopy, overlapping copies are handled properly. -+ */ -+static void dtrace_bcopy(const void *src, void *dst, size_t len) -+{ -+ if (len != 0) { -+ uint8_t *s1 = dst; -+ const uint8_t *s2 = src; -+ -+ if (s1 <= s2) { -+ do { -+ *s1++ = dtrace_load8((uintptr_t)s2++); -+ } while (--len != 0); -+ } else { -+ s2 += len; -+ s1 += len; -+ -+ do { -+ *--s1 = dtrace_load8((uintptr_t)--s2); -+ } while (--len != 0); -+ } -+ } -+} -+ -+/* -+ * Copy src to dst using safe memory accesses, up to either the specified -+ * length, or the point that a nul byte is encountered. The src is assumed to -+ * be unsafe memory specified by the DIF program. The dst is assumed to be -+ * safe memory that we can store to directly because it is managed by DTrace. -+ * Unlike dtrace_bcopy(), overlapping regions are not handled. -+ */ -+static void dtrace_strcpy(const void *src, void *dst, size_t len) -+{ -+ if (len != 0) { -+ uint8_t *s1 = dst, c; -+ const uint8_t *s2 = src; -+ -+ do { -+ *s1++ = c = dtrace_load8((uintptr_t)s2++); -+ } while (--len != 0 && c != '\0'); -+ } -+} -+/* -+ * Copy src to dst, deriving the size and type from the specified (BYREF) -+ * variable type. The src is assumed to be unsafe memory specified by the DIF -+ * program. The dst is assumed to be DTrace variable memory that is of the -+ * specified type; we assume that we can store to directly. -+ */ -+static void dtrace_vcopy(void *src, void *dst, struct dtrace_diftype *diftype) -+{ -+ ASSERT(diftype->dtdt_flags & DIF_TF_BYREF); -+ -+ if (diftype->dtdt_kind == DIF_TYPE_STRING) -+ dtrace_strcpy(src, dst, diftype->dtdt_size); -+ else -+ dtrace_bcopy(src, dst, diftype->dtdt_size); -+} -+ -+/* -+ * Compare s1 to s2 using safe memory accesses. The s1 data is assumed to be -+ * unsafe memory specified by the DIF program. The s2 data is assumed to be -+ * safe memory that we can access directly because it is managed by DTrace. -+ */ -+static int dtrace_bcmp(const void *s1, const void *s2, size_t len) -+{ -+ volatile uint16_t *flags; -+ -+ flags = (volatile uint16_t *)&this_cpu_core->cpuc_dtrace_flags; -+ -+ if (s1 == s2) -+ return 0; -+ -+ if (s1 == NULL || s2 == NULL) -+ return 1; -+ -+ if (s1 != s2 && len != 0) { -+ const uint8_t *ps1 = s1; -+ const uint8_t *ps2 = s2; -+ -+ do { -+ if (dtrace_load8((uintptr_t)ps1++) != *ps2++) -+ return 1; -+ } while (--len != 0 && !(*flags & CPU_DTRACE_FAULT)); -+ } -+ -+ return 0; -+} -+ -+/* -+ * Zero the specified region using a simple byte-by-byte loop. Note that this -+ * is for safe DTrace-managed memory only. -+ */ -+void dtrace_bzero(void *dst, size_t len) -+{ -+ uchar_t *cp; -+ -+ for (cp = dst; len != 0; len--) -+ *cp++ = 0; -+} -+ -+#define DTRACE_DYNHASH_FREE 0 -+#define DTRACE_DYNHASH_SINK 1 -+#define DTRACE_DYNHASH_VALID 2 -+ -+/* -+ * Depending on the value of the op parameter, this function looks-up, -+ * allocates or deallocates an arbitrarily-keyed dynamic variable. If an -+ * allocation is requested, this function will return a pointer to a -+ * dtrace_dynvar_t corresponding to the allocated variable -- or NULL if no -+ * variable can be allocated. If NULL is returned, the appropriate counter -+ * will be incremented. -+ */ -+static struct dtrace_dynvar *dtrace_dynvar(struct dtrace_dstate *dstate, -+ uint_t nkeys, -+ struct dtrace_key *key, -+ size_t dsize, -+ enum dtrace_dynvar_op op, -+ struct dtrace_mstate *mstate, -+ struct dtrace_vstate *vstate) -+{ -+ uint64_t hashval = DTRACE_DYNHASH_VALID; -+ struct dtrace_dynhash *hash = dstate->dtds_hash; -+ struct dtrace_dynvar *free, *new_free, *next, *dvar, *start, -+ *prev = NULL; -+ processorid_t me = smp_processor_id(), cpu = me; -+ struct dtrace_dstate_percpu *dcpu = &dstate->dtds_percpu[me]; -+ size_t bucket, ksize; -+ size_t chunksize = dstate->dtds_chunksize; -+ uintptr_t kdata, lock; -+ enum dtrace_dstate_state nstate; -+ uint_t i; -+ -+ ASSERT(nkeys != 0); -+ -+ /* -+ * Hash the key. As with aggregations, we use Jenkins' "One-at-a-time" -+ * algorithm. For the by-value portions, we perform the algorithm in -+ * 16-bit chunks (as opposed to 8-bit chunks). This speeds things up a -+ * bit, and seems to have only a minute effect on distribution. For -+ * the by-reference data, we perform "One-at-a-time" iterating (safely) -+ * over each referenced byte. It's painful to do this, but it's much -+ * better than pathological hash distribution. The efficacy of the -+ * hashing algorithm (and a comparison with other algorithms) may be -+ * found by running the ::dtrace_dynstat MDB dcmd. -+ */ -+ for (i = 0; i < nkeys; i++) { -+ if (key[i].dttk_size == 0) { -+ uint64_t val = key[i].dttk_value; -+ -+ hashval += (val >> 48) & 0xffff; -+ hashval += (hashval << 10); -+ hashval ^= (hashval >> 6); -+ -+ hashval += (val >> 32) & 0xffff; -+ hashval += (hashval << 10); -+ hashval ^= (hashval >> 6); -+ -+ hashval += (val >> 16) & 0xffff; -+ hashval += (hashval << 10); -+ hashval ^= (hashval >> 6); -+ -+ hashval += val & 0xffff; -+ hashval += (hashval << 10); -+ hashval ^= (hashval >> 6); -+ } else { -+ /* -+ * This is incredibly painful, but it beats the hell -+ * out of the alternative. -+ */ -+ uint64_t j, size = key[i].dttk_size; -+ uintptr_t base = (uintptr_t)key[i].dttk_value; -+ -+ if (!dtrace_canload(base, size, mstate, vstate)) -+ break; -+ -+ for (j = 0; j < size; j++) { -+ hashval += dtrace_load8(base + j); -+ hashval += (hashval << 10); -+ hashval ^= (hashval >> 6); -+ } -+ } -+ } -+ -+ if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_FAULT)) -+ return NULL; -+ -+ hashval += (hashval << 3); -+ hashval ^= (hashval >> 11); -+ hashval += (hashval << 15); -+ -+ /* -+ * There is a remote chance (ideally, 1 in 2^31) that our hashval -+ * comes out to be one of our two sentinel hash values. If this -+ * actually happens, we set the hashval to be a value known to be a -+ * non-sentinel value. -+ */ -+ if (hashval == DTRACE_DYNHASH_FREE || hashval == DTRACE_DYNHASH_SINK) -+ hashval = DTRACE_DYNHASH_VALID; -+ -+ /* -+ * Yes, it's painful to do a divide here. If the cycle count becomes -+ * important here, tricks can be pulled to reduce it. (However, it's -+ * critical that hash collisions be kept to an absolute minimum; -+ * they're much more painful than a divide.) It's better to have a -+ * solution that generates few collisions and still keeps things -+ * relatively simple. -+ * -+ * Linux cannot do a straight 64-bit divide without gcc requiring -+ * linking in code that the kernel doesn't link, so we need to use an -+ * alternative. -+ * -+ * bucket = hashval % dstate->dtds_hashsize; -+ */ -+ { -+ uint64_t num; -+ -+ num = hashval; -+ bucket = do_div(num, dstate->dtds_hashsize); -+ } -+ -+ if (op == DTRACE_DYNVAR_DEALLOC) { -+ volatile uintptr_t *lockp = &hash[bucket].dtdh_lock; -+ -+ for (;;) { -+ while ((lock = *lockp) & 1) -+ continue; -+ -+ if (cmpxchg(lockp, lock, (lock + 1)) == lock) -+ break; -+ } -+ -+ dtrace_membar_producer(); -+ } -+ -+top: -+ prev = NULL; -+ lock = hash[bucket].dtdh_lock; -+ -+ dtrace_membar_consumer(); -+ -+ start = hash[bucket].dtdh_chain; -+ ASSERT(start != NULL && (start->dtdv_hashval == DTRACE_DYNHASH_SINK || -+ start->dtdv_hashval != DTRACE_DYNHASH_FREE || -+ op != DTRACE_DYNVAR_DEALLOC)); -+ -+ for (dvar = start; dvar != NULL; dvar = dvar->dtdv_next) { -+ struct dtrace_tuple *dtuple = &dvar->dtdv_tuple; -+ struct dtrace_key *dkey = &dtuple->dtt_key[0]; -+ -+ if (dvar->dtdv_hashval != hashval) { -+ if (dvar->dtdv_hashval == DTRACE_DYNHASH_SINK) { -+ /* -+ * We've reached the sink, and therefore the -+ * end of the hash chain; we can kick out of -+ * the loop knowing that we have seen a valid -+ * snapshot of state. -+ */ -+ ASSERT(dvar->dtdv_next == NULL); -+ ASSERT(dvar == &dtrace_dynhash_sink); -+ break; -+ } -+ -+ if (dvar->dtdv_hashval == DTRACE_DYNHASH_FREE) { -+ /* -+ * We've gone off the rails: somewhere along -+ * the line, one of the members of this hash -+ * chain was deleted. Note that we could also -+ * detect this by simply letting this loop run -+ * to completion, as we would eventually hit -+ * the end of the dirty list. However, we -+ * want to avoid running the length of the -+ * dirty list unnecessarily (it might be quite -+ * long), so we catch this as early as -+ * possible by detecting the hash marker. In -+ * this case, we simply set dvar to NULL and -+ * break; the conditional after the loop will -+ * send us back to top. -+ */ -+ dvar = NULL; -+ break; -+ } -+ -+ goto next; -+ } -+ -+ if (dtuple->dtt_nkeys != nkeys) -+ goto next; -+ -+ for (i = 0; i < nkeys; i++, dkey++) { -+ if (dkey->dttk_size != key[i].dttk_size) -+ goto next; /* size or type mismatch */ -+ -+ if (dkey->dttk_size != 0) { -+ if (dtrace_bcmp( -+ (void *)(uintptr_t)key[i].dttk_value, -+ (void *)(uintptr_t)dkey->dttk_value, -+ dkey->dttk_size)) -+ goto next; -+ } else { -+ if (dkey->dttk_value != key[i].dttk_value) -+ goto next; -+ } -+ } -+ -+ if (op != DTRACE_DYNVAR_DEALLOC) -+ return dvar; -+ -+ ASSERT(dvar->dtdv_next == NULL || -+ dvar->dtdv_next->dtdv_hashval != DTRACE_DYNHASH_FREE); -+ -+ if (prev != NULL) { -+ ASSERT(hash[bucket].dtdh_chain != dvar); -+ ASSERT(start != dvar); -+ ASSERT(prev->dtdv_next == dvar); -+ prev->dtdv_next = dvar->dtdv_next; -+ } else { -+ if (cmpxchg(&hash[bucket].dtdh_chain, start, -+ dvar->dtdv_next) != start) { -+ /* -+ * We have failed to atomically swing the -+ * hash table head pointer, presumably because -+ * of a conflicting allocation on another CPU. -+ * We need to reread the hash chain and try -+ * again. -+ */ -+ goto top; -+ } -+ } -+ -+ dtrace_membar_producer(); -+ -+ /* -+ * Now set the hash value to indicate that it's free. -+ */ -+ ASSERT(hash[bucket].dtdh_chain != dvar); -+ dvar->dtdv_hashval = DTRACE_DYNHASH_FREE; -+ -+ dtrace_membar_producer(); -+ -+ /* -+ * Set the next pointer to point at the dirty list, and -+ * atomically swing the dirty pointer to the newly freed dvar. -+ */ -+ do { -+ next = dcpu->dtdsc_dirty; -+ dvar->dtdv_next = next; -+ } while (cmpxchg(&dcpu->dtdsc_dirty, next, dvar) != next); -+ -+ /* -+ * Finally, unlock this hash bucket. -+ */ -+ ASSERT(hash[bucket].dtdh_lock == lock); -+ ASSERT(lock & 1); -+ hash[bucket].dtdh_lock++; -+ -+ return NULL; -+next: -+ prev = dvar; -+ continue; -+ } -+ -+ if (dvar == NULL) { -+ /* -+ * If dvar is NULL, it is because we went off the rails: -+ * one of the elements that we traversed in the hash chain -+ * was deleted while we were traversing it. In this case, -+ * we assert that we aren't doing a dealloc (deallocs lock -+ * the hash bucket to prevent themselves from racing with -+ * one another), and retry the hash chain traversal. -+ */ -+ ASSERT(op != DTRACE_DYNVAR_DEALLOC); -+ goto top; -+ } -+ -+ if (op != DTRACE_DYNVAR_ALLOC) { -+ /* -+ * If we are not to allocate a new variable, we want to -+ * return NULL now. Before we return, check that the value -+ * of the lock word hasn't changed. If it has, we may have -+ * seen an inconsistent snapshot. -+ */ -+ if (op == DTRACE_DYNVAR_NOALLOC) { -+ if (hash[bucket].dtdh_lock != lock) -+ goto top; -+ } else { -+ ASSERT(op == DTRACE_DYNVAR_DEALLOC); -+ ASSERT(hash[bucket].dtdh_lock == lock); -+ ASSERT(lock & 1); -+ hash[bucket].dtdh_lock++; -+ } -+ -+ return NULL; -+ } -+ -+ /* -+ * We need to allocate a new dynamic variable. The size we need is the -+ * size of dtrace_dynvar plus the size of nkeys dtrace_key_t's plus the -+ * size of any auxiliary key data (rounded up to 8-byte alignment) plus -+ * the size of any referred-to data (dsize). We then round the final -+ * size up to the chunksize for allocation. -+ */ -+ for (ksize = 0, i = 0; i < nkeys; i++) -+ ksize += P2ROUNDUP(key[i].dttk_size, sizeof(uint64_t)); -+ -+ /* -+ * This should be pretty much impossible, but could happen if, say, -+ * strange DIF specified the tuple. Ideally, this should be an -+ * assertion and not an error condition -- but that requires that the -+ * chunksize calculation in dtrace_difo_chunksize() be absolutely -+ * bullet-proof. (That is, it must not be able to be fooled by -+ * malicious DIF.) Given the lack of backwards branches in DIF, -+ * solving this would presumably not amount to solving the Halting -+ * Problem -- but it still seems awfully hard. -+ */ -+ if (sizeof(struct dtrace_dynvar) + -+ sizeof(struct dtrace_key) * (nkeys - 1) + -+ ksize + dsize > chunksize) { -+ dcpu->dtdsc_drops++; -+ return NULL; -+ } -+ -+ nstate = DTRACE_DSTATE_EMPTY; -+ -+ do { -+retry: -+ free = dcpu->dtdsc_free; -+ -+ if (free == NULL) { -+ struct dtrace_dynvar *clean = dcpu->dtdsc_clean; -+ void *rval; -+ -+ if (clean == NULL) { -+ /* -+ * We're out of dynamic variable space on -+ * this CPU. Unless we have tried all CPUs, -+ * we'll try to allocate from a different -+ * CPU. -+ */ -+ switch (dstate->dtds_state) { -+ case DTRACE_DSTATE_CLEAN: { -+ enum dtrace_dstate_state *sp = -+ (enum dtrace_dstate_state *) -+ &dstate->dtds_state; -+ -+ if (++cpu >= NR_CPUS) -+ cpu = 0; -+ -+ if (dcpu->dtdsc_dirty != NULL && -+ nstate == DTRACE_DSTATE_EMPTY) -+ nstate = DTRACE_DSTATE_DIRTY; -+ -+ if (dcpu->dtdsc_rinsing != NULL) -+ nstate = DTRACE_DSTATE_RINSING; -+ -+ dcpu = &dstate->dtds_percpu[cpu]; -+ -+ if (cpu != me) -+ goto retry; -+ -+ cmpxchg(sp, DTRACE_DSTATE_CLEAN, -+ nstate); -+ -+ /* -+ * To increment the correct bean -+ * counter, take another lap. -+ */ -+ goto retry; -+ } -+ -+ case DTRACE_DSTATE_DIRTY: -+ dcpu->dtdsc_dirty_drops++; -+ break; -+ -+ case DTRACE_DSTATE_RINSING: -+ dcpu->dtdsc_rinsing_drops++; -+ break; -+ -+ case DTRACE_DSTATE_EMPTY: -+ dcpu->dtdsc_drops++; -+ break; -+ } -+ -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_DROP); -+ return NULL; -+ } -+ -+ /* -+ * The clean list appears to be non-empty. We want to -+ * move the clean list to the free list; we start by -+ * moving the clean pointer aside. -+ */ -+ if (cmpxchg(&dcpu->dtdsc_clean, clean, NULL) != clean) -+ /* -+ * We are in one of two situations: -+ * -+ * (a) The clean list was switched to the -+ * free list by another CPU. -+ * -+ * (b) The clean list was added to by the -+ * cleansing cyclic. -+ * -+ * In either of these situations, we can -+ * just reattempt the free list allocation. -+ */ -+ goto retry; -+ -+ ASSERT(clean->dtdv_hashval == DTRACE_DYNHASH_FREE); -+ -+ /* -+ * Now we'll move the clean list to the free list. -+ * It's impossible for this to fail: the only way -+ * the free list can be updated is through this -+ * code path, and only one CPU can own the clean list. -+ * Thus, it would only be possible for this to fail if -+ * this code were racing with dtrace_dynvar_clean(). -+ * (That is, if dtrace_dynvar_clean() updated the clean -+ * list, and we ended up racing to update the free -+ * list.) This race is prevented by the dtrace_sync() -+ * in dtrace_dynvar_clean() -- which flushes the -+ * owners of the clean lists out before resetting -+ * the clean lists. -+ */ -+ rval = cmpxchg(&dcpu->dtdsc_free, NULL, clean); -+ ASSERT(rval == NULL); -+ -+ goto retry; -+ } -+ -+ dvar = free; -+ new_free = dvar->dtdv_next; -+ } while (cmpxchg(&dcpu->dtdsc_free, free, new_free) != free); -+ -+ /* -+ * We have now allocated a new chunk. We copy the tuple keys into the -+ * tuple array and copy any referenced key data into the data space -+ * following the tuple array. As we do this, we relocate dttk_value -+ * in the final tuple to point to the key data address in the chunk. -+ */ -+ kdata = (uintptr_t)&dvar->dtdv_tuple.dtt_key[nkeys]; -+ dvar->dtdv_data = (void *)(kdata + ksize); -+ dvar->dtdv_tuple.dtt_nkeys = nkeys; -+ -+ for (i = 0; i < nkeys; i++) { -+ struct dtrace_key *dkey = &dvar->dtdv_tuple.dtt_key[i]; -+ size_t kesize = key[i].dttk_size; -+ -+ if (kesize != 0) { -+ dtrace_bcopy( -+ (const void *)(uintptr_t)key[i].dttk_value, -+ (void *)kdata, kesize); -+ dkey->dttk_value = kdata; -+ kdata += P2ROUNDUP(kesize, sizeof(uint64_t)); -+ } else -+ dkey->dttk_value = key[i].dttk_value; -+ -+ dkey->dttk_size = kesize; -+ } -+ -+ ASSERT(dvar->dtdv_hashval == DTRACE_DYNHASH_FREE); -+ dvar->dtdv_hashval = hashval; -+ dvar->dtdv_next = start; -+ -+ if (cmpxchg(&hash[bucket].dtdh_chain, start, dvar) == start) -+ return dvar; -+ -+ /* -+ * The cas has failed. Either another CPU is adding an element to -+ * this hash chain, or another CPU is deleting an element from this -+ * hash chain. The simplest way to deal with both of these cases -+ * (though not necessarily the most efficient) is to free our -+ * allocated block and tail-call ourselves. Note that the free is -+ * to the dirty list and _not_ to the free list. This is to prevent -+ * races with allocators, above. -+ */ -+ dvar->dtdv_hashval = DTRACE_DYNHASH_FREE; -+ -+ dtrace_membar_producer(); -+ -+ do { -+ free = dcpu->dtdsc_dirty; -+ dvar->dtdv_next = free; -+ } while (cmpxchg(&dcpu->dtdsc_dirty, free, dvar) != free); -+ -+ return dtrace_dynvar(dstate, nkeys, key, dsize, op, mstate, vstate); -+} -+ -+/* -+ * Return a string. In the event that the user lacks the privilege to access -+ * arbitrary kernel memory, we copy the string out to scratch memory so that we -+ * don't fail access checking. -+ * -+ * dtrace_dif_variable() uses this routine as a helper for various -+ * builtin values such as 'execname' and 'probefunc.' -+ */ -+static uintptr_t dtrace_dif_varstr(uintptr_t addr, struct dtrace_state *state, -+ struct dtrace_mstate *mstate) -+{ -+ uint64_t size = state->dts_options[DTRACEOPT_STRSIZE]; -+ uintptr_t ret; -+ size_t strsz; -+ -+ /* -+ * The easy case: this probe is allowed to read all of memory, so -+ * we can just return this as a vanilla pointer. -+ */ -+ if ((mstate->dtms_access & DTRACE_ACCESS_KERNEL) != 0) -+ return addr; -+ -+ /* -+ * This is the tougher case: we copy the string in question from -+ * kernel memory into scratch memory and return it that way: this -+ * ensures that we won't trip up when access checking tests the -+ * BYREF return value. -+ */ -+ strsz = dtrace_strlen((char *)addr, size) + 1; -+ -+ if (mstate->dtms_scratch_ptr + strsz > -+ mstate->dtms_scratch_base + mstate->dtms_scratch_size) { -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); -+ return (uintptr_t)NULL; -+ } -+ -+ dtrace_strcpy((const void *)addr, (void *)mstate->dtms_scratch_ptr, -+ strsz); -+ ret = mstate->dtms_scratch_ptr; -+ mstate->dtms_scratch_ptr += strsz; -+ -+ return ret; -+} -+ -+/* -+ * This function implements the DIF emulator's variable lookups. The emulator -+ * passes a reserved variable identifier and optional built-in array index. -+ * -+ * This function is annotated to be always inlined in dtrace_dif_emulate() -+ * because (1) that is the only place where it is called from, and (2) it has -+ * come to our attention that some GCC versions inline it automatically while -+ * others do not and that messes up the number of frames to skip (aframes). -+ */ -+static __always_inline uint64_t dtrace_dif_variable(struct dtrace_mstate *mstate, -+ struct dtrace_state *state, -+ uint64_t v, uint64_t ndx) -+{ -+ /* -+ * If we're accessing one of the uncached arguments, we'll turn this -+ * into a reference in the args array. -+ */ -+ if (v >= DIF_VAR_ARG0 && v <= DIF_VAR_ARG9) { -+ ndx = v - DIF_VAR_ARG0; -+ v = DIF_VAR_ARGS; -+ } -+ -+ switch (v) { -+ case DIF_VAR_ARGS: -+ ASSERT(mstate->dtms_present & DTRACE_MSTATE_ARGS); -+ -+ if (ndx >= DTRACE_MSTATE_ARGS_MAX) { -+ int aframes = -+ mstate->dtms_probe->dtpr_aframes + 1; -+ struct dtrace_provider *pv; -+ uint64_t val; -+ -+ pv = mstate->dtms_probe->dtpr_provider; -+ if (pv->dtpv_pops.dtps_getargval != NULL) -+ val = pv->dtpv_pops.dtps_getargval( -+ pv->dtpv_arg, -+ mstate->dtms_probe->dtpr_id, -+ mstate->dtms_probe->dtpr_arg, -+ ndx, aframes); -+ else -+ val = dtrace_getarg(ndx, aframes); -+ -+ /* -+ * This is regrettably required to keep the compiler -+ * from tail-optimizing the call to dtrace_getarg(). -+ * The condition always evaluates to true, but the -+ * compiler has no way of figuring that out a priori. -+ * (None of this would be necessary if the compiler -+ * could be relied upon to _always_ tail-optimize -+ * the call to dtrace_getarg() -- but it can't.) -+ */ -+ if (mstate->dtms_probe != NULL) -+ return val; -+ -+ ASSERT(0); -+ } -+ -+ return mstate->dtms_arg[ndx]; -+ -+ case DIF_VAR_UREGS: { -+ if (!dtrace_priv_proc(state)) -+ return 0; -+ -+ return dtrace_getreg(current, ndx); -+ } -+ -+ case DIF_VAR_CURTHREAD: -+ if (!dtrace_priv_kernel(state)) -+ return 0; -+ -+ return (uint64_t)(uintptr_t)current; -+ -+ case DIF_VAR_TIMESTAMP: -+ if (!(mstate->dtms_present & DTRACE_MSTATE_TIMESTAMP)) { -+ mstate->dtms_timestamp = dtrace_gethrtime(); -+ mstate->dtms_present |= DTRACE_MSTATE_TIMESTAMP; -+ } -+ -+ return ktime_to_ns(mstate->dtms_timestamp); -+ -+ case DIF_VAR_WALLTIMESTAMP: -+ return ktime_to_ns(dtrace_get_walltime()); -+ -+ case DIF_VAR_VTIMESTAMP: -+ ASSERT(dtrace_vtime_references != 0); -+ -+ if (current->dt_task != NULL) -+ return ktime_to_ns(current->dt_task->dt_vtime); -+ -+ /* -+ * This is not ideal but without any data available -+ * there is no reasonable default value for vtimestamp -+ * variable. -+ */ -+ return ktime_to_ns(0); -+ -+ case DIF_VAR_IPL: -+ if (!dtrace_priv_kernel(state)) -+ return 0; -+ -+ if (!(mstate->dtms_present & DTRACE_MSTATE_IPL)) { -+ mstate->dtms_ipl = dtrace_getipl(); -+ mstate->dtms_present |= DTRACE_MSTATE_IPL; -+ } -+ -+ return mstate->dtms_ipl; -+ -+ case DIF_VAR_EPID: -+ ASSERT(mstate->dtms_present & DTRACE_MSTATE_EPID); -+ ASSERT(mstate->dtms_present & DTRACE_MSTATE_EPID); -+ -+ return mstate->dtms_epid; -+ -+ case DIF_VAR_ID: -+ ASSERT(mstate->dtms_present & DTRACE_MSTATE_PROBE); -+ return mstate->dtms_probe->dtpr_id; -+ -+ case DIF_VAR_STACKDEPTH: -+ if (!dtrace_priv_kernel(state)) -+ return 0; -+ if (!(mstate->dtms_present & DTRACE_MSTATE_STACKDEPTH)) { -+ int aframes = mstate->dtms_probe->dtpr_aframes + 2; -+ -+ mstate->dtms_stackdepth = dtrace_getstackdepth( -+ mstate, aframes); -+ mstate->dtms_present |= DTRACE_MSTATE_STACKDEPTH; -+ } -+ -+ return mstate->dtms_stackdepth; -+ -+ case DIF_VAR_USTACKDEPTH: -+ if (!dtrace_priv_proc(state)) -+ return 0; -+ -+ if (!(mstate->dtms_present & DTRACE_MSTATE_USTACKDEPTH)) { -+ /* -+ * See comment in DIF_VAR_PID. -+ */ -+ if (DTRACE_ANCHORED(mstate->dtms_probe) && -+ in_interrupt()) -+ mstate->dtms_ustackdepth = 0; -+ else -+ mstate->dtms_ustackdepth = -+ dtrace_getustackdepth(); -+ -+ mstate->dtms_present |= DTRACE_MSTATE_USTACKDEPTH; -+ } -+ -+ return mstate->dtms_ustackdepth; -+ -+ case DIF_VAR_CALLER: -+ if (!dtrace_priv_kernel(state)) -+ return 0; -+ -+ if (!(mstate->dtms_present & DTRACE_MSTATE_CALLER)) { -+ int aframes = mstate->dtms_probe->dtpr_aframes + 1; -+ -+ if (!DTRACE_ANCHORED(mstate->dtms_probe)) { -+ /* -+ * If this is an unanchored probe, we are -+ * required to go through the slow path: -+ * dtrace_caller() only guarantees correct -+ * results for anchored probes. -+ */ -+ uint64_t caller[2]; -+ -+ dtrace_getpcstack(caller, 2, aframes, -+ (uint32_t *)(uintptr_t) -+ mstate->dtms_arg[0]); -+ mstate->dtms_caller = caller[1]; -+ } else if ((mstate->dtms_caller = -+ dtrace_caller(aframes, 0)) == -1) { -+ /* -+ * We have failed to do this the quick way; -+ * we must resort to the slower approach of -+ * calling dtrace_getpcstack(). -+ */ -+ uint64_t caller; -+ -+ dtrace_getpcstack(&caller, 1, aframes, NULL); -+ mstate->dtms_caller = caller; -+ } -+ -+ mstate->dtms_present |= DTRACE_MSTATE_CALLER; -+ } -+ -+ return mstate->dtms_caller; -+ -+ case DIF_VAR_UCALLER: -+ if (!dtrace_priv_proc(state)) -+ return 0; -+ -+ if (!(mstate->dtms_present & DTRACE_MSTATE_UCALLER)) { -+ uint64_t ustack[4]; -+ -+ /* -+ * dtrace_getupcstack() fills in the first uint64_t with -+ * the current PID, and the second uint64_t with the -+ * current TGID. The third uint64_t will be the -+ * program counter at user-level. The fourth uint64_t -+ * will contain the caller, which is what we're after. -+ */ -+ ustack[3] = 0; -+ dtrace_getupcstack(ustack, 4); -+ -+ mstate->dtms_ucaller = ustack[3]; -+ mstate->dtms_present |= DTRACE_MSTATE_UCALLER; -+ } -+ -+ return mstate->dtms_ucaller; -+ -+ case DIF_VAR_PROBEPROV: -+ ASSERT(mstate->dtms_present & DTRACE_MSTATE_PROBE); -+ -+ return dtrace_dif_varstr( -+ (uintptr_t)mstate->dtms_probe->dtpr_provider->dtpv_name, -+ state, mstate); -+ -+ case DIF_VAR_PROBEMOD: -+ ASSERT(mstate->dtms_present & DTRACE_MSTATE_PROBE); -+ return dtrace_dif_varstr( -+ (uintptr_t)mstate->dtms_probe->dtpr_mod, state, -+ mstate); -+ -+ case DIF_VAR_PROBEFUNC: -+ ASSERT(mstate->dtms_present & DTRACE_MSTATE_PROBE); -+ -+ return dtrace_dif_varstr( -+ (uintptr_t)mstate->dtms_probe->dtpr_func, state, -+ mstate); -+ -+ case DIF_VAR_PROBENAME: -+ ASSERT(mstate->dtms_present & DTRACE_MSTATE_PROBE); -+ -+ return dtrace_dif_varstr( -+ (uintptr_t)mstate->dtms_probe->dtpr_name, state, -+ mstate); -+ -+ case DIF_VAR_PID: -+ if (!dtrace_priv_proc(state)) -+ return 0; -+ -+ /* -+ * It is always safe to dereference current, it always points -+ * to a valid task_struct. -+ */ -+ return (uint64_t)current->tgid; -+ -+ case DIF_VAR_PPID: -+ if (!dtrace_priv_proc(state)) -+ return 0; -+ -+ /* -+ * It is always safe to dereference current, it always points -+ * to a valid task_struct. -+ * -+ * Additionally, it is safe to dereference one's parent, since -+ * it is never NULL after process birth. -+ */ -+ return (uint64_t)current->real_parent->tgid; -+ -+ case DIF_VAR_TID: -+ return (uint64_t)current->pid; -+ -+ case DIF_VAR_EXECNAME: -+ if (!dtrace_priv_proc(state)) -+ return 0; -+ -+ /* -+ * It is always safe to dereference current, it always points -+ * to a valid task_struct. -+ */ -+ return dtrace_dif_varstr((uintptr_t)current->comm, state, -+ mstate); -+ -+ case DIF_VAR_ZONENAME: -+ return 0; -+ -+ case DIF_VAR_UID: -+ if (!dtrace_priv_proc(state)) -+ return 0; -+ -+ /* -+ * It is always safe to dereference current, it always points -+ * to a valid task_struct. -+ * -+ * Additionally, it is safe to dereference one's own process -+ * credential, since this is never NULL after process birth. -+ */ -+ return (uint64_t)from_kuid(current_user_ns(), -+ current_real_cred()->uid); -+ -+ case DIF_VAR_GID: -+ if (!dtrace_priv_proc(state)) -+ return 0; -+ -+ /* -+ * It is always safe to dereference current, it always points -+ * to a valid task_struct. -+ * -+ * Additionally, it is safe to dereference one's own process -+ * credential, since this is never NULL after process birth. -+ */ -+ return (uint64_t)from_kgid(current_user_ns(), -+ current_real_cred()->gid); -+ -+ case DIF_VAR_ERRNO: { -+ int64_t arg0; -+ -+ ASSERT(mstate->dtms_present & DTRACE_MSTATE_PROBE); -+ -+ if (!dtrace_priv_proc(state)) -+ return 0; -+ -+ /* -+ * We need to do some magic here to get the correct semantics -+ * for the 'errno' variable. It can only have a non-zero value -+ * when executing a system call, and for Linux, only after the -+ * actual system call implementation has completed, indicating -+ * in its return value either an error code (-2048 < errno < 0) -+ * or a valid result. So, the only time we can expect a valid -+ * value in errno is during the processing of any return probe -+ * in the syscall provider. In all other cases, it should have -+ * the value 0. -+ * -+ * So, we only look at probes that match: syscall:::return -+ */ -+ if (strncmp(mstate->dtms_probe->dtpr_provider->dtpv_name, -+ "syscall", 7) != 0) -+ return 0; -+ if (strncmp(mstate->dtms_probe->dtpr_name, "return", 6) != 0) -+ return 0; -+ -+ /* -+ * Error number is present if arg0 lies between 0 and -2048, -+ * exclusive. -+ */ -+ arg0 = (int64_t)mstate->dtms_arg[ndx]; -+ if (arg0 < 0 && arg0 > -2048) -+ return (uint64_t)-arg0; -+ -+ return 0; -+ } -+ -+ case DIF_VAR_CURCPU: -+ return (uint64_t)(uintptr_t)this_cpu_info; -+ -+ default: -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); -+ return 0; -+ } -+} -+ -+#define DTRACE_V4MAPPED_OFFSET (sizeof(uint32_t) * 3) -+ -+/* -+ * Emulate the execution of DTrace ID subroutines invoked by the call opcode. -+ * Notice that we don't bother validating the proper number of arguments or -+ * their types in the tuple stack. This isn't needed because all argument -+ * interpretation is safe because of our load safety -- the worst that can -+ * happen is that a bogus program can obtain bogus results. -+ */ -+static void dtrace_dif_subr(uint_t subr, uint_t rd, uint64_t *regs, -+ struct dtrace_key *tupregs, int nargs, -+ struct dtrace_mstate *mstate, -+ struct dtrace_state *state) -+{ -+ volatile uint16_t *flags = &this_cpu_core->cpuc_dtrace_flags; -+ volatile uintptr_t *illval = &this_cpu_core->cpuc_dtrace_illval; -+ struct dtrace_vstate *vstate = &state->dts_vstate; -+ struct mutex mtx; -+ -+ union { -+ rwlock_t ri; -+ uintptr_t rw; -+ } r; -+ -+ dt_dbg_dif(" Subroutine %d\n", subr); -+ -+ switch (subr) { -+ case DIF_SUBR_RAND: -+ regs[rd] = ktime_to_ns(dtrace_gethrtime()) * 2416 + 374441; -+ regs[rd] = do_div(regs[rd], 1771875); -+ break; -+ -+ case DIF_SUBR_MUTEX_OWNED: -+ if (!dtrace_canload(tupregs[0].dttk_value, -+ sizeof(struct mutex), mstate, vstate)) -+ break; -+ -+ dtrace_bcopy((const void *)(uintptr_t)tupregs[0].dttk_value, -+ &mtx, sizeof(struct mutex)); -+ if (*flags & CPU_DTRACE_FAULT) -+ break; -+ -+ regs[rd] = mutex_owned(&mtx); -+ break; -+ -+ case DIF_SUBR_MUTEX_OWNER: -+ regs[rd] = 0; -+ if (!dtrace_canload(tupregs[0].dttk_value, -+ sizeof(struct mutex), mstate, vstate)) -+ break; -+ -+ dtrace_bcopy((const void *)(uintptr_t)tupregs[0].dttk_value, -+ &mtx, sizeof(struct mutex)); -+ if (*flags & CPU_DTRACE_FAULT) -+ break; -+ -+#ifdef CONFIG_SMP -+ regs[rd] = (uintptr_t)__mutex_owner(&mtx); -+#else -+ regs[rd] = 0; -+#endif -+ break; -+ -+ case DIF_SUBR_MUTEX_TYPE_ADAPTIVE: -+ if (!dtrace_canload(tupregs[0].dttk_value, -+ sizeof(struct mutex), mstate, vstate)) { -+ regs[rd] = 0; -+ break; -+ } -+ -+ /* -+ * On Linux, all mutexes are adaptive. -+ */ -+ regs[rd] = 1; -+ break; -+ -+ case DIF_SUBR_MUTEX_TYPE_SPIN: -+ if (!dtrace_canload(tupregs[0].dttk_value, -+ sizeof(struct mutex), mstate, vstate)) { -+ regs[rd] = 0; -+ break; -+ } -+ -+ /* -+ * On Linux, all mutexes are adaptive. -+ */ -+ regs[rd] = 0; -+ break; -+ -+ case DIF_SUBR_RW_READ_HELD: { -+ if (!dtrace_canload(tupregs[0].dttk_value, sizeof(rwlock_t), -+ mstate, vstate)) { -+ regs[rd] = 0; -+ break; -+ } -+ -+ r.rw = dtrace_loadptr(tupregs[0].dttk_value); -+ regs[rd] = !peek_write_can_lock(&r.ri) && -+ peek_read_can_lock(&r.ri); -+ break; -+ } -+ -+ case DIF_SUBR_RW_WRITE_HELD: -+ if (!dtrace_canload(tupregs[0].dttk_value, sizeof(rwlock_t), -+ mstate, vstate)) { -+ regs[rd] = 0; -+ break; -+ } -+ -+ r.rw = dtrace_loadptr(tupregs[0].dttk_value); -+ regs[rd] = !peek_write_can_lock(&r.ri); -+ break; -+ -+ case DIF_SUBR_RW_ISWRITER: -+ if (!dtrace_canload(tupregs[0].dttk_value, sizeof(rwlock_t), -+ mstate, vstate)) { -+ regs[rd] = 0; -+ break; -+ } -+ -+ r.rw = dtrace_loadptr(tupregs[0].dttk_value); -+ /* -+ * On Linux there is no way to determine whether someone is -+ * trying to acquire a write lock. -+ */ -+ regs[rd] = !peek_write_can_lock(&r.ri); -+ break; -+ -+ case DIF_SUBR_BCOPY: { -+ /* -+ * We need to be sure that the destination is in the scratch -+ * region -- no other region is allowed. -+ */ -+ uintptr_t src = tupregs[0].dttk_value; -+ uintptr_t dest = tupregs[1].dttk_value; -+ size_t size = tupregs[2].dttk_value; -+ -+ if (!dtrace_inscratch(dest, size, mstate)) { -+ *flags |= CPU_DTRACE_BADADDR; -+ *illval = regs[rd]; -+ break; -+ } -+ -+ if (!dtrace_canload(src, size, mstate, vstate)) { -+ regs[rd] = 0; -+ break; -+ } -+ -+ dtrace_bcopy((void *)src, (void *)dest, size); -+ break; -+ } -+ -+ case DIF_SUBR_ALLOCA: -+ case DIF_SUBR_COPYIN: { -+ uintptr_t dest = P2ROUNDUP(mstate->dtms_scratch_ptr, 8); -+ uint64_t size; -+ size_t scratch_size; -+ -+ size = tupregs[subr == DIF_SUBR_ALLOCA ? 0 : 1].dttk_value; -+ scratch_size = (dest - mstate->dtms_scratch_ptr) + size; -+ -+ /* -+ * This action doesn't require any credential checks since -+ * probes will not activate in user contexts to which the -+ * enabling user does not have permissions. -+ */ -+ -+ /* -+ * Rounding up the user allocation size could have overflowed -+ * a large, bogus allocation (like -1ULL) to 0. -+ */ -+ if (scratch_size < size || -+ !DTRACE_INSCRATCH(mstate, scratch_size)) { -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); -+ regs[rd] = 0; -+ break; -+ } -+ -+ if (subr == DIF_SUBR_COPYIN) { -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); -+ dtrace_copyin(tupregs[0].dttk_value, dest, size, flags); -+ DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); -+ } -+ -+ mstate->dtms_scratch_ptr += scratch_size; -+ regs[rd] = dest; -+ break; -+ } -+ -+ case DIF_SUBR_COPYINTO: { -+ uint64_t size = tupregs[1].dttk_value; -+ uintptr_t dest = tupregs[2].dttk_value; -+ -+ /* -+ * This action doesn't require any credential checks since -+ * probes will not activate in user contexts to which the -+ * enabling user does not have permissions. -+ */ -+ if (!dtrace_inscratch(dest, size, mstate)) { -+ *flags |= CPU_DTRACE_BADADDR; -+ *illval = regs[rd]; -+ break; -+ } -+ -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); -+ dtrace_copyin(tupregs[0].dttk_value, dest, size, flags); -+ DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); -+ break; -+ } -+ -+ case DIF_SUBR_COPYINSTR: { -+ uintptr_t dest = mstate->dtms_scratch_ptr; -+ uint64_t size = state->dts_options[DTRACEOPT_STRSIZE]; -+ -+ if (nargs > 1 && tupregs[1].dttk_value < size) -+ size = tupregs[1].dttk_value + 1; -+ -+ /* -+ * This action doesn't require any credential checks since -+ * probes will not activate in user contexts to which the -+ * enabling user does not have permissions. -+ */ -+ if (!DTRACE_INSCRATCH(mstate, size)) { -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); -+ regs[rd] = 0; -+ break; -+ } -+ -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); -+ dtrace_copyinstr(tupregs[0].dttk_value, dest, size, flags); -+ DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); -+ -+ ((char *)dest)[size - 1] = '\0'; -+ mstate->dtms_scratch_ptr += size; -+ regs[rd] = dest; -+ break; -+ } -+ -+#if 0 /* FIXME */ -+ case DIF_SUBR_MSGSIZE: -+ case DIF_SUBR_MSGDSIZE: { -+ uintptr_t baddr = tupregs[0].dttk_value, daddr; -+ uintptr_t wptr, rptr; -+ size_t count = 0; -+ int cont = 0; -+ -+ while (baddr != NULL && !(*flags & CPU_DTRACE_FAULT)) { -+ -+ if (!dtrace_canload(baddr, sizeof(mblk_t), mstate, -+ vstate)) { -+ regs[rd] = 0; -+ break; -+ } -+ -+ wptr = dtrace_loadptr(baddr + -+ offsetof(mblk_t, b_wptr)); -+ -+ rptr = dtrace_loadptr(baddr + -+ offsetof(mblk_t, b_rptr)); -+ -+ if (wptr < rptr) { -+ *flags |= CPU_DTRACE_BADADDR; -+ *illval = tupregs[0].dttk_value; -+ break; -+ } -+ -+ daddr = dtrace_loadptr(baddr + -+ offsetof(mblk_t, b_datap)); -+ -+ baddr = dtrace_loadptr(baddr + -+ offsetof(mblk_t, b_cont)); -+ -+ /* -+ * We want to prevent against denial-of-service here, -+ * so we're only going to search the list for -+ * dtrace_msgdsize_max mblks. -+ */ -+ if (cont++ > dtrace_msgdsize_max) { -+ *flags |= CPU_DTRACE_ILLOP; -+ break; -+ } -+ -+ if (subr == DIF_SUBR_MSGDSIZE) { -+ if (dtrace_load8(daddr + -+ offsetof(dblk_t, db_type)) != M_DATA) -+ continue; -+ } -+ -+ count += wptr - rptr; -+ } -+ -+ if (!(*flags & CPU_DTRACE_FAULT)) -+ regs[rd] = count; -+ -+ break; -+ } -+#endif -+ -+ case DIF_SUBR_PROGENYOF: { -+ pid_t pid = tupregs[0].dttk_value; -+ struct task_struct *p; -+ int rval = 0; -+ -+ for (p = current; p != NULL; p = p->real_parent) { -+ if (p->pid == pid) { -+ rval = 1; -+ break; -+ } -+ -+ if (p == p->real_parent) -+ break; -+ } -+ -+ regs[rd] = rval; -+ break; -+ } -+ -+ case DIF_SUBR_SPECULATION: -+ regs[rd] = dtrace_speculation(state); -+ break; -+ -+ case DIF_SUBR_COPYOUT: { -+ uintptr_t kaddr = tupregs[0].dttk_value; -+ uintptr_t uaddr = tupregs[1].dttk_value; -+ uint64_t size = tupregs[2].dttk_value; -+ -+ if (!dtrace_destructive_disallow && -+ dtrace_priv_proc_control(state) && -+ !dtrace_istoxic(kaddr, size) && -+ dtrace_canload(kaddr, size, mstate, vstate)) { -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); -+ dtrace_copyout(kaddr, uaddr, size, flags); -+ DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); -+ } -+ break; -+ } -+ -+ case DIF_SUBR_COPYOUTSTR: { -+ uintptr_t kaddr = tupregs[0].dttk_value; -+ uintptr_t uaddr = tupregs[1].dttk_value; -+ uint64_t size = tupregs[2].dttk_value; -+ -+ if (!dtrace_destructive_disallow && -+ dtrace_priv_proc_control(state) && -+ !dtrace_istoxic(kaddr, size) && -+ dtrace_strcanload(kaddr, size, mstate, vstate)) { -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); -+ dtrace_copyoutstr(kaddr, uaddr, size, flags); -+ DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); -+ } -+ break; -+ } -+ -+ case DIF_SUBR_STRLEN: { -+ size_t sz; -+ uintptr_t addr = (uintptr_t)tupregs[0].dttk_value; -+ -+ sz = dtrace_strlen((char *)addr, -+ state->dts_options[DTRACEOPT_STRSIZE]); -+ -+ if (!dtrace_canload(addr, sz + 1, mstate, vstate)) { -+ regs[rd] = 0; -+ break; -+ } -+ -+ regs[rd] = sz; -+ -+ break; -+ } -+ -+ case DIF_SUBR_STRCHR: -+ case DIF_SUBR_STRRCHR: { -+ /* -+ * We're going to iterate over the string looking for the -+ * specified character. We will iterate until we have reached -+ * the string length or we have found the character. If this -+ * is DIF_SUBR_STRRCHR, we will look for the last occurrence -+ * of the specified character instead of the first. -+ */ -+ uintptr_t saddr = tupregs[0].dttk_value; -+ uintptr_t addr = tupregs[0].dttk_value; -+ uintptr_t limit = addr + -+ state->dts_options[DTRACEOPT_STRSIZE]; -+ char c, target = (char)tupregs[1].dttk_value; -+ -+ for (regs[rd] = 0; addr < limit; addr++) { -+ c = dtrace_load8(addr); -+ if (c == target) { -+ regs[rd] = addr; -+ -+ if (subr == DIF_SUBR_STRCHR) -+ break; -+ } -+ -+ if (c == '\0') -+ break; -+ } -+ -+ if (!dtrace_canload(saddr, addr - saddr, mstate, vstate)) { -+ regs[rd] = 0; -+ break; -+ } -+ -+ break; -+ } -+ -+ case DIF_SUBR_STRSTR: -+ case DIF_SUBR_INDEX: -+ case DIF_SUBR_RINDEX: { -+ /* -+ * We're going to iterate over the string looking for the -+ * specified string. We will iterate until we have reached -+ * the string length or we have found the string. (Yes, this -+ * is done in the most naive way possible -- but considering -+ * that the string we're searching for is likely to be -+ * relatively short, the complexity of Rabin-Karp or similar -+ * hardly seems merited.) -+ */ -+ char *addr = (char *)(uintptr_t) -+ tupregs[0].dttk_value; -+ char *substr = (char *)(uintptr_t) -+ tupregs[1].dttk_value; -+ uint64_t size = state->dts_options[DTRACEOPT_STRSIZE]; -+ size_t len = dtrace_strlen(addr, size); -+ size_t sublen = dtrace_strlen(substr, size); -+ char *limit = addr + len, *orig = addr; -+ int notfound = subr == DIF_SUBR_STRSTR ? 0 : -1; -+ int inc = 1; -+ -+ regs[rd] = notfound; -+ -+ if (!dtrace_canload((uintptr_t)addr, len + 1, mstate, vstate)) { -+ regs[rd] = 0; -+ break; -+ } -+ -+ if (!dtrace_canload((uintptr_t)substr, sublen + 1, mstate, -+ vstate)) { -+ regs[rd] = 0; -+ break; -+ } -+ -+ /* -+ * strstr() and index()/rindex() have similar semantics if -+ * both strings are the empty string: strstr() returns a -+ * pointer to the (empty) string, and index() and rindex() -+ * both return index 0 (regardless of any position argument). -+ */ -+ if (sublen == 0 && len == 0) { -+ if (subr == DIF_SUBR_STRSTR) -+ regs[rd] = (uintptr_t)addr; -+ else -+ regs[rd] = 0; -+ break; -+ } -+ -+ if (subr != DIF_SUBR_STRSTR) { -+ if (subr == DIF_SUBR_RINDEX) { -+ limit = orig - 1; -+ addr += len; -+ inc = -1; -+ } -+ -+ /* -+ * Both index() and rindex() take an optional position -+ * argument that denotes the starting position. -+ */ -+ if (nargs == 3) { -+ int64_t pos = (int64_t)tupregs[2].dttk_value; -+ -+ /* -+ * If the position argument to index() is -+ * negative, Perl implicitly clamps it at -+ * zero. This semantic is a little surprising -+ * given the special meaning of negative -+ * positions to similar Perl functions like -+ * substr(), but it appears to reflect a -+ * notion that index() can start from a -+ * negative index and increment its way up to -+ * the string. Given this notion, Perl's -+ * rindex() is at least self-consistent in -+ * that it implicitly clamps positions greater -+ * than the string length to be the string -+ * length. Where Perl completely loses -+ * coherence, however, is when the specified -+ * substring is the empty string (""). In -+ * this case, even if the position is -+ * negative, rindex() returns 0 -- and even if -+ * the position is greater than the length, -+ * index() returns the string length. These -+ * semantics violate the notion that index() -+ * should never return a value less than the -+ * specified position and that rindex() should -+ * never return a value greater than the -+ * specified position. (One assumes that -+ * these semantics are artifacts of Perl's -+ * implementation and not the results of -+ * deliberate design -- it beggars belief that -+ * even Larry Wall could desire such oddness.) -+ * While in the abstract one would wish for -+ * consistent position semantics across -+ * substr(), index() and rindex() -- or at the -+ * very least self-consistent position -+ * semantics for index() and rindex() -- we -+ * instead opt to keep with the extant Perl -+ * semantics, in all their broken glory. (Do -+ * we have more desire to maintain Perl's -+ * semantics than Perl does? Probably.) -+ */ -+ if (subr == DIF_SUBR_RINDEX) { -+ if (pos < 0) { -+ if (sublen == 0) -+ regs[rd] = 0; -+ break; -+ } -+ -+ if (pos > len) -+ pos = len; -+ } else { -+ if (pos < 0) -+ pos = 0; -+ -+ if (pos >= len) { -+ if (sublen == 0) -+ regs[rd] = len; -+ break; -+ } -+ } -+ -+ addr = orig + pos; -+ } -+ } -+ -+ for (regs[rd] = notfound; addr != limit; addr += inc) { -+ if (dtrace_strncmp(addr, substr, sublen) == 0) { -+ if (subr != DIF_SUBR_STRSTR) { -+ /* -+ * As D index() and rindex() are -+ * modeled on Perl (and not on awk), -+ * we return a zero-based (and not a -+ * one-based) index. (For you Perl -+ * weenies: no, we're not going to add -+ * $[ -- and shouldn't you be at a con -+ * or something?) -+ */ -+ regs[rd] = (uintptr_t)(addr - orig); -+ break; -+ } -+ -+ ASSERT(subr == DIF_SUBR_STRSTR); -+ regs[rd] = (uintptr_t)addr; -+ break; -+ } -+ } -+ -+ break; -+ } -+ -+ case DIF_SUBR_STRTOK: { -+ uintptr_t addr = tupregs[0].dttk_value; -+ uintptr_t tokaddr = tupregs[1].dttk_value; -+ uint64_t size = state->dts_options[DTRACEOPT_STRSIZE]; -+ uintptr_t limit, toklimit = tokaddr + size; -+ uint8_t c = 0, tokmap[32]; /* 256 / 8 */ -+ char *dest = (char *)mstate->dtms_scratch_ptr; -+ int i; -+ -+ /* -+ * Check both the token buffer and (later) the input buffer, -+ * since both could be non-scratch addresses. -+ */ -+ if (!dtrace_strcanload(tokaddr, size, mstate, vstate)) { -+ regs[rd] = 0; -+ break; -+ } -+ -+ if (!DTRACE_INSCRATCH(mstate, size)) { -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); -+ regs[rd] = 0; -+ break; -+ } -+ -+ if (addr == (uintptr_t)NULL) { -+ /* -+ * If the address specified is NULL, we use our saved -+ * strtok pointer from the mstate. Note that this -+ * means that the saved strtok pointer is _only_ -+ * valid within multiple enablings of the same probe -- -+ * it behaves like an implicit clause-local variable. -+ */ -+ addr = mstate->dtms_strtok; -+ } else { -+ /* -+ * If the user-specified address is non-NULL we must -+ * access check it. This is the only time we have -+ * a chance to do so, since this address may reside -+ * in the string table of this clause-- future calls -+ * (when we fetch addr from mstate->dtms_strtok) -+ * would fail this access check. -+ */ -+ if (!dtrace_strcanload(addr, size, mstate, vstate)) { -+ regs[rd] = 0; -+ break; -+ } -+ } -+ -+ /* -+ * First, zero the token map, and then process the token -+ * string -- setting a bit in the map for every character -+ * found in the token string. -+ */ -+ for (i = 0; i < sizeof(tokmap); i++) -+ tokmap[i] = 0; -+ -+ for (; tokaddr < toklimit; tokaddr++) { -+ c = dtrace_load8(tokaddr); -+ if (c == '\0') -+ break; -+ -+ ASSERT((c >> 3) < sizeof(tokmap)); -+ tokmap[c >> 3] |= (1 << (c & 0x7)); -+ } -+ -+ for (limit = addr + size; addr < limit; addr++) { -+ /* -+ * We're looking for a character that is _not_ contained -+ * in the token string. -+ */ -+ c = dtrace_load8(addr); -+ if (c == '\0') -+ break; -+ -+ if (!(tokmap[c >> 3] & (1 << (c & 0x7)))) -+ break; -+ } -+ -+ if (c == '\0') { -+ /* -+ * We reached the end of the string without finding -+ * any character that was not in the token string. -+ * We return NULL in this case, and we set the saved -+ * address to NULL as well. -+ */ -+ regs[rd] = 0; -+ mstate->dtms_strtok = (uintptr_t)NULL; -+ break; -+ } -+ -+ /* -+ * From here on, we're copying into the destination string. -+ */ -+ for (i = 0; addr < limit && i < size - 1; addr++) { -+ c = dtrace_load8(addr); -+ if (c == '\0') -+ break; -+ -+ if (tokmap[c >> 3] & (1 << (c & 0x7))) -+ break; -+ -+ ASSERT(i < size); -+ dest[i++] = c; -+ } -+ -+ ASSERT(i < size); -+ dest[i] = '\0'; -+ regs[rd] = (uintptr_t)dest; -+ mstate->dtms_scratch_ptr += size; -+ mstate->dtms_strtok = addr; -+ break; -+ } -+ -+ case DIF_SUBR_SUBSTR: { -+ uintptr_t s = tupregs[0].dttk_value; -+ uint64_t size = state->dts_options[DTRACEOPT_STRSIZE]; -+ char *d = (char *)mstate->dtms_scratch_ptr; -+ int64_t index = (int64_t)tupregs[1].dttk_value; -+ int64_t remaining = (int64_t)tupregs[2].dttk_value; -+ size_t len = dtrace_strlen((char *)s, size); -+ int64_t i = 0; -+ -+ if (!dtrace_canload(s, len + 1, mstate, vstate)) { -+ regs[rd] = 0; -+ break; -+ } -+ -+ if (!DTRACE_INSCRATCH(mstate, size)) { -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); -+ regs[rd] = 0; -+ break; -+ } -+ -+ if (nargs <= 2) -+ remaining = (int64_t)size; -+ -+ if (index < 0) { -+ index += len; -+ -+ if (index < 0 && index + remaining > 0) { -+ remaining += index; -+ index = 0; -+ } -+ } -+ -+ if (index >= len || index < 0) -+ remaining = 0; -+ else if (remaining < 0) -+ remaining += len - index; -+ else if (index + remaining > size) -+ remaining = size - index; -+ -+ for (i = 0; i < remaining; i++) { -+ d[i] = dtrace_load8(s + index + i); -+ if (d[i] == '\0') -+ break; -+ } -+ -+ d[i] = '\0'; -+ -+ mstate->dtms_scratch_ptr += size; -+ regs[rd] = (uintptr_t)d; -+ break; -+ } -+ -+ case DIF_SUBR_GETMAJOR: -+ regs[rd] = MAJOR(tupregs[0].dttk_value); -+ break; -+ -+ case DIF_SUBR_GETMINOR: -+ regs[rd] = MINOR(tupregs[0].dttk_value); -+ break; -+ -+#if 0 /* FIXME */ -+ case DIF_SUBR_DDI_PATHNAME: { -+ /* -+ * This one is a galactic mess. We are going to roughly -+ * emulate ddi_pathname(), but it's made more complicated -+ * by the fact that we (a) want to include the minor name and -+ * (b) must proceed iteratively instead of recursively. -+ */ -+ uintptr_t dest = mstate->dtms_scratch_ptr; -+ uint64_t size = state->dts_options[DTRACEOPT_STRSIZE]; -+ char *start = (char *)dest, *end = start + size - 1; -+ uintptr_t daddr = tupregs[0].dttk_value; -+ int64_t minor = (int64_t)tupregs[1].dttk_value; -+ char *s; -+ int i, len, depth = 0; -+ -+ /* -+ * Due to all the pointer jumping we do and context we must -+ * rely upon, we just mandate that the user must have kernel -+ * read privileges to use this routine. -+ */ -+ if ((mstate->dtms_access & DTRACE_ACCESS_KERNEL) == 0) { -+ *flags |= CPU_DTRACE_KPRIV; -+ *illval = daddr; -+ regs[rd] = 0; -+ } -+ -+ if (!DTRACE_INSCRATCH(mstate, size)) { -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); -+ regs[rd] = 0; -+ break; -+ } -+ -+ *end = '\0'; -+ -+ /* -+ * We want to have a name for the minor. In order to do this, -+ * we need to walk the minor list from the devinfo. We want -+ * to be sure that we don't infinitely walk a circular list, -+ * so we check for circularity by sending a scout pointer -+ * ahead two elements for every element that we iterate over; -+ * if the list is circular, these will ultimately point to the -+ * same element. You may recognize this little trick as the -+ * answer to a stupid interview question -- one that always -+ * seems to be asked by those who had to have it laboriously -+ * explained to them, and who can't even concisely describe -+ * the conditions under which one would be forced to resort to -+ * this technique. Needless to say, those conditions are -+ * found here -- and probably only here. Is this the only use -+ * of this infamous trick in shipping, production code? If it -+ * isn't, it probably should be... -+ */ -+ if (minor != -1) { -+ uintptr_t maddr = dtrace_loadptr(daddr + -+ offsetof(struct dev_info, devi_minor)); -+ -+ uintptr_t next = offsetof(struct ddi_minor_data, next); -+ uintptr_t name = offsetof(struct ddi_minor_data, -+ d_minor) + offsetof(struct ddi_minor, name); -+ uintptr_t dev = offsetof(struct ddi_minor_data, -+ d_minor) + offsetof(struct ddi_minor, dev); -+ uintptr_t scout; -+ -+ if (maddr != NULL) -+ scout = dtrace_loadptr(maddr + next); -+ -+ while (maddr != NULL && !(*flags & CPU_DTRACE_FAULT)) { -+ uint64_t m; -+#ifdef _LP64 -+ m = dtrace_load64(maddr + dev) & MAXMIN64; -+#else -+ m = dtrace_load32(maddr + dev) & MAXMIN; -+#endif -+ if (m != minor) { -+ maddr = dtrace_loadptr(maddr + next); -+ -+ if (scout == NULL) -+ continue; -+ -+ scout = dtrace_loadptr(scout + next); -+ -+ if (scout == NULL) -+ continue; -+ -+ scout = dtrace_loadptr(scout + next); -+ -+ if (scout == NULL) -+ continue; -+ -+ if (scout == maddr) { -+ *flags |= CPU_DTRACE_ILLOP; -+ break; -+ } -+ -+ continue; -+ } -+ -+ /* -+ * We have the minor data. Now we need to -+ * copy the minor's name into the end of the -+ * pathname. -+ */ -+ s = (char *)dtrace_loadptr(maddr + name); -+ len = dtrace_strlen(s, size); -+ -+ if (*flags & CPU_DTRACE_FAULT) -+ break; -+ -+ if (len != 0) { -+ end -= len + 1; -+ if (end < start) -+ break; -+ -+ *end = ':'; -+ } -+ -+ for (i = 1; i <= len; i++) -+ end[i] = dtrace_load8((uintptr_t)s++); -+ break; -+ } -+ } -+ -+ while (daddr != NULL && !(*flags & CPU_DTRACE_FAULT)) { -+ ddi_node_state_t devi_state; -+ -+ devi_state = dtrace_load32(daddr + -+ offsetof(struct dev_info, devi_node_state)); -+ -+ if (*flags & CPU_DTRACE_FAULT) -+ break; -+ -+ if (devi_state >= DS_INITIALIZED) { -+ s = (char *)dtrace_loadptr(daddr + -+ offsetof(struct dev_info, devi_addr)); -+ len = dtrace_strlen(s, size); -+ -+ if (*flags & CPU_DTRACE_FAULT) -+ break; -+ -+ if (len != 0) { -+ end -= len + 1; -+ if (end < start) -+ break; -+ -+ *end = '@'; -+ } -+ -+ for (i = 1; i <= len; i++) -+ end[i] = dtrace_load8((uintptr_t)s++); -+ } -+ -+ /* -+ * Now for the node name... -+ */ -+ s = (char *)dtrace_loadptr(daddr + -+ offsetof(struct dev_info, devi_node_name)); -+ -+ daddr = dtrace_loadptr(daddr + -+ offsetof(struct dev_info, devi_parent)); -+ -+ /* -+ * If our parent is NULL (that is, if we're the root -+ * node), we're going to use the special path -+ * "devices". -+ */ -+ if (daddr == NULL) -+ s = "devices"; -+ -+ len = dtrace_strlen(s, size); -+ if (*flags & CPU_DTRACE_FAULT) -+ break; -+ -+ end -= len + 1; -+ if (end < start) -+ break; -+ -+ for (i = 1; i <= len; i++) -+ end[i] = dtrace_load8((uintptr_t)s++); -+ *end = '/'; -+ -+ if (depth++ > dtrace_devdepth_max) { -+ *flags |= CPU_DTRACE_ILLOP; -+ break; -+ } -+ } -+ -+ if (end < start) -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); -+ -+ if (daddr == NULL) { -+ regs[rd] = (uintptr_t)end; -+ mstate->dtms_scratch_ptr += size; -+ } -+ -+ break; -+ } -+#endif -+ -+ case DIF_SUBR_STRJOIN: { -+ char *d = (char *)mstate->dtms_scratch_ptr; -+ uint64_t size = state->dts_options[DTRACEOPT_STRSIZE]; -+ uintptr_t s1 = tupregs[0].dttk_value; -+ uintptr_t s2 = tupregs[1].dttk_value; -+ int i = 0; -+ -+ if (!dtrace_strcanload(s1, size, mstate, vstate) || -+ !dtrace_strcanload(s2, size, mstate, vstate)) { -+ regs[rd] = 0; -+ break; -+ } -+ -+ if (!DTRACE_INSCRATCH(mstate, size)) { -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); -+ regs[rd] = 0; -+ break; -+ } -+ -+ for (;;) { -+ if (i >= size) { -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); -+ regs[rd] = 0; -+ break; -+ } -+ -+ d[i] = dtrace_load8(s1++); -+ if ((d[i++]) == '\0') { -+ i--; -+ break; -+ } -+ } -+ -+ for (;;) { -+ if (i >= size) { -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); -+ regs[rd] = 0; -+ break; -+ } -+ -+ d[i] = dtrace_load8(s2++); -+ if ((d[i++]) == '\0') -+ break; -+ } -+ -+ if (i < size) { -+ mstate->dtms_scratch_ptr += i; -+ regs[rd] = (uintptr_t)d; -+ } -+ -+ break; -+ } -+ -+ case DIF_SUBR_LLTOSTR: { -+ int64_t i = (int64_t)tupregs[0].dttk_value; -+ int64_t val = i < 0 ? i * -1 : i; -+ uint64_t size = 22; /* room for 2^64 in dec */ -+ char *end = (char *)mstate->dtms_scratch_ptr + size -+ - 1; -+ -+ if (!DTRACE_INSCRATCH(mstate, size)) { -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); -+ regs[rd] = 0; -+ break; -+ } -+ -+ /* -+ * GCC on Linux introduces calls to functions that are not -+ * linked into the kernel image, so we need to use the do_div() -+ * function instead. It modifies the first argument in place -+ * (replaces it with the quotient), and returns the remainder. -+ * -+ * Was: -+ * for (*end-- = '\0'; val; val /= 10) -+ * *end-- = '0' + (val % 10); -+ */ -+ for (*end-- = '\0'; val; ) -+ *end-- = '0' + do_div(val, 10); -+ -+ if (i == 0) -+ *end-- = '0'; -+ -+ if (i < 0) -+ *end-- = '-'; -+ -+ regs[rd] = (uintptr_t)end + 1; -+ mstate->dtms_scratch_ptr += size; -+ break; -+ } -+ -+ case DIF_SUBR_HTONS: -+ case DIF_SUBR_NTOHS: -+#ifdef __BIG_ENDIAN -+ regs[rd] = (uint16_t)tupregs[0].dttk_value; -+#else -+ regs[rd] = DT_BSWAP_16((uint16_t)tupregs[0].dttk_value); -+#endif -+ break; -+ -+ -+ case DIF_SUBR_HTONL: -+ case DIF_SUBR_NTOHL: -+#ifdef __BIG_ENDIAN -+ regs[rd] = (uint32_t)tupregs[0].dttk_value; -+#else -+ regs[rd] = DT_BSWAP_32((uint32_t)tupregs[0].dttk_value); -+#endif -+ break; -+ -+ -+ case DIF_SUBR_HTONLL: -+ case DIF_SUBR_NTOHLL: -+#ifdef __BIG_ENDIAN -+ regs[rd] = (uint64_t)tupregs[0].dttk_value; -+#else -+ regs[rd] = DT_BSWAP_64((uint64_t)tupregs[0].dttk_value); -+#endif -+ break; -+ -+ -+ case DIF_SUBR_DIRNAME: -+ case DIF_SUBR_BASENAME: { -+ char *dest = (char *)mstate->dtms_scratch_ptr; -+ uint64_t size = state->dts_options[DTRACEOPT_STRSIZE]; -+ uintptr_t src = tupregs[0].dttk_value; -+ int i, j, len = dtrace_strlen((char *)src, size); -+ int lastbase = -1, firstbase = -1, lastdir = -1; -+ int start, end; -+ -+ if (!dtrace_canload(src, len + 1, mstate, vstate)) { -+ regs[rd] = 0; -+ break; -+ } -+ -+ if (!DTRACE_INSCRATCH(mstate, size)) { -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); -+ regs[rd] = 0; -+ break; -+ } -+ -+ /* -+ * The basename and dirname for a zero-length string is -+ * defined to be "." -+ */ -+ if (len == 0) { -+ len = 1; -+ src = (uintptr_t)"."; -+ } -+ -+ /* -+ * Start from the back of the string, moving back toward the -+ * front until we see a character that isn't a slash. That -+ * character is the last character in the basename. -+ */ -+ for (i = len - 1; i >= 0; i--) { -+ if (dtrace_load8(src + i) != '/') -+ break; -+ } -+ -+ if (i >= 0) -+ lastbase = i; -+ -+ /* -+ * Starting from the last character in the basename, move -+ * towards the front until we find a slash. The character -+ * that we processed immediately before that is the first -+ * character in the basename. -+ */ -+ for (; i >= 0; i--) { -+ if (dtrace_load8(src + i) == '/') -+ break; -+ } -+ -+ if (i >= 0) -+ firstbase = i + 1; -+ -+ /* -+ * Now keep going until we find a non-slash character. That -+ * character is the last character in the dirname. -+ */ -+ for (; i >= 0; i--) { -+ if (dtrace_load8(src + i) != '/') -+ break; -+ } -+ -+ if (i >= 0) -+ lastdir = i; -+ -+ ASSERT(!(lastbase == -1 && firstbase != -1)); -+ ASSERT(!(firstbase == -1 && lastdir != -1)); -+ -+ if (lastbase == -1) { -+ /* -+ * We didn't find a non-slash character. We know that -+ * the length is non-zero, so the whole string must be -+ * slashes. In either the dirname or the basename -+ * case, we return '/'. -+ */ -+ ASSERT(firstbase == -1); -+ firstbase = lastbase = lastdir = 0; -+ } -+ -+ if (firstbase == -1) { -+ /* -+ * The entire string consists only of a basename -+ * component. If we're looking for dirname, we need -+ * to change our string to be just "."; if we're -+ * looking for a basename, we'll just set the first -+ * character of the basename to be 0. -+ */ -+ if (subr == DIF_SUBR_DIRNAME) { -+ ASSERT(lastdir == -1); -+ src = (uintptr_t)"."; -+ lastdir = 0; -+ } else { -+ firstbase = 0; -+ } -+ } -+ -+ if (subr == DIF_SUBR_DIRNAME) { -+ if (lastdir == -1) { -+ /* -+ * We know that we have a slash in the name -- -+ * or lastdir would be set to 0, above. And -+ * because lastdir is -1, we know that this -+ * slash must be the first character. (That -+ * is, the full string must be of the form -+ * "/basename".) In this case, the last -+ * character of the directory name is 0. -+ */ -+ lastdir = 0; -+ } -+ -+ start = 0; -+ end = lastdir; -+ } else { -+ ASSERT(subr == DIF_SUBR_BASENAME); -+ ASSERT(firstbase != -1 && lastbase != -1); -+ start = firstbase; -+ end = lastbase; -+ } -+ -+ for (i = start, j = 0; i <= end && j < size - 1; i++, j++) -+ dest[j] = dtrace_load8(src + i); -+ -+ dest[j] = '\0'; -+ regs[rd] = (uintptr_t)dest; -+ mstate->dtms_scratch_ptr += size; -+ break; -+ } -+ -+ case DIF_SUBR_CLEANPATH: { -+ char *dest = (char *)mstate->dtms_scratch_ptr, c; -+ uint64_t size = state->dts_options[DTRACEOPT_STRSIZE]; -+ uintptr_t src = tupregs[0].dttk_value; -+ int i = 0, j = 0; -+ -+ if (!dtrace_strcanload(src, size, mstate, vstate)) { -+ regs[rd] = 0; -+ break; -+ } -+ -+ if (!DTRACE_INSCRATCH(mstate, size)) { -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); -+ regs[rd] = 0; -+ break; -+ } -+ -+ /* -+ * Move forward, loading each character. -+ */ -+ do { -+ c = dtrace_load8(src + i++); -+next: -+ if (j + 5 >= size) /* 5 = strlen("/..c\0") */ -+ break; -+ -+ if (c != '/') { -+ dest[j++] = c; -+ continue; -+ } -+ -+ c = dtrace_load8(src + i++); -+ -+ if (c == '/') { -+ /* -+ * We have two slashes -- we can just advance -+ * to the next character. -+ */ -+ goto next; -+ } -+ -+ if (c != '.') { -+ /* -+ * This is not "." and it's not ".." -- we can -+ * just store the "/" and this character and -+ * drive on. -+ */ -+ dest[j++] = '/'; -+ dest[j++] = c; -+ continue; -+ } -+ -+ c = dtrace_load8(src + i++); -+ -+ if (c == '/') { -+ /* -+ * This is a "/./" component. We're not going -+ * to store anything in the destination buffer; -+ * we're just going to go to the next component. -+ */ -+ goto next; -+ } -+ -+ if (c != '.') { -+ /* -+ * This is not ".." -- we can just store the -+ * "/." and this character and continue -+ * processing. -+ */ -+ dest[j++] = '/'; -+ dest[j++] = '.'; -+ dest[j++] = c; -+ continue; -+ } -+ -+ c = dtrace_load8(src + i++); -+ -+ if (c != '/' && c != '\0') { -+ /* -+ * This is not ".." -- it's "..[mumble]". -+ * We'll store the "/.." and this character -+ * and continue processing. -+ */ -+ dest[j++] = '/'; -+ dest[j++] = '.'; -+ dest[j++] = '.'; -+ dest[j++] = c; -+ continue; -+ } -+ -+ /* -+ * This is "/../" or "/..\0". We need to back up -+ * our destination pointer until we find a "/". -+ */ -+ i--; -+ while (j != 0 && dest[--j] != '/') -+ continue; -+ -+ if (c == '\0') -+ dest[++j] = '/'; -+ } while (c != '\0'); -+ -+ dest[j] = '\0'; -+ regs[rd] = (uintptr_t)dest; -+ mstate->dtms_scratch_ptr += size; -+ break; -+ } -+ -+ case DIF_SUBR_LINK_NTOP: { -+ struct dtrace_hwtype_alen { -+ int dhwa_hwtype; -+ size_t dhwa_hwalen; -+ } hwinfo[] = { -+ { ARPHRD_ETHER, ETH_ALEN }, -+ { ARPHRD_INFINIBAND, INFINIBAND_ALEN }, -+ { -1, 0 } -+ }; -+/* -+ * Captures the maximum hardware address length among all the supported -+ * hardware types. Please update this macro when adding a new hardware type. -+ */ -+#define DTRACE_MAX_HWTYPE_ALEN (ETH_ALEN > INFINIBAND_ALEN ? \ -+ ETH_ALEN : INFINIBAND_ALEN) -+ uintptr_t src = tupregs[1].dttk_value; -+ int hwtype = tupregs[0].dttk_value; -+ uint8_t hwaddr[DTRACE_MAX_HWTYPE_ALEN]; -+ char *base; -+ size_t size, len; -+ int i; -+ -+ for (i = 0; hwinfo[i].dhwa_hwtype != -1; i++) { -+ if (hwtype == hwinfo[i].dhwa_hwtype) -+ break; -+ } -+ if (hwinfo[i].dhwa_hwtype == -1) { -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); -+ regs[rd] = 0; -+ break; -+ } -+ len = hwinfo[i].dhwa_hwalen; -+ -+ /* -+ * Safely load the hardware address. -+ */ -+ if (!dtrace_canload(src, len, mstate, vstate)) { -+ regs[rd] = 0; -+ break; -+ } -+ dtrace_bcopy((void *)src, hwaddr, len); -+ -+ /* -+ * Check if a hardware address string will fit in scratch. -+ * For every byte we need 3 characters (including ':'). -+ */ -+ size = len * 3; -+ if (!DTRACE_INSCRATCH(mstate, size)) { -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); -+ regs[rd] = 0; -+ break; -+ } -+ base = (char *)mstate->dtms_scratch_ptr; -+ -+ /* -+ * Build the Hardware address string by working through the -+ * address from the beginning. Given a hardware address -+ * {0xa0, 0xaa, 0xff, 0xc, 0, 1, 2} of length 6, it will build -+ * a0:aa:ff:0c:00:01:02. -+ */ -+ for (i = 0; i < len; i++) { -+ if (hwaddr[i] < 16) { -+ *base++ = '0'; -+ *base++ = hexdigits[hwaddr[i]]; -+ } else { -+ *base++ = hexdigits[hwaddr[i] / 16]; -+ *base++ = hexdigits[hwaddr[i] % 16]; -+ } -+ -+ if (i < len - 1) -+ *base++ = ':'; -+ } -+ *base++ = '\0'; -+ regs[rd] = mstate->dtms_scratch_ptr; -+ mstate->dtms_scratch_ptr += size; -+#undef DTRACE_MAX_HWTYPE_ALEN -+ break; -+ } -+ -+ case DIF_SUBR_INET_NTOA: -+ case DIF_SUBR_INET_NTOA6: -+ case DIF_SUBR_INET_NTOP: { -+ uintptr_t src; -+ size_t size; -+ int af, argi, i; -+ char *base, *end; -+ -+ if (subr == DIF_SUBR_INET_NTOP) { -+ af = (int)tupregs[0].dttk_value; -+ argi = 1; -+ } else { -+ af = subr == DIF_SUBR_INET_NTOA ? AF_INET : AF_INET6; -+ argi = 0; -+ } -+ -+ src = tupregs[argi].dttk_value; -+ if (af == AF_INET) { -+ ipaddr_t ip4; -+ ipaddr_t_p ptr4; -+ uint8_t *ptr8, val; -+ -+ /* -+ * Safely load the IPv4 address. -+ */ -+ if (!dtrace_canload(src, 4, mstate, vstate)) { -+ regs[rd] = 0; -+ break; -+ } -+ ip4 = dtrace_load32(src); -+ -+ /* -+ * Check an IPv4 string will fit in scratch. -+ */ -+ size = INET_ADDRSTRLEN; -+ if (!DTRACE_INSCRATCH(mstate, size)) { -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); -+ regs[rd] = 0; -+ break; -+ } -+ base = (char *)mstate->dtms_scratch_ptr; -+ end = (char *)mstate->dtms_scratch_ptr + size - 1; -+ -+ /* -+ * Stringify as a dotted decimal quad. -+ */ -+ *end-- = '\0'; -+ ptr4 = &ip4; -+ ptr8 = (uint8_t *)ptr4; -+ for (i = 3; i >= 0; i--) { -+ val = ptr8[i]; -+ -+ if (val == 0) { -+ *end-- = '0'; -+ } else { -+ for (; val; val /= 10) -+ *end-- = '0' + (val % 10); -+ } -+ -+ if (i > 0) -+ *end-- = '.'; -+ } -+ ASSERT(end + 1 >= base); -+#if IS_ENABLED(CONFIG_IPV6) -+ } else if (af == AF_INET6) { -+ in6_addr_t ip6; -+ int firstzero, tryzero, numzero, v6end; -+ uint16_t val; -+ -+ /* -+ * Stringify using RFC 1884 convention 2 - 16 bit -+ * hexadecimal values with a zero-run compression. -+ * Lower case hexadecimal digits are used. -+ * eg, fe80::214:4fff:fe0b:76c8. -+ * The IPv4 embedded form is returned for inet_ntop, -+ * just the IPv4 string is returned for inet_ntoa6. -+ */ -+ -+ /* -+ * Safely load the IPv6 address. -+ */ -+ if (!dtrace_canload(src, sizeof(in6_addr_t), mstate, -+ vstate)) { -+ regs[rd] = 0; -+ break; -+ } -+ dtrace_bcopy((void *)src, (void *)(uintptr_t)&ip6, -+ sizeof(in6_addr_t)); -+ -+ /* -+ * Check an IPv6 string will fit in scratch. -+ */ -+ size = INET6_ADDRSTRLEN; -+ if (!DTRACE_INSCRATCH(mstate, size)) { -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); -+ regs[rd] = 0; -+ break; -+ } -+ base = (char *)mstate->dtms_scratch_ptr; -+ end = (char *)mstate->dtms_scratch_ptr + size - 1; -+ *end-- = '\0'; -+ -+ /* -+ * Find the longest run of 16 bit zero values -+ * for the single allowed zero compression - "::". -+ */ -+ firstzero = -1; -+ tryzero = -1; -+ numzero = 1; -+ for (i = 0; i < sizeof(in6_addr_t); i++) { -+ if (ip6.s6_addr[i] == 0 && -+ tryzero == -1 && i % 2 == 0) { -+ tryzero = i; -+ continue; -+ } -+ -+ if (tryzero != -1 && -+ (ip6.s6_addr[i] != 0 || -+ i == sizeof(in6_addr_t) - 1)) { -+ -+ if (i - tryzero <= numzero) { -+ tryzero = -1; -+ continue; -+ } -+ -+ firstzero = tryzero; -+ numzero = i - i % 2 - tryzero; -+ tryzero = -1; -+ -+ if (ip6.s6_addr[i] == 0 && -+ i == sizeof(in6_addr_t) - 1) -+ numzero += 2; -+ } -+ } -+ ASSERT(firstzero + numzero <= sizeof(in6_addr_t)); -+ -+ /* -+ * Check for an IPv4 embedded address. -+ */ -+ v6end = sizeof(in6_addr_t) - 2; -+ if (ipv6_addr_type(&ip6) & -+ (IPV6_ADDR_COMPATv4 | IPV6_ADDR_MAPPED)) { -+ for (i = sizeof(in6_addr_t) - 1; -+ i >= DTRACE_V4MAPPED_OFFSET; i--) { -+ ASSERT(end >= base); -+ -+ val = ip6.s6_addr[i]; -+ -+ if (val == 0) { -+ *end-- = '0'; -+ } else { -+ for (; val; val /= 10) -+ *end-- = '0' + val % 10; -+ } -+ -+ if (i > DTRACE_V4MAPPED_OFFSET) -+ *end-- = '.'; -+ } -+ -+ if (subr == DIF_SUBR_INET_NTOA6) -+ goto inetout; -+ -+ /* -+ * Set v6end to skip the IPv4 address that -+ * we have already stringified. -+ */ -+ v6end = 10; -+ } -+ -+ /* -+ * Build the IPv6 string by working through the -+ * address in reverse. -+ */ -+ for (i = v6end; i >= 0; i -= 2) { -+ ASSERT(end >= base); -+ -+ if (i == firstzero + numzero - 2) { -+ *end-- = ':'; -+ *end-- = ':'; -+ i -= numzero - 2; -+ continue; -+ } -+ -+ if (i < 14 && i != firstzero - 2) -+ *end-- = ':'; -+ -+ val = (ip6.s6_addr[i] << 8) + -+ ip6.s6_addr[i + 1]; -+ -+ if (val == 0) { -+ *end-- = '0'; -+ } else { -+ for (; val; val /= 16) -+ *end-- = hexdigits[val % 16]; -+ } -+ } -+ ASSERT(end + 1 >= base); -+#endif -+ } else { -+ /* -+ * The user didn't use AH_INET or AH_INET6. -+ */ -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); -+ regs[rd] = 0; -+ break; -+ } -+ -+#if IS_ENABLED(CONFIG_IPV6) -+inetout: -+#endif -+ regs[rd] = (uintptr_t)end + 1; -+ mstate->dtms_scratch_ptr += size; -+ break; -+ } -+ -+ case DIF_SUBR_D_PATH: { -+ struct path *path = (struct path *)tupregs[0].dttk_value; -+ char *dest = (char *)mstate->dtms_scratch_ptr; -+ char *ptr; -+ uint64_t size = state->dts_options[DTRACEOPT_STRSIZE]; -+ unsigned int fd; -+ struct files_struct -+ *files = current->files; -+ struct fdtable *fdt; -+ -+ if (!dtrace_canload((uintptr_t)path, sizeof(struct path), -+ mstate, vstate)) { -+ regs[rd] = 0; -+ break; -+ } -+ -+ if (!DTRACE_INSCRATCH(mstate, size)) { -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); -+ regs[rd] = 0; -+ break; -+ } -+ -+ if (spin_is_locked(&files->file_lock) || -+ !spin_trylock(&files->file_lock)) { -+ regs[rd] = 0; -+ break; -+ } -+ -+ fdt = files->fdt; -+ -+ /* -+ * We (currently) limit the d_path() subroutine to paths that -+ * relate to open files in the current task. -+ */ -+ for (fd = 0; fd < fdt->max_fds; fd++) { -+ if (fdt->fd[fd] && &fdt->fd[fd]->f_path == path) -+ break; -+ } -+ -+ spin_unlock(&files->file_lock); -+ -+ if (fd >= fdt->max_fds) { -+ *flags |= CPU_DTRACE_BADADDR; -+ *illval = (uintptr_t)path; -+ regs[rd] = 0; -+ break; -+ } -+ -+ ptr = d_path(path, dest, size); -+ if (ptr < 0) { -+ regs[rd] = 0; -+ break; -+ } -+ -+ regs[rd] = (uintptr_t)ptr; -+ mstate->dtms_scratch_ptr += size; -+ break; -+ } -+ -+ } -+} -+ -+/* -+ * Emulate the execution of DTrace IR instructions specified by the given DIF -+ * object. This function is deliberately void fo assertions as all of the -+ * necessary checks are handled by a call to dtrace_difo_validate(). -+ */ -+uint64_t dtrace_dif_emulate(struct dtrace_difo *difo, -+ struct dtrace_mstate *mstate, -+ struct dtrace_vstate *vstate, -+ struct dtrace_state *state) -+{ -+ const dif_instr_t *text = difo->dtdo_buf; -+ const uint_t textlen = difo->dtdo_len; -+ const char *strtab = difo->dtdo_strtab; -+ const uint64_t *inttab = difo->dtdo_inttab; -+ -+ uint64_t rval = 0; -+ struct dtrace_statvar *svar; -+ struct dtrace_dstate *dstate = &vstate->dtvs_dynvars; -+ struct dtrace_difv *v; -+ volatile uint16_t *flags = &this_cpu_core->cpuc_dtrace_flags; -+ volatile uintptr_t *illval = &this_cpu_core->cpuc_dtrace_illval; -+ -+ struct dtrace_key tupregs[DIF_DTR_NREGS + 2]; -+ /* +2 for thread and id */ -+ uint64_t regs[DIF_DIR_NREGS]; -+ uint64_t *tmp; -+ -+ uint8_t cc_n = 0, cc_z = 0, cc_v = 0, cc_c = 0; -+ int64_t cc_r; -+ uint_t pc = 0, id, opc = 0; -+ uint8_t ttop = 0; -+ dif_instr_t instr; -+ uint_t r1, r2, rd; -+ -+ dt_dbg_dif(" DIF %p emulation (text %p, %d instructions)...\n", -+ difo, text, textlen); -+ -+ /* -+ * We stash the current DIF object into the machine state: we need it -+ * for subsequent access checking. -+ */ -+ mstate->dtms_difo = difo; -+ -+ regs[DIF_REG_R0] = 0; /* %r0 is fixed at zero */ -+ -+ while (pc < textlen && !(*flags & CPU_DTRACE_FAULT)) { -+ opc = pc; -+ -+ instr = text[pc++]; -+ r1 = DIF_INSTR_R1(instr); -+ r2 = DIF_INSTR_R2(instr); -+ rd = DIF_INSTR_RD(instr); -+ -+ dt_dbg_dif(" Executing opcode %02x (%02x, %02x, %02x)\n", -+ DIF_INSTR_OP(instr), r1, r2, rd); -+ -+ switch (DIF_INSTR_OP(instr)) { -+ case DIF_OP_OR: -+ regs[rd] = regs[r1] | regs[r2]; -+ break; -+ case DIF_OP_XOR: -+ regs[rd] = regs[r1] ^ regs[r2]; -+ break; -+ case DIF_OP_AND: -+ regs[rd] = regs[r1] & regs[r2]; -+ break; -+ case DIF_OP_SLL: -+ regs[rd] = regs[r1] << regs[r2]; -+ break; -+ case DIF_OP_SRL: -+ regs[rd] = regs[r1] >> regs[r2]; -+ break; -+ case DIF_OP_SUB: -+ regs[rd] = regs[r1] - regs[r2]; -+ break; -+ case DIF_OP_ADD: -+ regs[rd] = regs[r1] + regs[r2]; -+ break; -+ case DIF_OP_MUL: -+ regs[rd] = regs[r1] * regs[r2]; -+ break; -+ case DIF_OP_SDIV: -+ if (regs[r2] == 0) { -+ regs[rd] = 0; -+ *flags |= CPU_DTRACE_DIVZERO; -+ } else { -+ int neg = 0; -+ -+ /* -+ * We cannot simply do a 64-bit division, since -+ * gcc translates it into a call to a function -+ * that is not linked into the kernel. -+ * -+ * regs[rd] = (int64_t)regs[r1] / -+ * (int64_t)regs[r2]; -+ */ -+ if ((int64_t)regs[r1] < 0) { -+ neg = !neg; -+ regs[r1] = -(int64_t)regs[r1]; -+ } -+ if ((int64_t)regs[r2] < 0) { -+ neg = !neg; -+ regs[r2] = -(int64_t)regs[r2]; -+ } -+ regs[rd] = regs[r1]; -+ do_div(regs[rd], regs[r2]); -+ -+ if (neg) -+ regs[rd] = -(int64_t)regs[rd]; -+ } -+ break; -+ -+ case DIF_OP_UDIV: -+ if (regs[r2] == 0) { -+ regs[rd] = 0; -+ *flags |= CPU_DTRACE_DIVZERO; -+ } else { -+ /* -+ * We cannot simply do a 64-bit division, since -+ * gcc translates it into a call to a function -+ * that is not linked into the kernel. -+ * -+ * regs[rd] = regs[r1] / regs[r2]; -+ */ -+ regs[rd] = regs[r1]; -+ do_div(regs[rd], regs[r2]); -+ } -+ break; -+ -+ case DIF_OP_SREM: -+ if (regs[r2] == 0) { -+ regs[rd] = 0; -+ *flags |= CPU_DTRACE_DIVZERO; -+ } else { -+ int neg = 0; -+ -+ /* -+ * We cannot simply do a 64-bit division, since -+ * gcc translates it into a call to a function -+ * that is not linked into the kernel. -+ * -+ * regs[rd] = (int64_t)regs[r1] % -+ * (int64_t)regs[r2]; -+ */ -+ if ((int64_t)regs[r1] < 0) { -+ neg = !neg; -+ regs[r1] = -(int64_t)regs[r1]; -+ } -+ if ((int64_t)regs[r2] < 0) { -+ neg = !neg; -+ regs[r2] = -(int64_t)regs[r2]; -+ } -+ regs[rd] = regs[r1]; -+ regs[rd] = do_div(regs[rd], regs[r2]); -+ -+ if (neg) -+ regs[rd] = -(int64_t)regs[rd]; -+ } -+ break; -+ -+ case DIF_OP_UREM: -+ if (regs[r2] == 0) { -+ regs[rd] = 0; -+ *flags |= CPU_DTRACE_DIVZERO; -+ } else { -+ /* -+ * We cannot simply do a 64-bit division, since -+ * gcc translates it into a call to a function -+ * that is not linked into the kernel. -+ * -+ * regs[rd] = regs[r1] % regs[r2]; -+ */ -+ regs[rd] = regs[r1]; -+ regs[rd] = do_div(regs[rd], regs[r2]); -+ } -+ break; -+ -+ case DIF_OP_NOT: -+ regs[rd] = ~regs[r1]; -+ break; -+ case DIF_OP_MOV: -+ regs[rd] = regs[r1]; -+ break; -+ case DIF_OP_CMP: -+ cc_r = regs[r1] - regs[r2]; -+ cc_n = cc_r < 0; -+ cc_z = cc_r == 0; -+ cc_v = 0; -+ cc_c = regs[r1] < regs[r2]; -+ break; -+ case DIF_OP_TST: -+ cc_n = cc_v = cc_c = 0; -+ cc_z = regs[r1] == 0; -+ break; -+ case DIF_OP_BA: -+ pc = DIF_INSTR_LABEL(instr); -+ break; -+ case DIF_OP_BE: -+ if (cc_z) -+ pc = DIF_INSTR_LABEL(instr); -+ break; -+ case DIF_OP_BNE: -+ if (cc_z == 0) -+ pc = DIF_INSTR_LABEL(instr); -+ break; -+ case DIF_OP_BG: -+ if ((cc_z | (cc_n ^ cc_v)) == 0) -+ pc = DIF_INSTR_LABEL(instr); -+ break; -+ case DIF_OP_BGU: -+ if ((cc_c | cc_z) == 0) -+ pc = DIF_INSTR_LABEL(instr); -+ break; -+ case DIF_OP_BGE: -+ if ((cc_n ^ cc_v) == 0) -+ pc = DIF_INSTR_LABEL(instr); -+ break; -+ case DIF_OP_BGEU: -+ if (cc_c == 0) -+ pc = DIF_INSTR_LABEL(instr); -+ break; -+ case DIF_OP_BL: -+ if (cc_n ^ cc_v) -+ pc = DIF_INSTR_LABEL(instr); -+ break; -+ case DIF_OP_BLU: -+ if (cc_c) -+ pc = DIF_INSTR_LABEL(instr); -+ break; -+ case DIF_OP_BLE: -+ if (cc_z | (cc_n ^ cc_v)) -+ pc = DIF_INSTR_LABEL(instr); -+ break; -+ case DIF_OP_BLEU: -+ if (cc_c | cc_z) -+ pc = DIF_INSTR_LABEL(instr); -+ break; -+ case DIF_OP_RLDSB: -+#ifdef FIXME_OPENSOLARIS_BUG -+ if (!dtrace_canstore(regs[r1], 1, mstate, vstate)) { -+#else -+ if (!dtrace_canload(regs[r1], 1, mstate, vstate)) { -+#endif -+ *flags |= CPU_DTRACE_KPRIV; -+ *illval = regs[r1]; -+ break; -+ } -+ /*FALLTHROUGH*/ -+ case DIF_OP_LDSB: -+ regs[rd] = (int8_t)dtrace_load8(regs[r1]); -+ break; -+ case DIF_OP_RLDSH: -+ if (!dtrace_canstore(regs[r1], 2, mstate, vstate)) { -+ *flags |= CPU_DTRACE_KPRIV; -+ *illval = regs[r1]; -+ break; -+ } -+ /*FALLTHROUGH*/ -+ case DIF_OP_LDSH: -+ regs[rd] = (int16_t)dtrace_load16(regs[r1]); -+ break; -+ case DIF_OP_RLDSW: -+ if (!dtrace_canstore(regs[r1], 4, mstate, vstate)) { -+ *flags |= CPU_DTRACE_KPRIV; -+ *illval = regs[r1]; -+ break; -+ } -+ /*FALLTHROUGH*/ -+ case DIF_OP_LDSW: -+ regs[rd] = (int32_t)dtrace_load32(regs[r1]); -+ break; -+ case DIF_OP_RLDUB: -+ if (!dtrace_canstore(regs[r1], 1, mstate, vstate)) { -+ *flags |= CPU_DTRACE_KPRIV; -+ *illval = regs[r1]; -+ break; -+ } -+ /*FALLTHROUGH*/ -+ case DIF_OP_LDUB: -+ regs[rd] = dtrace_load8(regs[r1]); -+ break; -+ case DIF_OP_RLDUH: -+ if (!dtrace_canstore(regs[r1], 2, mstate, vstate)) { -+ *flags |= CPU_DTRACE_KPRIV; -+ *illval = regs[r1]; -+ break; -+ } -+ /*FALLTHROUGH*/ -+ case DIF_OP_LDUH: -+ regs[rd] = dtrace_load16(regs[r1]); -+ break; -+ case DIF_OP_RLDUW: -+ if (!dtrace_canstore(regs[r1], 4, mstate, vstate)) { -+ *flags |= CPU_DTRACE_KPRIV; -+ *illval = regs[r1]; -+ break; -+ } -+ /*FALLTHROUGH*/ -+ case DIF_OP_LDUW: -+ regs[rd] = dtrace_load32(regs[r1]); -+ break; -+ case DIF_OP_RLDX: -+ if (!dtrace_canstore(regs[r1], 8, mstate, vstate)) { -+ *flags |= CPU_DTRACE_KPRIV; -+ *illval = regs[r1]; -+ break; -+ } -+ /*FALLTHROUGH*/ -+ case DIF_OP_LDX: -+ regs[rd] = dtrace_load64(regs[r1]); -+ break; -+ case DIF_OP_ULDSB: -+ regs[rd] = (int8_t)dtrace_fuword8( -+ (void *)(uintptr_t)regs[r1]); -+ break; -+ case DIF_OP_ULDSH: -+ regs[rd] = (int16_t)dtrace_fuword16( -+ (void *)(uintptr_t)regs[r1]); -+ break; -+ case DIF_OP_ULDSW: -+ regs[rd] = (int32_t)dtrace_fuword32( -+ (void *)(uintptr_t)regs[r1]); -+ break; -+ case DIF_OP_ULDUB: -+ regs[rd] = dtrace_fuword8((void *)(uintptr_t)regs[r1]); -+ break; -+ case DIF_OP_ULDUH: -+ regs[rd] = dtrace_fuword16( -+ (void *)(uintptr_t)regs[r1]); -+ break; -+ case DIF_OP_ULDUW: -+ regs[rd] = dtrace_fuword32( -+ (void *)(uintptr_t)regs[r1]); -+ break; -+ case DIF_OP_ULDX: -+ regs[rd] = dtrace_fuword64( -+ (void *)(uintptr_t)regs[r1]); -+ break; -+ case DIF_OP_RET: -+ rval = regs[rd]; -+ pc = textlen; -+ break; -+ case DIF_OP_NOP: -+ break; -+ case DIF_OP_SETX: -+ regs[rd] = inttab[DIF_INSTR_INTEGER(instr)]; -+ break; -+ case DIF_OP_SETS: -+ regs[rd] = (uint64_t)(uintptr_t) -+ (strtab + DIF_INSTR_STRING(instr)); -+ break; -+ case DIF_OP_SCMP: { -+ size_t sz = state->dts_options[ -+ DTRACEOPT_STRSIZE]; -+ uintptr_t s1 = regs[r1]; -+ uintptr_t s2 = regs[r2]; -+ -+ if (s1 != (uintptr_t)NULL && -+ !dtrace_strcanload(s1, sz, mstate, vstate)) -+ break; -+ if (s2 != (uintptr_t)NULL && -+ !dtrace_strcanload(s2, sz, mstate, vstate)) -+ break; -+ -+ cc_r = dtrace_strncmp((char *)s1, (char *)s2, sz); -+ -+ cc_n = cc_r < 0; -+ cc_z = cc_r == 0; -+ cc_v = cc_c = 0; -+ break; -+ } -+ case DIF_OP_LDGA: -+ regs[rd] = dtrace_dif_variable(mstate, state, r1, -+ regs[r2]); -+ break; -+ case DIF_OP_LDGS: -+ id = DIF_INSTR_VAR(instr); -+ -+ if (id >= DIF_VAR_OTHER_UBASE) { -+ uintptr_t a; -+ -+ id -= DIF_VAR_OTHER_UBASE; -+ svar = vstate->dtvs_globals[id]; -+ ASSERT(svar != NULL); -+ v = &svar->dtsv_var; -+ -+ if (!(v->dtdv_type.dtdt_flags & DIF_TF_BYREF)) { -+ regs[rd] = svar->dtsv_data; -+ break; -+ } -+ -+ a = (uintptr_t)svar->dtsv_data; -+ -+ /* -+ * If the 0th byte is set to UINT8_MAX then -+ * this is to be treated as a reference to a -+ * NULL variable. -+ */ -+ if (*(uint8_t *)a == UINT8_MAX) -+ regs[rd] = 0; -+ else -+ regs[rd] = a + sizeof(uint64_t); -+ -+ break; -+ } -+ -+ regs[rd] = dtrace_dif_variable(mstate, state, id, 0); -+ break; -+ -+ case DIF_OP_STGS: -+ id = DIF_INSTR_VAR(instr); -+ -+ ASSERT(id >= DIF_VAR_OTHER_UBASE); -+ id -= DIF_VAR_OTHER_UBASE; -+ -+ svar = vstate->dtvs_globals[id]; -+ ASSERT(svar != NULL); -+ v = &svar->dtsv_var; -+ -+ if (v->dtdv_type.dtdt_flags & DIF_TF_BYREF) { -+ uintptr_t a = (uintptr_t)svar->dtsv_data; -+ -+ ASSERT(a != 0); -+ ASSERT(svar->dtsv_size != 0); -+ -+ if (regs[rd] == 0) { -+ *(uint8_t *)a = UINT8_MAX; -+ break; -+ } else { -+ *(uint8_t *)a = 0; -+ a += sizeof(uint64_t); -+ } -+ -+ if (!dtrace_vcanload( -+ (void *)(uintptr_t)regs[rd], -+ &v->dtdv_type, mstate, vstate)) -+ break; -+ -+ dtrace_vcopy((void *)(uintptr_t)regs[rd], -+ (void *)a, &v->dtdv_type); -+ break; -+ } -+ -+ svar->dtsv_data = regs[rd]; -+ break; -+ -+ case DIF_OP_LDTA: -+ /* -+ * There are no DTrace built-in thread-local arrays at -+ * present. This opcode is saved for future work. -+ */ -+ *flags |= CPU_DTRACE_ILLOP; -+ regs[rd] = 0; -+ break; -+ -+ case DIF_OP_LDLS: -+ id = DIF_INSTR_VAR(instr); -+ -+ if (id < DIF_VAR_OTHER_UBASE) { -+ /* -+ * For now, this has no meaning. -+ */ -+ regs[rd] = 0; -+ break; -+ } -+ -+ id -= DIF_VAR_OTHER_UBASE; -+ -+ ASSERT(id < vstate->dtvs_nlocals); -+ ASSERT(vstate->dtvs_locals != NULL); -+ -+ svar = vstate->dtvs_locals[id]; -+ ASSERT(svar != NULL); -+ v = &svar->dtsv_var; -+ -+ if (v->dtdv_type.dtdt_flags & DIF_TF_BYREF) { -+ uintptr_t a = (uintptr_t)svar->dtsv_data; -+ size_t sz = v->dtdv_type.dtdt_size; -+ -+ sz += sizeof(uint64_t); -+ ASSERT(svar->dtsv_size == NR_CPUS * sz); -+ a += smp_processor_id() * sz; -+ -+ if (*(uint8_t *)a == UINT8_MAX) { -+ /* -+ * If the 0th byte is set to UINT8_MAX -+ * then this is to be treated as a -+ * reference to a NULL variable. -+ */ -+ regs[rd] = 0; -+ } else -+ regs[rd] = a + sizeof(uint64_t); -+ -+ break; -+ } -+ -+ ASSERT(svar->dtsv_size == NR_CPUS * sizeof(uint64_t)); -+ tmp = (uint64_t *)(uintptr_t)svar->dtsv_data; -+ regs[rd] = tmp[smp_processor_id()]; -+ break; -+ -+ case DIF_OP_STLS: -+ id = DIF_INSTR_VAR(instr); -+ -+ ASSERT(id >= DIF_VAR_OTHER_UBASE); -+ id -= DIF_VAR_OTHER_UBASE; -+ ASSERT(id < vstate->dtvs_nlocals); -+ -+ ASSERT(vstate->dtvs_locals != NULL); -+ svar = vstate->dtvs_locals[id]; -+ ASSERT(svar != NULL); -+ v = &svar->dtsv_var; -+ -+ if (v->dtdv_type.dtdt_flags & DIF_TF_BYREF) { -+ uintptr_t a = (uintptr_t)svar->dtsv_data; -+ size_t sz = v->dtdv_type.dtdt_size; -+ -+ sz += sizeof(uint64_t); -+ ASSERT(svar->dtsv_size == NR_CPUS * sz); -+ a += smp_processor_id() * sz; -+ -+ if (regs[rd] == 0) { -+ *(uint8_t *)a = UINT8_MAX; -+ break; -+ } else { -+ *(uint8_t *)a = 0; -+ a += sizeof(uint64_t); -+ } -+ -+ if (!dtrace_vcanload( -+ (void *)(uintptr_t)regs[rd], -+ &v->dtdv_type, mstate, vstate)) -+ break; -+ -+ dtrace_vcopy((void *)(uintptr_t)regs[rd], -+ (void *)a, &v->dtdv_type); -+ break; -+ } -+ -+ ASSERT(svar->dtsv_size == NR_CPUS * sizeof(uint64_t)); -+ tmp = (uint64_t *)(uintptr_t)svar->dtsv_data; -+ tmp[smp_processor_id()] = regs[rd]; -+ break; -+ -+ case DIF_OP_LDTS: { -+ struct dtrace_dynvar *dvar; -+ struct dtrace_key *key; -+ -+ id = DIF_INSTR_VAR(instr); -+ ASSERT(id >= DIF_VAR_OTHER_UBASE); -+ id -= DIF_VAR_OTHER_UBASE; -+ v = &vstate->dtvs_tlocals[id]; -+ -+ key = &tupregs[DIF_DTR_NREGS]; -+ key[0].dttk_value = (uint64_t)id; -+ key[0].dttk_size = 0; -+ DTRACE_TLS_THRKEY(key[1].dttk_value); -+ key[1].dttk_size = 0; -+ -+ dvar = dtrace_dynvar(dstate, 2, key, sizeof(uint64_t), -+ DTRACE_DYNVAR_NOALLOC, mstate, -+ vstate); -+ -+ if (dvar == NULL) { -+ regs[rd] = 0; -+ break; -+ } -+ -+ if (v->dtdv_type.dtdt_flags & DIF_TF_BYREF) -+ regs[rd] = (uint64_t)(uintptr_t)dvar->dtdv_data; -+ else -+ regs[rd] = *((uint64_t *)dvar->dtdv_data); -+ -+ break; -+ } -+ -+ case DIF_OP_STTS: { -+ struct dtrace_dynvar *dvar; -+ struct dtrace_key *key; -+ -+ id = DIF_INSTR_VAR(instr); -+ ASSERT(id >= DIF_VAR_OTHER_UBASE); -+ id -= DIF_VAR_OTHER_UBASE; -+ -+ key = &tupregs[DIF_DTR_NREGS]; -+ key[0].dttk_value = (uint64_t)id; -+ key[0].dttk_size = 0; -+ DTRACE_TLS_THRKEY(key[1].dttk_value); -+ key[1].dttk_size = 0; -+ v = &vstate->dtvs_tlocals[id]; -+ -+ dvar = dtrace_dynvar(dstate, 2, key, -+ v->dtdv_type.dtdt_size > sizeof(uint64_t) -+ ? v->dtdv_type.dtdt_size -+ : sizeof(uint64_t), -+ regs[rd] -+ ? DTRACE_DYNVAR_ALLOC -+ : DTRACE_DYNVAR_DEALLOC, -+ mstate, vstate); -+ -+ /* -+ * Given that we're storing to thread-local data, -+ * we need to flush our predicate cache. -+ */ -+ if (current->dt_task != NULL) -+ current->dt_task->dt_predcache = 0; -+ -+ if (dvar == NULL) -+ break; -+ -+ if (v->dtdv_type.dtdt_flags & DIF_TF_BYREF) { -+ if (!dtrace_vcanload( -+ (void *)(uintptr_t)regs[rd], -+ &v->dtdv_type, mstate, vstate)) -+ break; -+ -+ dtrace_vcopy((void *)(uintptr_t)regs[rd], -+ dvar->dtdv_data, &v->dtdv_type); -+ } else -+ *((uint64_t *)dvar->dtdv_data) = regs[rd]; -+ -+ break; -+ } -+ -+ case DIF_OP_SRA: -+ regs[rd] = (int64_t)regs[r1] >> regs[r2]; -+ break; -+ -+ case DIF_OP_CALL: -+ dtrace_dif_subr(DIF_INSTR_SUBR(instr), rd, regs, -+ tupregs, ttop, mstate, state); -+ break; -+ -+ case DIF_OP_PUSHTR: -+ if (ttop == DIF_DTR_NREGS) { -+ *flags |= CPU_DTRACE_TUPOFLOW; -+ break; -+ } -+ -+ if (r1 == DIF_TYPE_STRING) -+ /* -+ * If this is a string type and the size is 0, -+ * we'll use the system-wide default string -+ * size. Note that we are _not_ looking at -+ * the value of the DTRACEOPT_STRSIZE option; -+ * had this been set, we would expect to have -+ * a non-zero size value in the "pushtr". -+ */ -+ tupregs[ttop].dttk_size = -+ dtrace_strlen( -+ (char *)(uintptr_t)regs[rd], -+ regs[r2] -+ ? regs[r2] -+ : dtrace_strsize_default -+ ) + 1; -+ else -+ tupregs[ttop].dttk_size = regs[r2]; -+ -+ tupregs[ttop++].dttk_value = regs[rd]; -+ break; -+ -+ case DIF_OP_PUSHTV: -+ if (ttop == DIF_DTR_NREGS) { -+ *flags |= CPU_DTRACE_TUPOFLOW; -+ break; -+ } -+ -+ tupregs[ttop].dttk_value = regs[rd]; -+ tupregs[ttop++].dttk_size = 0; -+ break; -+ -+ case DIF_OP_POPTS: -+ if (ttop != 0) -+ ttop--; -+ break; -+ -+ case DIF_OP_FLUSHTS: -+ ttop = 0; -+ break; -+ -+ case DIF_OP_LDGAA: -+ case DIF_OP_LDTAA: { -+ struct dtrace_dynvar *dvar; -+ struct dtrace_key *key = tupregs; -+ uint_t nkeys = ttop; -+ -+ id = DIF_INSTR_VAR(instr); -+ ASSERT(id >= DIF_VAR_OTHER_UBASE); -+ id -= DIF_VAR_OTHER_UBASE; -+ -+ key[nkeys].dttk_value = (uint64_t)id; -+ key[nkeys++].dttk_size = 0; -+ -+ if (DIF_INSTR_OP(instr) == DIF_OP_LDTAA) { -+ DTRACE_TLS_THRKEY(key[nkeys].dttk_value); -+ key[nkeys++].dttk_size = 0; -+ v = &vstate->dtvs_tlocals[id]; -+ } else -+ v = &vstate->dtvs_globals[id]->dtsv_var; -+ -+ dvar = dtrace_dynvar(dstate, nkeys, key, -+ v->dtdv_type.dtdt_size > sizeof(uint64_t) ? -+ v->dtdv_type.dtdt_size : sizeof(uint64_t), -+ DTRACE_DYNVAR_NOALLOC, mstate, vstate); -+ -+ if (dvar == NULL) { -+ regs[rd] = 0; -+ break; -+ } -+ -+ if (v->dtdv_type.dtdt_flags & DIF_TF_BYREF) -+ regs[rd] = (uint64_t)(uintptr_t)dvar->dtdv_data; -+ else -+ regs[rd] = *((uint64_t *)dvar->dtdv_data); -+ -+ break; -+ } -+ -+ case DIF_OP_STGAA: -+ case DIF_OP_STTAA: { -+ struct dtrace_dynvar *dvar; -+ struct dtrace_key *key = tupregs; -+ uint_t nkeys = ttop; -+ -+ id = DIF_INSTR_VAR(instr); -+ ASSERT(id >= DIF_VAR_OTHER_UBASE); -+ id -= DIF_VAR_OTHER_UBASE; -+ -+ key[nkeys].dttk_value = (uint64_t)id; -+ key[nkeys++].dttk_size = 0; -+ -+ if (DIF_INSTR_OP(instr) == DIF_OP_STTAA) { -+ DTRACE_TLS_THRKEY(key[nkeys].dttk_value); -+ key[nkeys++].dttk_size = 0; -+ v = &vstate->dtvs_tlocals[id]; -+ } else -+ v = &vstate->dtvs_globals[id]->dtsv_var; -+ -+ dvar = dtrace_dynvar(dstate, nkeys, key, -+ v->dtdv_type.dtdt_size > sizeof(uint64_t) -+ ? v->dtdv_type.dtdt_size -+ : sizeof(uint64_t), -+ regs[rd] ? DTRACE_DYNVAR_ALLOC -+ : DTRACE_DYNVAR_DEALLOC, -+ mstate, vstate); -+ -+ if (dvar == NULL) -+ break; -+ -+ if (v->dtdv_type.dtdt_flags & DIF_TF_BYREF) { -+ if (!dtrace_vcanload( -+ (void *)(uintptr_t)regs[rd], -+ &v->dtdv_type, mstate, vstate)) -+ break; -+ -+ dtrace_vcopy((void *)(uintptr_t)regs[rd], -+ dvar->dtdv_data, &v->dtdv_type); -+ } else -+ *((uint64_t *)dvar->dtdv_data) = regs[rd]; -+ -+ break; -+ } -+ -+ case DIF_OP_ALLOCS: { -+ uintptr_t ptr = -+ P2ROUNDUP(mstate->dtms_scratch_ptr, 8); -+ size_t size = ptr - mstate->dtms_scratch_ptr + -+ regs[r1]; -+ -+ /* -+ * Rounding up the user allocation size could have -+ * overflowed large, bogus allocations (like -1ULL) to -+ * 0. -+ */ -+ if (size < regs[r1] || -+ !DTRACE_INSCRATCH(mstate, size)) { -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); -+ regs[rd] = 0; -+ break; -+ } -+ -+ dtrace_bzero((void *) mstate->dtms_scratch_ptr, size); -+ mstate->dtms_scratch_ptr += size; -+ regs[rd] = ptr; -+ break; -+ } -+ -+ case DIF_OP_COPYS: -+ if (!dtrace_canstore(regs[rd], regs[r2], mstate, -+ vstate)) { -+ *flags |= CPU_DTRACE_BADADDR; -+ *illval = regs[rd]; -+ break; -+ } -+ -+ if (!dtrace_canload(regs[r1], regs[r2], mstate, vstate)) -+ break; -+ -+ dtrace_bcopy((void *)(uintptr_t)regs[r1], -+ (void *)(uintptr_t)regs[rd], -+ (size_t)regs[r2]); -+ break; -+ -+ case DIF_OP_STB: -+ if (!dtrace_canstore(regs[rd], 1, mstate, vstate)) { -+ *flags |= CPU_DTRACE_BADADDR; -+ *illval = regs[rd]; -+ break; -+ } -+ -+ *((uint8_t *)(uintptr_t)regs[rd]) = (uint8_t)regs[r1]; -+ break; -+ -+ case DIF_OP_STH: -+ if (!dtrace_canstore(regs[rd], 2, mstate, vstate)) { -+ *flags |= CPU_DTRACE_BADADDR; -+ *illval = regs[rd]; -+ break; -+ } -+ -+ if (regs[rd] & 1) { -+ *flags |= CPU_DTRACE_BADALIGN; -+ *illval = regs[rd]; -+ break; -+ } -+ -+ *((uint16_t *)(uintptr_t)regs[rd]) = (uint16_t)regs[r1]; -+ break; -+ -+ case DIF_OP_STW: -+ if (!dtrace_canstore(regs[rd], 4, mstate, vstate)) { -+ *flags |= CPU_DTRACE_BADADDR; -+ *illval = regs[rd]; -+ break; -+ } -+ -+ if (regs[rd] & 3) { -+ *flags |= CPU_DTRACE_BADALIGN; -+ *illval = regs[rd]; -+ break; -+ } -+ -+ *((uint32_t *)(uintptr_t)regs[rd]) = (uint32_t)regs[r1]; -+ break; -+ -+ case DIF_OP_STX: -+ if (!dtrace_canstore(regs[rd], 8, mstate, vstate)) { -+ *flags |= CPU_DTRACE_BADADDR; -+ *illval = regs[rd]; -+ break; -+ } -+ -+ if (regs[rd] & 7) { -+ *flags |= CPU_DTRACE_BADALIGN; -+ *illval = regs[rd]; -+ break; -+ } -+ -+ *((uint64_t *)(uintptr_t)regs[rd]) = regs[r1]; -+ break; -+ } -+ } -+ -+ -+ if (!(*flags & CPU_DTRACE_FAULT)) { -+ dt_dbg_dif(" DIF %p completed, rval = %llx (flags %x)\n", -+ difo, rval, *flags); -+ return rval; -+ } -+ -+ dt_dbg_dif(" DIF %p emulation failed (flags %x)\n", difo, *flags); -+ -+ mstate->dtms_fltoffs = opc * sizeof(dif_instr_t); -+ mstate->dtms_present |= DTRACE_MSTATE_FLTOFFS; -+ -+ return 0; -+} -diff --git a/dtrace/dtrace_dof.c b/dtrace/dtrace_dof.c -new file mode 100644 -index 000000000000..85ff9b21a205 ---- /dev/null -+++ b/dtrace/dtrace_dof.c -@@ -0,0 +1,2504 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_dof.c -+ * DESCRIPTION: DTrace - DOF implementation -+ * -+ * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/dtrace_task_impl.h> -+#include <linux/slab.h> -+#include <linux/types.h> -+#include <linux/vmalloc.h> -+#include <linux/uaccess.h> -+ -+#include "dtrace.h" -+ -+size_t dtrace_difo_maxsize = 256 * 1024; -+dtrace_optval_t dtrace_dof_maxsize = 256 * 1024; -+size_t dtrace_actions_max = 16 * 1024; -+dtrace_optval_t dtrace_helper_actions_max = 32; -+dtrace_optval_t dtrace_helper_providers_max = 32; -+ -+static int dtrace_helpers; -+ -+static uint32_t dtrace_helptrace_next; -+static uint32_t dtrace_helptrace_nlocals; -+ -+#ifdef CONFIG_DT_DEBUG -+int dtrace_helptrace_enabled = 1; -+#else -+int dtrace_helptrace_enabled = 0; -+#endif -+int dtrace_helptrace_bufsize = 512 * 1024; -+char *dtrace_helptrace_buffer; -+ -+void dtrace_dof_error(struct dof_hdr *dof, const char *str) -+{ -+ if (dtrace_err_verbose) -+ pr_warn("failed to process DOF: %s", str); -+ else -+ dt_dbg_dof("Failed to process DOF: %s\n", str); -+ -+#ifdef DTRACE_ERRDEBUG -+ dtrace_errdebug(str); -+#endif -+} -+ -+/* -+ * Create DOF out of a currently enabled state. Right now, we only create -+ * DOF containing the run-time options -- but this could be expanded to create -+ * complete DOF representing the enabled state. -+ */ -+struct dof_hdr *dtrace_dof_create(struct dtrace_state *state) -+{ -+ struct dof_hdr *dof; -+ struct dof_sec *sec; -+ struct dof_optdesc *opt; -+ -+ int i, len = sizeof(struct dof_hdr) + -+ roundup(sizeof(struct dof_sec), -+ sizeof(uint64_t)) + -+ sizeof(struct dof_optdesc) * DTRACEOPT_MAX; -+ -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ -+ dof = vmalloc(len); -+ if (dof == NULL) -+ return NULL; -+ -+ dof->dofh_ident[DOF_ID_MAG0] = DOF_MAG_MAG0; -+ dof->dofh_ident[DOF_ID_MAG1] = DOF_MAG_MAG1; -+ dof->dofh_ident[DOF_ID_MAG2] = DOF_MAG_MAG2; -+ dof->dofh_ident[DOF_ID_MAG3] = DOF_MAG_MAG3; -+ -+ dof->dofh_ident[DOF_ID_MODEL] = DOF_MODEL_NATIVE; -+ dof->dofh_ident[DOF_ID_ENCODING] = DOF_ENCODE_NATIVE; -+ dof->dofh_ident[DOF_ID_VERSION] = DOF_VERSION; -+ dof->dofh_ident[DOF_ID_DIFVERS] = DIF_VERSION; -+ dof->dofh_ident[DOF_ID_DIFIREG] = DIF_DIR_NREGS; -+ dof->dofh_ident[DOF_ID_DIFTREG] = DIF_DTR_NREGS; -+ -+ dof->dofh_flags = 0; -+ dof->dofh_hdrsize = sizeof(struct dof_hdr); -+ dof->dofh_secsize = sizeof(struct dof_sec); -+ dof->dofh_secnum = 1; /* only DOF_SECT_OPTDESC */ -+ dof->dofh_secoff = sizeof(struct dof_hdr); -+ dof->dofh_loadsz = len; -+ dof->dofh_filesz = len; -+ dof->dofh_pad = 0; -+ -+ /* -+ * Fill in the option section header... -+ */ -+ sec = (struct dof_sec *)((uintptr_t)dof + sizeof(struct dof_hdr)); -+ sec->dofs_type = DOF_SECT_OPTDESC; -+ sec->dofs_align = sizeof(uint64_t); -+ sec->dofs_flags = DOF_SECF_LOAD; -+ sec->dofs_entsize = sizeof(struct dof_optdesc); -+ -+ opt = (struct dof_optdesc *)((uintptr_t)sec + -+ roundup(sizeof(struct dof_sec), -+ sizeof(uint64_t))); -+ -+ sec->dofs_offset = (uintptr_t)opt - (uintptr_t)dof; -+ sec->dofs_size = sizeof(struct dof_optdesc) * DTRACEOPT_MAX; -+ -+ for (i = 0; i < DTRACEOPT_MAX; i++) { -+ opt[i].dofo_option = i; -+ opt[i].dofo_strtab = DOF_SECIDX_NONE; -+ opt[i].dofo_value = state->dts_options[i]; -+ } -+ -+ return dof; -+} -+ -+struct dof_hdr *dtrace_dof_copyin(void __user *argp, int *errp) -+{ -+ struct dof_hdr hdr, *dof; -+ -+ ASSERT(!MUTEX_HELD(&dtrace_lock)); -+ -+ /* -+ * First, we're going to copyin() the sizeof(dof_hdr_t). -+ */ -+ if (copy_from_user(&hdr, argp, sizeof(hdr)) != 0) { -+ dtrace_dof_error(NULL, "failed to copyin DOF header"); -+ *errp = -EFAULT; -+ return NULL; -+ } -+ -+ /* -+ * Now we'll allocate the entire DOF and copy it in -- provided -+ * that the length isn't outrageous. -+ */ -+ if (hdr.dofh_loadsz >= dtrace_dof_maxsize) { -+ dtrace_dof_error(&hdr, "load size exceeds maximum"); -+ *errp = -E2BIG; -+ return NULL; -+ } -+ -+ if (hdr.dofh_loadsz < sizeof(hdr)) { -+ dtrace_dof_error(&hdr, "invalid load size"); -+ *errp = -EINVAL; -+ return NULL; -+ } -+ -+ dof = vmalloc(hdr.dofh_loadsz); -+ if (dof == NULL) { -+ *errp = -ENOMEM; -+ return NULL; -+ } -+ -+ if (copy_from_user(dof, argp, hdr.dofh_loadsz) != 0 || -+ dof->dofh_loadsz != hdr.dofh_loadsz) { -+ vfree(dof); -+ *errp = -EFAULT; -+ return NULL; -+ } -+ -+ return dof; -+} -+ -+struct dof_hdr *dtrace_dof_property(const char *name) -+{ -+ uchar_t *buf; -+ uint64_t loadsz; -+ unsigned int len, i; -+ struct dof_hdr *dof; -+ -+ /* -+ * Unfortunately, array of values in .conf files are always (and -+ * only) interpreted to be integer arrays. We must read our DOF -+ * as an integer array, and then squeeze it into a byte array. -+ */ -+#ifdef FIXME -+ if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dtrace_devi, 0, -+ (char *)name, (int **)&buf, &len) != -+ DDI_PROP_SUCCESS) -+ return NULL; -+#else -+ return NULL; -+#endif -+ -+ for (i = 0; i < len; i++) -+ buf[i] = (uchar_t)(((int *)buf)[i]); -+ -+ if (len < sizeof(struct dof_hdr)) { -+#ifdef FIXME -+ ddi_prop_free(buf); -+#endif -+ dtrace_dof_error(NULL, "truncated header"); -+ return NULL; -+ } -+ -+ loadsz = ((struct dof_hdr *)buf)->dofh_loadsz; -+ if (len < loadsz) { -+#ifdef FIXME -+ ddi_prop_free(buf); -+#endif -+ dtrace_dof_error(NULL, "truncated DOF"); -+ return NULL; -+ } -+ -+ if (loadsz >= dtrace_dof_maxsize) { -+#ifdef FIXME -+ ddi_prop_free(buf); -+#endif -+ dtrace_dof_error(NULL, "oversized DOF"); -+ return NULL; -+ } -+ -+ dof = vmalloc(loadsz); -+ if (dof == NULL) { -+ dtrace_dof_error(NULL, "out-of-memory"); -+ return NULL; -+ } -+ memcpy(dof, buf, loadsz); -+#ifdef FIXME -+ ddi_prop_free(buf); -+#endif -+ -+ return dof; -+} -+ -+void dtrace_dof_destroy(struct dof_hdr *dof) -+{ -+ vfree(dof); -+} -+ -+/* -+ * Return the dof_sec_t pointer corresponding to a given section index. If the -+ * index is not valid, dtrace_dof_error() is called and NULL is returned. If -+ * a type other than DOF_SECT_NONE is specified, the header is checked against -+ * this type and NULL is returned if the types do not match. -+ */ -+static struct dof_sec *dtrace_dof_sect(struct dof_hdr *dof, uint32_t doftype, -+ dof_secidx_t i) -+{ -+ struct dof_sec *sec; -+ -+ sec = (struct dof_sec *)(uintptr_t) ((uintptr_t)dof + -+ dof->dofh_secoff + -+ i * dof->dofh_secsize); -+ -+ if (i >= dof->dofh_secnum) { -+ dtrace_dof_error(dof, "referenced section index is invalid"); -+ return NULL; -+ } -+ -+ if (!(sec->dofs_flags & DOF_SECF_LOAD)) { -+ dtrace_dof_error(dof, "referenced section is not loadable"); -+ return NULL; -+ } -+ -+ if (doftype != DOF_SECT_NONE && doftype != sec->dofs_type) { -+ dtrace_dof_error(dof, "referenced section is the wrong type"); -+ return NULL; -+ } -+ -+ return sec; -+} -+ -+static struct dtrace_probedesc *dtrace_dof_probedesc(struct dof_hdr *dof, -+ struct dof_sec *sec, -+ struct dtrace_probedesc *desc) -+{ -+ struct dof_probedesc *probe; -+ struct dof_sec *strtab; -+ uintptr_t daddr = (uintptr_t)dof; -+ uintptr_t str; -+ size_t size; -+ -+ if (sec->dofs_type != DOF_SECT_PROBEDESC) { -+ dtrace_dof_error(dof, "invalid probe section"); -+ return NULL; -+ } -+ -+ if (sec->dofs_align != sizeof(dof_secidx_t)) { -+ dtrace_dof_error(dof, "bad alignment in probe description"); -+ return NULL; -+ } -+ -+ if (sec->dofs_offset + sizeof(struct dof_probedesc) > -+ dof->dofh_loadsz) { -+ dtrace_dof_error(dof, "truncated probe description"); -+ return NULL; -+ } -+ -+ probe = (struct dof_probedesc *)(uintptr_t)(daddr + sec->dofs_offset); -+ strtab = dtrace_dof_sect(dof, DOF_SECT_STRTAB, probe->dofp_strtab); -+ -+ if (strtab == NULL) -+ return NULL; -+ -+ str = daddr + strtab->dofs_offset; -+ size = strtab->dofs_size; -+ -+ if (probe->dofp_provider >= strtab->dofs_size) { -+ dtrace_dof_error(dof, "corrupt probe provider"); -+ return NULL; -+ } -+ -+ strncpy(desc->dtpd_provider, (char *)(str + probe->dofp_provider), -+ min((size_t)DTRACE_PROVNAMELEN - 1, -+ size - probe->dofp_provider)); -+ -+ if (probe->dofp_mod >= strtab->dofs_size) { -+ dtrace_dof_error(dof, "corrupt probe module"); -+ return NULL; -+ } -+ -+ strncpy(desc->dtpd_mod, (char *)(str + probe->dofp_mod), -+ min((size_t)DTRACE_MODNAMELEN - 1, size - probe->dofp_mod)); -+ -+ if (probe->dofp_func >= strtab->dofs_size) { -+ dtrace_dof_error(dof, "corrupt probe function"); -+ return NULL; -+ } -+ -+ strncpy(desc->dtpd_func, (char *)(str + probe->dofp_func), -+ min((size_t)DTRACE_FUNCNAMELEN - 1, size - probe->dofp_func)); -+ -+ if (probe->dofp_name >= strtab->dofs_size) { -+ dtrace_dof_error(dof, "corrupt probe name"); -+ return NULL; -+ } -+ -+ strncpy(desc->dtpd_name, (char *)(str + probe->dofp_name), -+ min((size_t)DTRACE_NAMELEN - 1, size - probe->dofp_name)); -+ -+ dt_dbg_dof(" ECB Probe %s:%s:%s:%s\n", -+ desc->dtpd_provider, desc->dtpd_mod, desc->dtpd_func, -+ desc->dtpd_name); -+ -+ return desc; -+} -+ -+static struct dtrace_difo *dtrace_dof_difo(struct dof_hdr *dof, -+ struct dof_sec *sec, -+ struct dtrace_vstate *vstate, -+ const struct cred *cr) -+{ -+ struct dtrace_difo *dp; -+ size_t ttl = 0; -+ struct dof_difohdr *dofd; -+ uintptr_t daddr = (uintptr_t)dof; -+ size_t max = dtrace_difo_maxsize; -+ int i, l, n; -+ -+ static const struct { -+ int section; -+ int bufoffs; -+ int lenoffs; -+ int entsize; -+ int align; -+ const char *msg; -+ } difo[] = { -+ { -+ DOF_SECT_DIF, -+ offsetof(struct dtrace_difo, dtdo_buf), -+ offsetof(struct dtrace_difo, dtdo_len), -+ sizeof(dif_instr_t), -+ sizeof(dif_instr_t), -+ "multiple DIF sections" -+ }, -+ { -+ DOF_SECT_INTTAB, -+ offsetof(struct dtrace_difo, dtdo_inttab), -+ offsetof(struct dtrace_difo, dtdo_intlen), -+ sizeof(uint64_t), -+ sizeof(uint64_t), -+ "multiple integer tables" -+ }, -+ { -+ DOF_SECT_STRTAB, -+ offsetof(struct dtrace_difo, dtdo_strtab), -+ offsetof(struct dtrace_difo, dtdo_strlen), -+ 0, -+ sizeof(char), -+ "multiple string tables" -+ }, -+ { -+ DOF_SECT_VARTAB, -+ offsetof(struct dtrace_difo, dtdo_vartab), -+ offsetof(struct dtrace_difo, dtdo_varlen), -+ sizeof(struct dtrace_difv), -+ sizeof(uint_t), -+ "multiple variable tables" -+ }, -+ { -+ DOF_SECT_NONE, -+ 0, -+ 0, -+ 0, -+ 0, -+ NULL -+ } -+ }; -+ -+ if (sec->dofs_type != DOF_SECT_DIFOHDR) { -+ dtrace_dof_error(dof, "invalid DIFO header section"); -+ return NULL; -+ } -+ -+ if (sec->dofs_align != sizeof(dof_secidx_t)) { -+ dtrace_dof_error(dof, "bad alignment in DIFO header"); -+ return NULL; -+ } -+ -+ if (sec->dofs_size < sizeof(struct dof_difohdr) || -+ sec->dofs_size % sizeof(dof_secidx_t)) { -+ dtrace_dof_error(dof, "bad size in DIFO header"); -+ return NULL; -+ } -+ -+ dofd = (struct dof_difohdr *)(uintptr_t)(daddr + sec->dofs_offset); -+ n = (sec->dofs_size - sizeof(*dofd)) / sizeof(dof_secidx_t) + 1; -+ -+ dp = kzalloc(sizeof(struct dtrace_difo), GFP_KERNEL); -+ if (dp == NULL) { -+ dtrace_dof_error(dof, "out-of-memory"); -+ return NULL; -+ } -+ dp->dtdo_rtype = dofd->dofd_rtype; -+ -+ for (l = 0; l < n; l++) { -+ struct dof_sec *subsec; -+ void **bufp; -+ uint32_t *lenp; -+ -+ subsec = dtrace_dof_sect(dof, DOF_SECT_NONE, -+ dofd->dofd_links[l]); -+ if (subsec == NULL) -+ goto err; /* invalid section link */ -+ -+ if (ttl + subsec->dofs_size > max) { -+ dtrace_dof_error(dof, "exceeds maximum size"); -+ goto err; -+ } -+ -+ ttl += subsec->dofs_size; -+ -+ for (i = 0; difo[i].section != DOF_SECT_NONE; i++) { -+ if (subsec->dofs_type != difo[i].section) -+ continue; -+ -+ if (!(subsec->dofs_flags & DOF_SECF_LOAD)) { -+ dtrace_dof_error(dof, "section not loaded"); -+ goto err; -+ } -+ -+ if (subsec->dofs_align != difo[i].align) { -+ dtrace_dof_error(dof, "bad alignment"); -+ goto err; -+ } -+ -+ bufp = (void **)((uintptr_t)dp + difo[i].bufoffs); -+ lenp = (uint32_t *)((uintptr_t)dp + difo[i].lenoffs); -+ -+ if (*bufp != NULL) { -+ dtrace_dof_error(dof, difo[i].msg); -+ goto err; -+ } -+ -+ if (difo[i].entsize != subsec->dofs_entsize) { -+ dtrace_dof_error(dof, "entry size mismatch"); -+ goto err; -+ } -+ -+ if (subsec->dofs_entsize != 0) { -+ uint64_t n = subsec->dofs_size; -+ -+ if (do_div(n, subsec->dofs_entsize) != 0) { -+ dtrace_dof_error(dof, -+ "corrupt entry size"); -+ goto err; -+ } -+ } -+ -+ *lenp = subsec->dofs_size; -+ *bufp = vmalloc(subsec->dofs_size); -+ if (*bufp == NULL) { -+ dtrace_dof_error(dof, "out-of-memory"); -+ goto err; -+ } -+ memcpy(*bufp, -+ (char *)(uintptr_t)(daddr + subsec->dofs_offset), -+ subsec->dofs_size); -+ -+ if (subsec->dofs_entsize != 0) -+ *lenp /= subsec->dofs_entsize; -+ -+ break; -+ } -+ -+ /* -+ * If we encounter a loadable DIFO sub-section that is not -+ * known to us, assume this is a broken program and fail. -+ */ -+ if (difo[i].section == DOF_SECT_NONE && -+ (subsec->dofs_flags & DOF_SECF_LOAD)) { -+ dtrace_dof_error(dof, "unrecognized DIFO subsection"); -+ goto err; -+ } -+ } -+ -+ if (dp->dtdo_buf == NULL) { -+ /* -+ * We can't have a DIF object without DIF text. -+ */ -+ dtrace_dof_error(dof, "missing DIF text"); -+ goto err; -+ } -+ -+ /* -+ * Before we validate the DIF object, run through the variable table -+ * looking for the strings -- if any of their size are under, we'll set -+ * their size to be the system-wide default string size. Note that -+ * this should _not_ happen if the "strsize" option has been set -- -+ * in this case, the compiler should have set the size to reflect the -+ * setting of the option. -+ */ -+ for (i = 0; i < dp->dtdo_varlen; i++) { -+ struct dtrace_difv *v = &dp->dtdo_vartab[i]; -+ struct dtrace_diftype *t = &v->dtdv_type; -+ -+ if (v->dtdv_id < DIF_VAR_OTHER_UBASE) -+ continue; -+ -+ if (t->dtdt_kind == DIF_TYPE_STRING && t->dtdt_size == 0) -+ t->dtdt_size = dtrace_strsize_default; -+ } -+ -+ if (dtrace_difo_validate(dp, vstate, DIF_DIR_NREGS, cr) != 0) -+ goto err; -+ -+ dtrace_difo_init(dp, vstate); -+ return dp; -+ -+err: -+ if (dp->dtdo_buf != NULL) -+ vfree(dp->dtdo_buf); -+ if (dp->dtdo_inttab != NULL) -+ vfree(dp->dtdo_inttab); -+ if (dp->dtdo_strtab != NULL) -+ vfree(dp->dtdo_strtab); -+ if (dp->dtdo_vartab != NULL) -+ vfree(dp->dtdo_vartab); -+ -+ kfree(dp); -+ -+ return NULL; -+} -+ -+static struct dtrace_predicate *dtrace_dof_predicate(struct dof_hdr *dof, -+ struct dof_sec *sec, -+ struct dtrace_vstate *vstate, -+ const struct cred *cr) -+{ -+ struct dtrace_difo *dp; -+ -+ if ((dp = dtrace_dof_difo(dof, sec, vstate, cr)) == NULL) -+ return NULL; -+ -+ return dtrace_predicate_create(dp); -+} -+ -+static struct dtrace_actdesc *dtrace_dof_actdesc(struct dof_hdr *dof, -+ struct dof_sec *sec, -+ struct dtrace_vstate *vstate, -+ const struct cred *cr) -+{ -+ struct dtrace_actdesc *act, *first = NULL, *last = NULL, *next; -+ struct dof_actdesc *desc; -+ struct dof_sec *difosec; -+ size_t offs; -+ uintptr_t daddr = (uintptr_t)dof; -+ uint64_t arg; -+ dtrace_actkind_t kind; -+ -+ if (sec->dofs_type != DOF_SECT_ACTDESC) { -+ dtrace_dof_error(dof, "invalid action section"); -+ return NULL; -+ } -+ -+ if (sec->dofs_offset + sizeof(struct dof_actdesc) > dof->dofh_loadsz) { -+ dtrace_dof_error(dof, "truncated action description"); -+ return NULL; -+ } -+ -+ if (sec->dofs_align != sizeof(uint64_t)) { -+ dtrace_dof_error(dof, "bad alignment in action description"); -+ return NULL; -+ } -+ -+ if (sec->dofs_size < sec->dofs_entsize) { -+ dtrace_dof_error(dof, "section entry size exceeds total size"); -+ return NULL; -+ } -+ -+ if (sec->dofs_entsize != sizeof(struct dof_actdesc)) { -+ dtrace_dof_error(dof, "bad entry size in action description"); -+ return NULL; -+ } -+ -+ /* -+ * Was: sec->dofs_size / sec->dofs_entsize > dtrace_actions_max -+ * but it is safer to simply avoid the division (it requires use of -+ * a macro in Linux to cover 64-bit division in a 32-bit kernel. -+ */ -+ if (sec->dofs_size > sec->dofs_entsize * dtrace_actions_max) { -+ dtrace_dof_error(dof, "actions exceed dtrace_actions_max"); -+ return NULL; -+ } -+ -+ for (offs = 0; offs < sec->dofs_size; offs += sec->dofs_entsize) { -+ desc = (struct dof_actdesc *)(daddr + -+ (uintptr_t)sec->dofs_offset + offs); -+ kind = (dtrace_actkind_t)desc->dofa_kind; -+ -+ if (DTRACEACT_ISPRINTFLIKE(kind) && -+ (kind != DTRACEACT_PRINTA || -+ desc->dofa_strtab != DOF_SECIDX_NONE)) { -+ struct dof_sec *strtab; -+ char *str, *fmt; -+ uint64_t i; -+ -+ /* -+ * The printf()-like actions must have a format string. -+ */ -+ strtab = dtrace_dof_sect(dof, DOF_SECT_STRTAB, -+ desc->dofa_strtab); -+ if (strtab == NULL) -+ goto err; -+ -+ str = (char *)((uintptr_t)dof + -+ (uintptr_t)strtab->dofs_offset); -+ -+ for (i = desc->dofa_arg; i < strtab->dofs_size; i++) { -+ if (str[i] == '\0') -+ break; -+ } -+ -+ if (i >= strtab->dofs_size) { -+ dtrace_dof_error(dof, "bogus format string"); -+ goto err; -+ } -+ -+ if (i == desc->dofa_arg) { -+ dtrace_dof_error(dof, "empty format string"); -+ goto err; -+ } -+ -+ i -= desc->dofa_arg; -+ fmt = vmalloc(i + 1); -+ if (fmt == NULL) { -+ dtrace_dof_error(dof, "out-of-memory"); -+ goto err; -+ } -+ memcpy(fmt, &str[desc->dofa_arg], i + 1); -+ arg = (uint64_t)(uintptr_t)fmt; -+ } else { -+ if (kind == DTRACEACT_PRINTA) { -+ ASSERT(desc->dofa_strtab == DOF_SECIDX_NONE); -+ arg = 0; -+ } else -+ arg = desc->dofa_arg; -+ } -+ -+ act = dtrace_actdesc_create(kind, desc->dofa_ntuple, -+ desc->dofa_uarg, arg); -+ if (act == NULL) -+ goto err; -+ -+ if (last != NULL) -+ last->dtad_next = act; -+ else -+ first = act; -+ -+ last = act; -+ -+ if (desc->dofa_difo == DOF_SECIDX_NONE) -+ continue; -+ -+ difosec = dtrace_dof_sect(dof, DOF_SECT_DIFOHDR, -+ desc->dofa_difo); -+ if (difosec == NULL) -+ goto err; -+ -+ act->dtad_difo = dtrace_dof_difo(dof, difosec, vstate, cr); -+ -+ if (act->dtad_difo == NULL) -+ goto err; -+ } -+ -+ ASSERT(first != NULL); -+ return first; -+ -+err: -+ for (act = first; act != NULL; act = next) { -+ next = act->dtad_next; -+ dtrace_actdesc_release(act, vstate); -+ } -+ -+ return NULL; -+} -+ -+static struct dtrace_ecbdesc *dtrace_dof_ecbdesc(struct dof_hdr *dof, -+ struct dof_sec *sec, -+ struct dtrace_vstate *vstate, -+ const struct cred *cr) -+{ -+ struct dtrace_ecbdesc *ep; -+ struct dof_ecbdesc *ecb; -+ struct dtrace_probedesc *desc; -+ struct dtrace_predicate *pred = NULL; -+ -+ if (sec->dofs_size < sizeof(struct dof_ecbdesc)) { -+ dtrace_dof_error(dof, "truncated ECB description"); -+ return NULL; -+ } -+ -+ if (sec->dofs_align != sizeof(uint64_t)) { -+ dtrace_dof_error(dof, "bad alignment in ECB description"); -+ return NULL; -+ } -+ -+ ecb = (struct dof_ecbdesc *) -+ ((uintptr_t)dof + (uintptr_t)sec->dofs_offset); -+ sec = dtrace_dof_sect(dof, DOF_SECT_PROBEDESC, ecb->dofe_probes); -+ -+ if (sec == NULL) -+ return NULL; -+ -+ ep = kzalloc(sizeof(struct dtrace_ecbdesc), GFP_KERNEL); -+ if (ep == NULL) -+ return NULL; -+ ep->dted_uarg = ecb->dofe_uarg; -+ desc = &ep->dted_probe; -+ -+ if (dtrace_dof_probedesc(dof, sec, desc) == NULL) -+ goto err; -+ -+ if (ecb->dofe_pred != DOF_SECIDX_NONE) { -+ sec = dtrace_dof_sect(dof, DOF_SECT_DIFOHDR, ecb->dofe_pred); -+ if (sec == NULL) -+ goto err; -+ -+ pred = dtrace_dof_predicate(dof, sec, vstate, cr); -+ if (pred == NULL) -+ goto err; -+ -+ ep->dted_pred.dtpdd_predicate = pred; -+ } -+ -+ if (ecb->dofe_actions != DOF_SECIDX_NONE) { -+ sec = dtrace_dof_sect(dof, DOF_SECT_ACTDESC, ecb->dofe_actions); -+ if (sec == NULL) -+ goto err; -+ -+ ep->dted_action = dtrace_dof_actdesc(dof, sec, vstate, cr); -+ -+ if (ep->dted_action == NULL) -+ goto err; -+ } -+ -+ return ep; -+ -+err: -+ if (pred != NULL) -+ dtrace_predicate_release(pred, vstate); -+ kfree(ep); -+ return NULL; -+} -+ -+/* -+ * Apply the relocations from the specified 'sec' (a DOF_SECT_URELHDR) to the -+ * specified DOF. At present, this amounts to simply adding 'ubase' to the -+ * site of any user SETX relocations to account for load object base address. -+ * In the future, if we need other relocations, this function can be extended. -+ */ -+static int dtrace_dof_relocate(struct dof_hdr *dof, struct dof_sec *sec, -+ uint64_t ubase) -+{ -+ uintptr_t daddr = (uintptr_t)dof; -+ struct dof_relohdr *dofr; -+ struct dof_sec *ss, *rs, *ts; -+ struct dof_relodesc *r; -+ uint_t i, n; -+ -+ dofr = (struct dof_relohdr *)(uintptr_t) (daddr + sec->dofs_offset); -+ -+ if (sec->dofs_size < sizeof(struct dof_relohdr) || -+ sec->dofs_align != sizeof(dof_secidx_t)) { -+ dtrace_dof_error(dof, "invalid relocation header"); -+ return -1; -+ } -+ -+ ss = dtrace_dof_sect(dof, DOF_SECT_STRTAB, dofr->dofr_strtab); -+ rs = dtrace_dof_sect(dof, DOF_SECT_RELTAB, dofr->dofr_relsec); -+ ts = dtrace_dof_sect(dof, DOF_SECT_NONE, dofr->dofr_tgtsec); -+ -+ if (ss == NULL || rs == NULL || ts == NULL) -+ return -1; /* dtrace_dof_error() has been called already */ -+ -+ if (rs->dofs_entsize < sizeof(struct dof_relodesc) || -+ rs->dofs_align != sizeof(uint64_t)) { -+ dtrace_dof_error(dof, "invalid relocation section"); -+ return -1; -+ } -+ -+ r = (struct dof_relodesc *)(uintptr_t)(daddr + rs->dofs_offset); -+ /* -+ * Was: n = rs->dofs_size / rs->dofs_entsize; -+ * but on Linux we need to use a macro for the division to handle the -+ * possible case of 64-bit division on a 32-bit kernel. -+ */ -+ n = rs->dofs_size; -+ do_div(n, rs->dofs_entsize); -+ -+ for (i = 0; i < n; i++) { -+ uintptr_t taddr = daddr + ts->dofs_offset + r->dofr_offset; -+ -+ switch (r->dofr_type) { -+ case DOF_RELO_NONE: -+ break; -+ case DOF_RELO_SETX: -+ if (r->dofr_offset >= ts->dofs_size || -+ r->dofr_offset + sizeof(uint64_t) > -+ ts->dofs_size) { -+ dtrace_dof_error(dof, "bad relocation offset"); -+ return -1; -+ } -+ -+ if (!IS_ALIGNED(taddr, sizeof(uint64_t))) { -+ dtrace_dof_error(dof, "misaligned setx relo"); -+ return -1; -+ } -+ -+ /* -+ * This is a bit ugly but it is necessary for arm64, -+ * where the linking of shared libraries retains the -+ * relocation records for the .SUNW_dof section. In -+ * that case, the runtime loader already performed the -+ * relocation, so we do not have to do anything here. -+ * -+ * We check for this situation by comparing the target -+ * address against the base address (ubase). If it is -+ * larger, we assume the relocation already took place. -+ */ -+ if (*(uint64_t *)taddr > ubase) -+ dt_dbg_dof(" Relocation by runtime " \ -+ "loader: 0x%llx (base 0x%llx)\n", -+ *(uint64_t *)taddr, ubase); -+ else { -+ dt_dbg_dof(" Relocate 0x%llx + 0x%llx " \ -+ "= 0x%llx\n", -+ *(uint64_t *)taddr, ubase, -+ *(uint64_t *)taddr + ubase); -+ -+ *(uint64_t *)taddr += ubase; -+ } -+ -+ break; -+ default: -+ dtrace_dof_error(dof, "invalid relocation type"); -+ return -1; -+ } -+ -+ r = (struct dof_relodesc *)((uintptr_t)r + rs->dofs_entsize); -+ } -+ -+ return 0; -+} -+ -+/* -+ * The dof_hdr_t passed to dtrace_dof_slurp() should be a partially validated -+ * header: it should be at the front of a memory region that is at least -+ * sizeof(dof_hdr_t) in size -- and then at least dof_hdr.dofh_loadsz in -+ * size. It need not be validated in any other way. -+ */ -+int dtrace_dof_slurp(struct dof_hdr *dof, struct dtrace_vstate *vstate, -+ const struct cred *cr, struct dtrace_enabling **enabp, -+ uint64_t ubase, int noprobes) -+{ -+ uint64_t len = dof->dofh_loadsz, seclen; -+ uintptr_t daddr = (uintptr_t)dof; -+ struct dtrace_ecbdesc *ep; -+ struct dtrace_enabling *enab; -+ uint_t i; -+ -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ ASSERT(dof->dofh_loadsz >= sizeof(struct dof_hdr)); -+ -+ dt_dbg_dof(" DOF 0x%p Slurping...\n", dof); -+ -+ dt_dbg_dof(" DOF 0x%p Validating...\n", dof); -+ -+ /* -+ * Check the DOF header identification bytes. In addition to checking -+ * valid settings, we also verify that unused bits/bytes are zeroed so -+ * we can use them later without fear of regressing existing binaries. -+ */ -+ if (memcmp(&dof->dofh_ident[DOF_ID_MAG0], DOF_MAG_STRING, -+ DOF_MAG_STRLEN) != 0) { -+ dtrace_dof_error(dof, "DOF magic string mismatch"); -+ return -1; -+ } -+ -+ if (dof->dofh_ident[DOF_ID_MODEL] != DOF_MODEL_ILP32 && -+ dof->dofh_ident[DOF_ID_MODEL] != DOF_MODEL_LP64) { -+ dtrace_dof_error(dof, "DOF has invalid data model"); -+ return -1; -+ } -+ -+ if (dof->dofh_ident[DOF_ID_ENCODING] != DOF_ENCODE_NATIVE) { -+ dtrace_dof_error(dof, "DOF encoding mismatch"); -+ return -1; -+ } -+ -+ if (dof->dofh_ident[DOF_ID_VERSION] != DOF_VERSION_1 && -+ dof->dofh_ident[DOF_ID_VERSION] != DOF_VERSION_2) { -+ dtrace_dof_error(dof, "DOF version mismatch"); -+ return -1; -+ } -+ -+ if (dof->dofh_ident[DOF_ID_DIFVERS] != DIF_VERSION_2) { -+ dtrace_dof_error(dof, "DOF uses unsupported instruction set"); -+ return -1; -+ } -+ -+ if (dof->dofh_ident[DOF_ID_DIFIREG] > DIF_DIR_NREGS) { -+ dtrace_dof_error(dof, "DOF uses too many integer registers"); -+ return -1; -+ } -+ -+ if (dof->dofh_ident[DOF_ID_DIFTREG] > DIF_DTR_NREGS) { -+ dtrace_dof_error(dof, "DOF uses too many tuple registers"); -+ return -1; -+ } -+ -+ for (i = DOF_ID_PAD; i < DOF_ID_SIZE; i++) { -+ if (dof->dofh_ident[i] != 0) { -+ dtrace_dof_error(dof, "DOF has invalid ident byte set"); -+ return -1; -+ } -+ } -+ -+ if (dof->dofh_flags & ~DOF_FL_VALID) { -+ dtrace_dof_error(dof, "DOF has invalid flag bits set"); -+ return -1; -+ } -+ -+ if (dof->dofh_secsize == 0) { -+ dtrace_dof_error(dof, "zero section header size"); -+ return -1; -+ } -+ -+ /* -+ * Check that the section headers don't exceed the amount of DOF -+ * data. Note that we cast the section size and number of sections -+ * to uint64_t's to prevent possible overflow in the multiplication. -+ */ -+ seclen = (uint64_t)dof->dofh_secnum * (uint64_t)dof->dofh_secsize; -+ -+ if (dof->dofh_secoff > len || seclen > len || -+ dof->dofh_secoff + seclen > len) { -+ dtrace_dof_error(dof, "truncated section headers"); -+ return -1; -+ } -+ -+ if (!IS_ALIGNED(dof->dofh_secoff, sizeof(uint64_t))) { -+ dtrace_dof_error(dof, "misaligned section headers"); -+ return -1; -+ } -+ -+ if (!IS_ALIGNED(dof->dofh_secsize, sizeof(uint64_t))) { -+ dtrace_dof_error(dof, "misaligned section size"); -+ return -1; -+ } -+ -+ /* -+ * Take an initial pass through the section headers to be sure that -+ * the headers don't have stray offsets. If the 'noprobes' flag is -+ * set, do not permit sections relating to providers, probes, or args. -+ */ -+ dt_dbg_dof(" DOF 0x%p Checking section offsets...\n", dof); -+ -+ for (i = 0; i < dof->dofh_secnum; i++) { -+ struct dof_sec *sec; -+ -+ sec = (struct dof_sec *)(daddr + (uintptr_t)dof->dofh_secoff + -+ i * dof->dofh_secsize); -+ -+ if (noprobes) { -+ switch (sec->dofs_type) { -+ case DOF_SECT_PROVIDER: -+ case DOF_SECT_PROBES: -+ case DOF_SECT_PRARGS: -+ case DOF_SECT_PROFFS: -+ dtrace_dof_error( -+ dof, "illegal sections for enabling"); -+ return -1; -+ } -+ } -+ -+ if (DOF_SEC_ISLOADABLE(sec->dofs_type) && -+ !(sec->dofs_flags & DOF_SECF_LOAD)) { -+ dtrace_dof_error( -+ dof, "loadable section with load flag unset"); -+ return -1; -+ } -+ -+ /* -+ * Just ignore non-loadable sections. -+ */ -+ if (!(sec->dofs_flags & DOF_SECF_LOAD)) -+ continue; -+ -+ if (sec->dofs_align & (sec->dofs_align - 1)) { -+ dtrace_dof_error(dof, "bad section alignment"); -+ return -1; -+ } -+ -+ if (sec->dofs_offset & (sec->dofs_align - 1)) { -+ dtrace_dof_error(dof, "misaligned section"); -+ return -1; -+ } -+ -+ if (sec->dofs_offset > len || sec->dofs_size > len || -+ sec->dofs_offset + sec->dofs_size > len) { -+ dtrace_dof_error(dof, "corrupt section header"); -+ return -1; -+ } -+ -+ if (sec->dofs_type == DOF_SECT_STRTAB && *((char *)daddr + -+ sec->dofs_offset + sec->dofs_size - 1) != '\0') { -+ dtrace_dof_error(dof, "non-terminating string table"); -+ return -1; -+ } -+ } -+ -+ /* -+ * Take a second pass through the sections and locate and perform any -+ * relocations that are present. We do this after the first pass to -+ * be sure that all sections have had their headers validated. -+ */ -+ dt_dbg_dof(" DOF 0x%p Performing relocations...\n", dof); -+ -+ for (i = 0; i < dof->dofh_secnum; i++) { -+ struct dof_sec *sec; -+ -+ sec = (struct dof_sec *)(daddr + (uintptr_t)dof->dofh_secoff + -+ i * dof->dofh_secsize); -+ -+ /* -+ * Skip sections that are not loadable. -+ */ -+ if (!(sec->dofs_flags & DOF_SECF_LOAD)) -+ continue; -+ -+ switch (sec->dofs_type) { -+ case DOF_SECT_URELHDR: -+ if (dtrace_dof_relocate(dof, sec, ubase) != 0) -+ return -1; -+ break; -+ } -+ } -+ -+ dt_dbg_dof(" DOF 0x%p Processing enablings...\n", dof); -+ -+ enab = *enabp; -+ if (enab == NULL) -+ enab = *enabp = dtrace_enabling_create(vstate); -+ -+ if (enab == NULL) { -+ dt_dbg_dof(" DOF 0x%p Done slurping - no enablings\n", dof); -+ return -1; -+ } -+ -+ for (i = 0; i < dof->dofh_secnum; i++) { -+ struct dof_sec *sec; -+ -+ sec = (struct dof_sec *)(daddr + (uintptr_t)dof->dofh_secoff + -+ i * dof->dofh_secsize); -+ -+ if (sec->dofs_type != DOF_SECT_ECBDESC) -+ continue; -+ -+ ep = dtrace_dof_ecbdesc(dof, sec, vstate, cr); -+ if (ep == NULL) { -+ dt_dbg_dof(" DOF 0x%p Done slurping - ECB problem\n", -+ dof); -+ dtrace_enabling_destroy(enab); -+ *enabp = NULL; -+ return -1; -+ } -+ -+ dtrace_enabling_add(enab, ep); -+ } -+ -+ dt_dbg_dof(" DOF 0x%p Enablings processed\n", dof); -+ dt_dbg_dof(" DOF 0x%p Done slurping\n", dof); -+ -+ return 0; -+} -+ -+/* -+ * Process DOF for any options. This should be called after the DOF has been -+ * processed by dtrace_dof_slurp(). -+ */ -+int dtrace_dof_options(struct dof_hdr *dof, struct dtrace_state *state) -+{ -+ int i, rval; -+ uint32_t entsize; -+ size_t offs; -+ struct dof_optdesc *desc; -+ -+ for (i = 0; i < dof->dofh_secnum; i++) { -+ struct dof_sec *sec; -+ -+ sec = (struct dof_sec *)((uintptr_t)dof + -+ (uintptr_t)dof->dofh_secoff + -+ i * dof->dofh_secsize); -+ -+ if (sec->dofs_type != DOF_SECT_OPTDESC) -+ continue; -+ -+ if (sec->dofs_align != sizeof(uint64_t)) { -+ dtrace_dof_error( -+ dof, "bad alignment in option description"); -+ return -EINVAL; -+ } -+ -+ entsize = sec->dofs_entsize; -+ if (entsize == 0) { -+ dtrace_dof_error(dof, "zeroed option entry size"); -+ return -EINVAL; -+ } -+ -+ if (entsize < sizeof(struct dof_optdesc)) { -+ dtrace_dof_error(dof, "bad option entry size"); -+ return -EINVAL; -+ } -+ -+ for (offs = 0; offs < sec->dofs_size; offs += entsize) { -+ desc = (struct dof_optdesc *)((uintptr_t)dof + -+ (uintptr_t)sec->dofs_offset + -+ offs); -+ -+ if (desc->dofo_strtab != DOF_SECIDX_NONE) { -+ dtrace_dof_error( -+ dof, "non-zero option string"); -+ return -EINVAL; -+ } -+ -+ if (desc->dofo_value == DTRACEOPT_UNSET) { -+ dtrace_dof_error(dof, "unset option"); -+ return -EINVAL; -+ } -+ -+ rval = dtrace_state_option(state, desc->dofo_option, -+ desc->dofo_value); -+ if (rval != 0) { -+ dtrace_dof_error(dof, "rejected option"); -+ return rval; -+ } -+ } -+ } -+ -+ return 0; -+} -+ -+static struct dtrace_helpers *dtrace_helpers_create(struct task_struct *curr) -+{ -+ struct dtrace_helpers *dth; -+ -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ -+ if (curr->dt_task == NULL) -+ return NULL; -+ -+ ASSERT(curr->dt_task->dt_helpers == NULL); -+ -+ dth = kzalloc(sizeof(struct dtrace_helpers), GFP_KERNEL); -+ if (dth == NULL) -+ return NULL; -+ -+ dth->dthps_actions = vzalloc(sizeof(struct dtrace_helper_action *) * -+ DTRACE_NHELPER_ACTIONS); -+ if (dth->dthps_actions == NULL) { -+ kfree(dth); -+ return NULL; -+ } -+ -+ curr->dt_task->dt_helpers = dth; -+ dtrace_helpers++; -+ -+ dt_dbg_dof(" Helpers allocated for task 0x%p (%d system-wide)\n", -+ curr, dtrace_helpers); -+ -+ return dth; -+} -+ -+static int dtrace_helper_validate(struct dtrace_helper_action *helper) -+{ -+ int err = 0, i; -+ struct dtrace_difo *dp; -+ -+ dp = helper->dtha_predicate; -+ if (dp != NULL) -+ err += dtrace_difo_validate_helper(dp); -+ -+ for (i = 0; i < helper->dtha_nactions; i++) -+ err += dtrace_difo_validate_helper(helper->dtha_actions[i]); -+ -+ return (err == 0); -+} -+ -+static int dtrace_helper_provider_validate(struct dof_hdr *dof, -+ struct dof_sec *sec) -+{ -+ uintptr_t daddr = (uintptr_t)dof; -+ struct dof_sec *str_sec, *prb_sec, *arg_sec, *off_sec, -+ *enoff_sec; -+ struct dof_provider *prov; -+ struct dof_probe *prb; -+ uint8_t *arg; -+ char *strtab, *typestr; -+ dof_stridx_t typeidx; -+ size_t typesz; -+ uint_t nprobes, j, k; -+ -+ ASSERT(sec->dofs_type == DOF_SECT_PROVIDER); -+ -+ if (sec->dofs_offset & (sizeof(uint_t) - 1)) { -+ dtrace_dof_error(dof, "misaligned section offset"); -+ return -1; -+ } -+ -+ /* -+ * The section needs to be large enough to contain the DOF provider -+ * structure appropriate for the given version. -+ */ -+ if (sec->dofs_size < -+ ((dof->dofh_ident[DOF_ID_VERSION] == DOF_VERSION_1) -+ ? offsetof(struct dof_provider, dofpv_prenoffs) -+ : sizeof(struct dof_provider))) { -+ dtrace_dof_error(dof, "provider section too small"); -+ return -1; -+ } -+ -+ prov = (struct dof_provider *)(uintptr_t)(daddr + sec->dofs_offset); -+ str_sec = dtrace_dof_sect(dof, DOF_SECT_STRTAB, prov->dofpv_strtab); -+ prb_sec = dtrace_dof_sect(dof, DOF_SECT_PROBES, prov->dofpv_probes); -+ arg_sec = dtrace_dof_sect(dof, DOF_SECT_PRARGS, prov->dofpv_prargs); -+ off_sec = dtrace_dof_sect(dof, DOF_SECT_PROFFS, prov->dofpv_proffs); -+ -+ if (str_sec == NULL || prb_sec == NULL || -+ arg_sec == NULL || off_sec == NULL) -+ return -1; -+ -+ enoff_sec = NULL; -+ -+ if (dof->dofh_ident[DOF_ID_VERSION] != DOF_VERSION_1 && -+ prov->dofpv_prenoffs != DOF_SECT_NONE) { -+ enoff_sec = dtrace_dof_sect(dof, DOF_SECT_PRENOFFS, -+ prov->dofpv_prenoffs); -+ -+ if (enoff_sec == NULL) -+ return -1; -+ } -+ -+ strtab = (char *)(uintptr_t)(daddr + str_sec->dofs_offset); -+ -+ if (prov->dofpv_name >= str_sec->dofs_size || -+ strlen(strtab + prov->dofpv_name) >= DTRACE_PROVNAMELEN) { -+ dtrace_dof_error(dof, "invalid provider name"); -+ return -1; -+ } -+ -+ if (prb_sec->dofs_entsize == 0 || -+ prb_sec->dofs_entsize > prb_sec->dofs_size) { -+ dtrace_dof_error(dof, "invalid entry size"); -+ return -1; -+ } -+ -+ if (prb_sec->dofs_entsize & (sizeof(uintptr_t) - 1)) { -+ dtrace_dof_error(dof, "misaligned entry size"); -+ return -1; -+ } -+ -+ if (off_sec->dofs_entsize != sizeof(uint32_t)) { -+ dtrace_dof_error(dof, "invalid entry size"); -+ return -1; -+ } -+ -+ if (off_sec->dofs_offset & (sizeof(uint32_t) - 1)) { -+ dtrace_dof_error(dof, "misaligned section offset"); -+ return -1; -+ } -+ -+ if (arg_sec->dofs_entsize != sizeof(uint8_t)) { -+ dtrace_dof_error(dof, "invalid entry size"); -+ return -1; -+ } -+ -+ arg = (uint8_t *)(uintptr_t)(daddr + arg_sec->dofs_offset); -+ nprobes = prb_sec->dofs_size / prb_sec->dofs_entsize; -+ -+ dt_dbg_dof(" DOF 0x%p %s::: with %d probes\n", -+ dof, strtab + prov->dofpv_name, nprobes); -+ -+ /* -+ * Take a pass through the probes to check for errors. -+ */ -+ for (j = 0; j < nprobes; j++) { -+ prb = (struct dof_probe *)(uintptr_t) -+ (daddr + prb_sec->dofs_offset + -+ j * prb_sec->dofs_entsize); -+ -+ if (prb->dofpr_func >= str_sec->dofs_size) { -+ dtrace_dof_error(dof, "invalid function name"); -+ return -1; -+ } -+ -+ if (strlen(strtab + prb->dofpr_func) >= DTRACE_FUNCNAMELEN) { -+ dtrace_dof_error(dof, "function name too long"); -+ return -1; -+ } -+ -+ if (prb->dofpr_name >= str_sec->dofs_size || -+ strlen(strtab + prb->dofpr_name) >= DTRACE_NAMELEN) { -+ dtrace_dof_error(dof, "invalid probe name"); -+ return -1; -+ } -+ -+ /* -+ * The offset count must not wrap the index, and the offsets -+ * must also not overflow the section's data. -+ */ -+ if (prb->dofpr_offidx + prb->dofpr_noffs < prb->dofpr_offidx || -+ (prb->dofpr_offidx + prb->dofpr_noffs) * -+ off_sec->dofs_entsize > off_sec->dofs_size) { -+ dtrace_dof_error(dof, "invalid probe offset"); -+ return -1; -+ } -+ -+ if (dof->dofh_ident[DOF_ID_VERSION] != DOF_VERSION_1) { -+ /* -+ * If there's no is-enabled offset section, make sure -+ * there aren't any is-enabled offsets. Otherwise -+ * perform the same checks as for probe offsets -+ * (immediately above). -+ */ -+ if (enoff_sec == NULL) { -+ if (prb->dofpr_enoffidx != 0 || -+ prb->dofpr_nenoffs != 0) { -+ dtrace_dof_error(dof, -+ "is-enabled offsets " -+ "with null section"); -+ return -1; -+ } -+ } else if (prb->dofpr_enoffidx + prb->dofpr_nenoffs < -+ prb->dofpr_enoffidx || -+ (prb->dofpr_enoffidx + prb->dofpr_nenoffs) * -+ enoff_sec->dofs_entsize > -+ enoff_sec->dofs_size) { -+ dtrace_dof_error(dof, "invalid is-enabled " -+ "offset"); -+ return -1; -+ } -+ -+ if (prb->dofpr_noffs + prb->dofpr_nenoffs == 0) { -+ dtrace_dof_error(dof, "zero probe and " -+ "is-enabled offsets"); -+ return -1; -+ } -+ } else if (prb->dofpr_noffs == 0) { -+ dtrace_dof_error(dof, "zero probe offsets"); -+ return -1; -+ } -+ -+ if (prb->dofpr_argidx + prb->dofpr_xargc < prb->dofpr_argidx || -+ (prb->dofpr_argidx + prb->dofpr_xargc) * -+ arg_sec->dofs_entsize > arg_sec->dofs_size) { -+ dtrace_dof_error(dof, "invalid args"); -+ return -1; -+ } -+ -+ typeidx = prb->dofpr_nargv; -+ typestr = strtab + prb->dofpr_nargv; -+ for (k = 0; k < prb->dofpr_nargc; k++) { -+ if (typeidx >= str_sec->dofs_size) { -+ dtrace_dof_error(dof, "bad native argument " -+ "type"); -+ return -1; -+ } -+ -+ typesz = strlen(typestr) + 1; -+ if (typesz > DTRACE_ARGTYPELEN) { -+ dtrace_dof_error(dof, "native argument type " -+ "too long"); -+ return -1; -+ } -+ -+ typeidx += typesz; -+ typestr += typesz; -+ } -+ -+ typeidx = prb->dofpr_xargv; -+ typestr = strtab + prb->dofpr_xargv; -+ for (k = 0; k < prb->dofpr_xargc; k++) { -+ if (arg[prb->dofpr_argidx + k] > prb->dofpr_nargc) { -+ dtrace_dof_error(dof, "bad native argument " -+ "index"); -+ return -1; -+ } -+ -+ if (typeidx >= str_sec->dofs_size) { -+ dtrace_dof_error(dof, "bad translated " -+ "argument type"); -+ return -1; -+ } -+ -+ typesz = strlen(typestr) + 1; -+ if (typesz > DTRACE_ARGTYPELEN) { -+ dtrace_dof_error(dof, "translated argument " -+ "type too long"); -+ return -1; -+ } -+ -+ typeidx += typesz; -+ typestr += typesz; -+ } -+ -+ dt_dbg_dof(" Probe %d %s:%s:%s:%s with %d offsets, " -+ "%d is-enabled offsets\n", j, -+ strtab + prov->dofpv_name, "", -+ strtab + prb->dofpr_func, strtab + prb->dofpr_name, -+ prb->dofpr_noffs, prb->dofpr_nenoffs); -+ } -+ -+ return 0; -+} -+ -+static void dtrace_helper_action_destroy(struct dtrace_helper_action *helper, -+ struct dtrace_vstate *vstate) -+{ -+ int i; -+ -+ if (helper->dtha_predicate != NULL) -+ dtrace_difo_release(helper->dtha_predicate, vstate); -+ -+ for (i = 0; i < helper->dtha_nactions; i++) { -+ ASSERT(helper->dtha_actions[i] != NULL); -+ dtrace_difo_release(helper->dtha_actions[i], vstate); -+ } -+ -+ vfree(helper->dtha_actions); -+ kfree(helper); -+} -+ -+static int dtrace_helper_action_add(int which, struct dtrace_ecbdesc *ep) -+{ -+ struct dtrace_helpers *dth; -+ struct dtrace_helper_action *helper, *last; -+ struct dtrace_actdesc *act; -+ struct dtrace_vstate *vstate; -+ struct dtrace_predicate *pred; -+ int count = 0, nactions = 0, i; -+ -+ if (which < 0 || which >= DTRACE_NHELPER_ACTIONS) -+ return -EINVAL; -+ -+ if (current->dt_task == NULL) -+ return -ENOMEM; -+ -+ dth = current->dt_task->dt_helpers; -+ last = dth->dthps_actions[which]; -+ vstate = &dth->dthps_vstate; -+ -+ for (count = 0; last != NULL; last = last->dtha_next) { -+ count++; -+ if (last->dtha_next == NULL) -+ break; -+ } -+ -+ /* -+ * If we already have dtrace_helper_actions_max helper actions for this -+ * helper action type, we'll refuse to add a new one. -+ */ -+ if (count >= dtrace_helper_actions_max) -+ return -ENOSPC; -+ -+ helper = kzalloc(sizeof(struct dtrace_helper_action), GFP_KERNEL); -+ if (helper == NULL) -+ return -ENOMEM; -+ -+ helper->dtha_generation = dth->dthps_generation; -+ -+ pred = ep->dted_pred.dtpdd_predicate; -+ if (pred != NULL) { -+ ASSERT(pred->dtp_difo != NULL); -+ dtrace_difo_hold(pred->dtp_difo); -+ helper->dtha_predicate = pred->dtp_difo; -+ } -+ -+ for (act = ep->dted_action; act != NULL; act = act->dtad_next) { -+ if (act->dtad_kind != DTRACEACT_DIFEXPR) -+ goto err; -+ -+ if (act->dtad_difo == NULL) -+ goto err; -+ -+ nactions++; -+ } -+ -+ helper->dtha_actions = vzalloc(sizeof(struct dtrace_difo *) * -+ (helper->dtha_nactions = nactions)); -+ if (helper->dtha_actions == NULL) -+ goto err; -+ -+ for (act = ep->dted_action, i = 0; act != NULL; act = act->dtad_next) { -+ dtrace_difo_hold(act->dtad_difo); -+ helper->dtha_actions[i++] = act->dtad_difo; -+ } -+ -+ if (!dtrace_helper_validate(helper)) -+ goto err; -+ -+ if (last == NULL) -+ dth->dthps_actions[which] = helper; -+ else -+ last->dtha_next = helper; -+ -+ if (vstate->dtvs_nlocals > dtrace_helptrace_nlocals) { -+ dtrace_helptrace_nlocals = vstate->dtvs_nlocals; -+ dtrace_helptrace_next = 0; -+ } -+ -+ return 0; -+ -+err: -+ dtrace_helper_action_destroy(helper, vstate); -+ if (helper->dtha_actions != NULL) -+ vfree(helper->dtha_actions); -+ else -+ return -ENOMEM; -+ -+ return -EINVAL; -+} -+ -+static int dtrace_helper_provider_add(struct dof_helper *dofhp, int gen) -+{ -+ struct dtrace_helpers *dth; -+ struct dtrace_helper_provider *hprov, **tmp_provs; -+ uint_t tmp_maxprovs, i; -+ -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ -+ if (current->dt_task == NULL) -+ return -ENOMEM; -+ -+ dth = current->dt_task->dt_helpers; -+ ASSERT(dth != NULL); -+ -+ /* -+ * If we already have dtrace_helper_providers_max helper providers, -+ * we're refuse to add a new one. -+ */ -+ if (dth->dthps_nprovs >= dtrace_helper_providers_max) -+ return -ENOSPC; -+ -+ /* -+ * Check to make sure this isn't a duplicate. -+ */ -+ for (i = 0; i < dth->dthps_nprovs; i++) { -+ if (dofhp->dofhp_addr == -+ dth->dthps_provs[i]->dthp_prov.dofhp_addr) -+ return -EALREADY; -+ } -+ -+ hprov = kzalloc(sizeof(struct dtrace_helper_provider), GFP_KERNEL); -+ if (hprov == NULL) -+ return -ENOMEM; -+ hprov->dthp_prov = *dofhp; -+ hprov->dthp_ref = 1; -+ hprov->dthp_generation = gen; -+ -+ /* -+ * Allocate a bigger table for helper providers if it's already full. -+ */ -+ if (dth->dthps_maxprovs == dth->dthps_nprovs) { -+ tmp_maxprovs = dth->dthps_maxprovs; -+ tmp_provs = dth->dthps_provs; -+ -+ if (dth->dthps_maxprovs == 0) -+ dth->dthps_maxprovs = 2; -+ else -+ dth->dthps_maxprovs *= 2; -+ -+ if (dth->dthps_maxprovs > dtrace_helper_providers_max) -+ dth->dthps_maxprovs = dtrace_helper_providers_max; -+ -+ ASSERT(tmp_maxprovs < dth->dthps_maxprovs); -+ -+ dth->dthps_provs = -+ vzalloc(dth->dthps_maxprovs * -+ sizeof(struct dtrace_helper_provider *)); -+ -+ if (dth->dthps_provs == NULL) { -+ kfree(hprov); -+ return -ENOMEM; -+ } -+ -+ if (tmp_provs != NULL) { -+ memcpy(dth->dthps_provs, tmp_provs, -+ tmp_maxprovs * -+ sizeof(struct dtrace_helper_provider *)); -+ vfree(tmp_provs); -+ } -+ } -+ -+ dth->dthps_provs[dth->dthps_nprovs] = hprov; -+ dth->dthps_nprovs++; -+ -+ return 0; -+} -+ -+static void dtrace_helper_provider_destroy(struct dtrace_helper_provider *hprov) -+{ -+ mutex_lock(&dtrace_lock); -+ -+ if (--hprov->dthp_ref == 0) { -+ struct dof_hdr *dof; -+ -+ mutex_unlock(&dtrace_lock); -+ -+ dof = (struct dof_hdr *)(uintptr_t)hprov->dthp_prov.dofhp_dof; -+ dtrace_dof_destroy(dof); -+ kfree(hprov); -+ } else -+ mutex_unlock(&dtrace_lock); -+} -+ -+static void dtrace_dofattr2attr(struct dtrace_attribute *attr, -+ const dof_attr_t dofattr) -+{ -+ attr->dtat_name = DOF_ATTR_NAME(dofattr); -+ attr->dtat_data = DOF_ATTR_DATA(dofattr); -+ attr->dtat_class = DOF_ATTR_CLASS(dofattr); -+} -+ -+static void dtrace_dofprov2hprov(struct dtrace_helper_provdesc *hprov, -+ const struct dof_provider *dofprov, -+ char *strtab) -+{ -+ hprov->dthpv_provname = strtab + dofprov->dofpv_name; -+ dtrace_dofattr2attr(&hprov->dthpv_pattr.dtpa_provider, -+ dofprov->dofpv_provattr); -+ dtrace_dofattr2attr(&hprov->dthpv_pattr.dtpa_mod, -+ dofprov->dofpv_modattr); -+ dtrace_dofattr2attr(&hprov->dthpv_pattr.dtpa_func, -+ dofprov->dofpv_funcattr); -+ dtrace_dofattr2attr(&hprov->dthpv_pattr.dtpa_name, -+ dofprov->dofpv_nameattr); -+ dtrace_dofattr2attr(&hprov->dthpv_pattr.dtpa_args, -+ dofprov->dofpv_argsattr); -+} -+ -+static void dtrace_helper_provider_remove_one(struct dof_helper *dhp, -+ struct dof_sec *sec, pid_t pid) -+{ -+ uintptr_t daddr = (uintptr_t)dhp->dofhp_dof; -+ struct dof_hdr *dof = (struct dof_hdr *)daddr; -+ struct dof_sec *str_sec; -+ struct dof_provider *prov; -+ char *strtab; -+ struct dtrace_helper_provdesc dhpv; -+ struct dtrace_meta *meta = dtrace_meta_pid; -+ struct dtrace_mops *mops = &meta->dtm_mops; -+ -+ prov = (struct dof_provider *)(uintptr_t)(daddr + sec->dofs_offset); -+ str_sec = (struct dof_sec *)(uintptr_t)(daddr + dof->dofh_secoff + -+ prov->dofpv_strtab * -+ dof->dofh_secsize); -+ -+ strtab = (char *)(uintptr_t)(daddr + str_sec->dofs_offset); -+ -+ /* -+ * Create the provider. -+ */ -+ dtrace_dofprov2hprov(&dhpv, prov, strtab); -+ -+ dt_dbg_dof(" Removing provider %s for PID %d\n", -+ dhpv.dthpv_provname, pid); -+ -+ mops->dtms_remove_pid(meta->dtm_arg, &dhpv, pid); -+ -+ meta->dtm_count--; -+} -+ -+static void dtrace_helper_provider_remove(struct dof_helper *dhp, pid_t pid) -+{ -+ uintptr_t daddr = (uintptr_t)dhp->dofhp_dof; -+ struct dof_hdr *dof = (struct dof_hdr *)daddr; -+ int i; -+ -+ ASSERT(MUTEX_HELD(&dtrace_meta_lock)); -+ -+ for (i = 0; i < dof->dofh_secnum; i++) { -+ struct dof_sec *sec; -+ -+ sec = (struct dof_sec *)(uintptr_t) (daddr + dof->dofh_secoff + -+ i * dof->dofh_secsize); -+ -+ if (sec->dofs_type != DOF_SECT_PROVIDER) -+ continue; -+ -+ dtrace_helper_provider_remove_one(dhp, sec, pid); -+ } -+} -+ -+static void dtrace_helper_provide_one(struct dof_helper *dhp, -+ struct dof_sec *sec, -+ pid_t pid) -+{ -+ uintptr_t daddr = (uintptr_t)dhp->dofhp_dof; -+ uint32_t *off, *enoff; -+ uint8_t *arg; -+ char *strtab; -+ uint_t i, nprobes; -+ void *parg; -+ -+ struct dof_hdr *dof = (struct dof_hdr *)daddr; -+ struct dof_sec *str_sec, *prb_sec, *arg_sec, *off_sec, -+ *enoff_sec; -+ struct dof_provider *prov; -+ struct dof_probe *probe; -+ struct dtrace_helper_provdesc dhpv; -+ struct dtrace_helper_probedesc dhpb; -+ struct dtrace_meta *meta = dtrace_meta_pid; -+ struct dtrace_mops *mops = &meta->dtm_mops; -+ -+ prov = (struct dof_provider *)(uintptr_t)(daddr + sec->dofs_offset); -+ str_sec = (struct dof_sec *)(uintptr_t)(daddr + dof->dofh_secoff + -+ prov->dofpv_strtab * -+ dof->dofh_secsize); -+ prb_sec = (struct dof_sec *)(uintptr_t)(daddr + dof->dofh_secoff + -+ prov->dofpv_probes * -+ dof->dofh_secsize); -+ arg_sec = (struct dof_sec *)(uintptr_t)(daddr + dof->dofh_secoff + -+ prov->dofpv_prargs * -+ dof->dofh_secsize); -+ off_sec = (struct dof_sec *)(uintptr_t)(daddr + dof->dofh_secoff + -+ prov->dofpv_proffs * -+ dof->dofh_secsize); -+ -+ strtab = (char *)(uintptr_t)(daddr + str_sec->dofs_offset); -+ off = (uint32_t *)(uintptr_t)(daddr + off_sec->dofs_offset); -+ arg = (uint8_t *)(uintptr_t)(daddr + arg_sec->dofs_offset); -+ enoff = NULL; -+ -+ /* -+ * See dtrace_helper_provider_validate(). -+ */ -+ if (dof->dofh_ident[DOF_ID_VERSION] != DOF_VERSION_1 && -+ prov->dofpv_prenoffs != DOF_SECT_NONE) { -+ enoff_sec = (struct dof_sec *)(uintptr_t) -+ (daddr + dof->dofh_secoff + -+ prov->dofpv_prenoffs * dof->dofh_secsize); -+ enoff = (uint32_t *)(uintptr_t) -+ (daddr + enoff_sec->dofs_offset); -+ } -+ -+ nprobes = prb_sec->dofs_size / prb_sec->dofs_entsize; -+ -+ /* -+ * Create the provider. -+ */ -+ dtrace_dofprov2hprov(&dhpv, prov, strtab); -+ -+ dt_dbg_dof(" Creating provider %s for PID %d\n", -+ strtab + prov->dofpv_name, pid); -+ -+ /* -+ * This used to just 'return;' when parg is NULL, but that causes the -+ * cleanup code (dtrace_helper_provider_remove[_one]) to make a call -+ * to dtms_remove_pid() for a provider that never got created. -+ * -+ * If we fail to provide this provider, mark it as something to ignore, -+ * so we don't try to process it during cleanup. -+ */ -+ parg = mops->dtms_provide_pid(meta->dtm_arg, &dhpv, pid); -+ if (parg == NULL) { -+ sec->dofs_type = DOF_SECT_NONE; -+ return; -+ } -+ -+ meta->dtm_count++; -+ -+ /* -+ * Create the probes. -+ */ -+ for (i = 0; i < nprobes; i++) { -+ probe = (struct dof_probe *)(uintptr_t)(daddr + -+ prb_sec->dofs_offset + -+ i * prb_sec->dofs_entsize); -+ -+ dhpb.dthpb_mod = dhp->dofhp_mod; -+ dhpb.dthpb_func = strtab + probe->dofpr_func; -+ dhpb.dthpb_name = strtab + probe->dofpr_name; -+ dhpb.dthpb_base = probe->dofpr_addr; -+ dhpb.dthpb_offs = off + probe->dofpr_offidx; -+ dhpb.dthpb_noffs = probe->dofpr_noffs; -+ -+ if (enoff != NULL) { -+ dhpb.dthpb_enoffs = enoff + probe->dofpr_enoffidx; -+ dhpb.dthpb_nenoffs = probe->dofpr_nenoffs; -+ } else { -+ dhpb.dthpb_enoffs = NULL; -+ dhpb.dthpb_nenoffs = 0; -+ } -+ -+ dhpb.dthpb_args = arg + probe->dofpr_argidx; -+ dhpb.dthpb_nargc = probe->dofpr_nargc; -+ dhpb.dthpb_xargc = probe->dofpr_xargc; -+ dhpb.dthpb_ntypes = strtab + probe->dofpr_nargv; -+ dhpb.dthpb_xtypes = strtab + probe->dofpr_xargv; -+ -+ dt_dbg_dof(" Creating probe %s:%s:%s:%s\n", -+ strtab + prov->dofpv_name, "", dhpb.dthpb_func, -+ dhpb.dthpb_name); -+ -+ mops->dtms_create_probe(meta->dtm_arg, parg, &dhpb); -+ } -+} -+ -+void dtrace_helper_provide(struct dof_helper *dhp, pid_t pid) -+{ -+ uintptr_t daddr = (uintptr_t)dhp->dofhp_dof; -+ struct dof_hdr *dof = (struct dof_hdr *)daddr; -+ int i; -+ -+ ASSERT(MUTEX_HELD(&dtrace_meta_lock)); -+ -+ for (i = 0; i < dof->dofh_secnum; i++) { -+ struct dof_sec *sec; -+ -+ sec = (struct dof_sec *)(uintptr_t) (daddr + dof->dofh_secoff + -+ i * dof->dofh_secsize); -+ -+ if (sec->dofs_type != DOF_SECT_PROVIDER) -+ continue; -+ -+ dtrace_helper_provide_one(dhp, sec, pid); -+ } -+ -+ /* -+ * We may have just created probes, so we must now rematch against any -+ * retained enablings. Note that this call will acquire both cpu_lock -+ * and dtrace_lock; the fact that we are holding dtrace_meta_lock now -+ * is what defines the ordering with respect to these three locks. -+ */ -+ dt_dbg_dof(" Re-matching against any retained enablings\n"); -+ dtrace_enabling_matchall(); -+} -+ -+static void dtrace_helper_provider_register(struct task_struct *tsk, -+ struct dtrace_helpers *dth, -+ struct dof_helper *dofhp) -+{ -+ ASSERT(!MUTEX_HELD(&dtrace_lock)); -+ -+ mutex_lock(&dtrace_meta_lock); -+ mutex_lock(&dtrace_lock); -+ -+ if (!dtrace_attached() || dtrace_meta_pid == NULL) { -+ dt_dbg_dof(" No meta provider registered -- deferred\n"); -+ -+ /* -+ * If the dtrace module is loaded but not attached, or if there -+ * isn't a meta provider registered to deal with these provider -+ * descriptions, we need to postpone creating the actual -+ * providers until later. -+ */ -+ if (dth->dthps_next == NULL && dth->dthps_prev == NULL && -+ dtrace_deferred_pid != dth) { -+ dth->dthps_deferred = 1; -+ dth->dthps_pid = tsk->pid; -+ dth->dthps_next = dtrace_deferred_pid; -+ dth->dthps_prev = NULL; -+ if (dtrace_deferred_pid != NULL) -+ dtrace_deferred_pid->dthps_prev = dth; -+ dtrace_deferred_pid = dth; -+ } -+ -+ mutex_unlock(&dtrace_lock); -+ } else if (dofhp != NULL) { -+ /* -+ * If the dtrace module is loaded and we have a particular -+ * helper provider description, pass that off to the meta -+ * provider. -+ */ -+ mutex_unlock(&dtrace_lock); -+ -+ dtrace_helper_provide(dofhp, tsk->pid); -+ } else { -+ /* -+ * Otherwise, just pass all the helper provider descriptions -+ * off to the meta provider. -+ */ -+ int i; -+ -+ mutex_unlock(&dtrace_lock); -+ -+ for (i = 0; i < dth->dthps_nprovs; i++) { -+ dtrace_helper_provide(&dth->dthps_provs[i]->dthp_prov, -+ tsk->pid); -+ } -+ } -+ -+ mutex_unlock(&dtrace_meta_lock); -+} -+ -+int dtrace_helper_slurp(struct dof_hdr *dof, struct dof_helper *dhp) -+{ -+ struct dtrace_helpers *dth; -+ struct dtrace_vstate *vstate; -+ struct dtrace_enabling *enab = NULL; -+ int i, gen, rv; -+ int nhelpers = 0, nprovs = 0, destroy = 1; -+ uintptr_t daddr = (uintptr_t)dof; -+ -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ -+ if (current->dt_task == NULL) -+ return -1; -+ -+ dth = current->dt_task->dt_helpers; -+ if (dth == NULL) -+ dth = dtrace_helpers_create(current); -+ -+ if (dth == NULL) { -+ dtrace_dof_destroy(dof); -+ return -1; -+ } -+ -+ dt_dbg_dof("DOF 0x%p from helper {'%s', %p, %p}...\n", -+ dof, dhp ? dhp->dofhp_mod : "<none>", -+ dhp ? (void *)(dhp->dofhp_addr) : NULL, -+ dhp ? (void *)(dhp->dofhp_dof) : NULL); -+ -+ vstate = &dth->dthps_vstate; -+ -+ rv = dtrace_dof_slurp(dof, vstate, NULL, &enab, -+ dhp != NULL ? dhp->dofhp_addr : 0, FALSE); -+ if (rv != 0) { -+ dtrace_dof_destroy(dof); -+ return rv; -+ } -+ -+ /* -+ * Look for helper providers and validate their descriptions. -+ */ -+ if (dhp != NULL) { -+ dt_dbg_dof(" DOF 0x%p Validating providers...\n", dof); -+ -+ for (i = 0; i < dof->dofh_secnum; i++) { -+ struct dof_sec *sec; -+ -+ sec = (struct dof_sec *)(uintptr_t) -+ (daddr + dof->dofh_secoff + -+ i * dof->dofh_secsize); -+ -+ if (sec->dofs_type != DOF_SECT_PROVIDER) -+ continue; -+ -+ if (dtrace_helper_provider_validate(dof, sec) != 0) { -+ dtrace_enabling_destroy(enab); -+ dtrace_dof_destroy(dof); -+ return -1; -+ } -+ -+ nprovs++; -+ } -+ } -+ -+ /* -+ * Now we need to walk through the ECB descriptions in the enabling. -+ */ -+ for (i = 0; i < enab->dten_ndesc; i++) { -+ struct dtrace_ecbdesc *ep = enab->dten_desc[i]; -+ struct dtrace_probedesc *desc = &ep->dted_probe; -+ -+ dt_dbg_dof(" ECB Desc %s:%s:%s:%s\n", -+ desc->dtpd_provider, desc->dtpd_mod, -+ desc->dtpd_func, desc->dtpd_name); -+ if (strcmp(desc->dtpd_provider, "dtrace") != 0) -+ continue; -+ -+ if (strcmp(desc->dtpd_mod, "helper") != 0) -+ continue; -+ -+ if (strcmp(desc->dtpd_func, "ustack") != 0) -+ continue; -+ -+ rv = dtrace_helper_action_add(DTRACE_HELPER_ACTION_USTACK, ep); -+ if (rv != 0) { -+ /* -+ * Adding this helper action failed -- we are now going -+ * to rip out the entire generation and return failure. -+ */ -+ dtrace_helper_destroygen(dth->dthps_generation); -+ dtrace_enabling_destroy(enab); -+ dtrace_dof_destroy(dof); -+ return -1; -+ } -+ -+ nhelpers++; -+ } -+ -+ if (nhelpers < enab->dten_ndesc) -+ dtrace_dof_error(dof, "unmatched helpers"); -+ -+ gen = dth->dthps_generation++; -+ dtrace_enabling_destroy(enab); -+ -+ if (dhp != NULL && nprovs > 0) { -+ dt_dbg_dof(" DOF 0x%p Adding and registering providers\n", -+ dof); -+ -+ dhp->dofhp_dof = (uint64_t)(uintptr_t)dof; -+ if (dtrace_helper_provider_add(dhp, gen) == 0) { -+ mutex_unlock(&dtrace_lock); -+ dtrace_helper_provider_register(current, dth, dhp); -+ mutex_lock(&dtrace_lock); -+ -+ destroy = 0; -+ } -+ } -+ -+ if (destroy) -+ dtrace_dof_destroy(dof); -+ -+ return gen; -+} -+ -+void dtrace_helpers_destroy(struct task_struct *tsk) -+{ -+ struct dtrace_helpers *help; -+ struct dtrace_vstate *vstate; -+ int i; -+ -+ if (tsk->dt_task == NULL) -+ return; -+ -+ mutex_lock(&dtrace_lock); -+ -+ ASSERT(tsk->dt_task->dt_helpers != NULL); -+ ASSERT(dtrace_helpers > 0); -+ -+ dt_dbg_dof("Helper cleanup: PID %d\n", tsk->pid); -+ -+ help = tsk->dt_task->dt_helpers; -+ vstate = &help->dthps_vstate; -+ -+ /* -+ * We're now going to lose the help from this process. -+ */ -+ tsk->dt_task->dt_helpers = NULL; -+ dtrace_sync(); -+ -+ /* -+ * Destroy the helper actions. -+ */ -+ for (i = 0; i < DTRACE_NHELPER_ACTIONS; i++) { -+ struct dtrace_helper_action *h, *next; -+ -+ for (h = help->dthps_actions[i]; h != NULL; h = next) { -+ next = h->dtha_next; -+ dtrace_helper_action_destroy(h, vstate); -+ h = next; -+ } -+ } -+ -+ mutex_unlock(&dtrace_lock); -+ -+ /* -+ * Destroy the helper providers. -+ */ -+ if (help->dthps_maxprovs > 0) { -+ mutex_lock(&dtrace_meta_lock); -+ if (dtrace_meta_pid != NULL) { -+ ASSERT(dtrace_deferred_pid == NULL); -+ -+ for (i = 0; i < help->dthps_nprovs; i++) { -+ dtrace_helper_provider_remove( -+ &help->dthps_provs[i]->dthp_prov, -+ tsk->pid); -+ } -+ } else { -+ mutex_lock(&dtrace_lock); -+ ASSERT(help->dthps_deferred == 0 || -+ help->dthps_next != NULL || -+ help->dthps_prev != NULL || -+ help == dtrace_deferred_pid); -+ -+ /* -+ * Remove the helper from the deferred list. -+ */ -+ if (help->dthps_next != NULL) -+ help->dthps_next->dthps_prev = help->dthps_prev; -+ if (help->dthps_prev != NULL) -+ help->dthps_prev->dthps_next = help->dthps_next; -+ if (dtrace_deferred_pid == help) { -+ dtrace_deferred_pid = help->dthps_next; -+ ASSERT(help->dthps_prev == NULL); -+ } -+ -+ mutex_unlock(&dtrace_lock); -+ } -+ -+ mutex_unlock(&dtrace_meta_lock); -+ -+ for (i = 0; i < help->dthps_nprovs; i++) -+ dtrace_helper_provider_destroy(help->dthps_provs[i]); -+ -+ vfree(help->dthps_provs); -+ } -+ -+ mutex_lock(&dtrace_lock); -+ -+ dtrace_vstate_fini(&help->dthps_vstate); -+ vfree(help->dthps_actions); -+ kfree(help); -+ -+ --dtrace_helpers; -+ mutex_unlock(&dtrace_lock); -+} -+ -+void dtrace_helpers_duplicate(struct task_struct *from, struct task_struct *to) -+{ -+ struct dtrace_task *dfrom = from->dt_task; -+ struct dtrace_task *dto = to->dt_task; -+ struct dtrace_helpers *help, *newhelp; -+ struct dtrace_helper_action *helper, *new, *last; -+ struct dtrace_difo *dp; -+ struct dtrace_vstate *vstate; -+ -+ int i, j, sz, hasprovs = 0; -+ -+ if (dfrom == NULL || dto == NULL) -+ return; -+ -+ mutex_lock(&dtrace_lock); -+ -+ ASSERT(dfrom->dt_helpers != NULL); -+ ASSERT(dtrace_helpers > 0); -+ -+ help = dfrom->dt_helpers; -+ newhelp = dtrace_helpers_create(to); -+ -+ ASSERT(dto->dt_helpers != NULL); -+ -+ newhelp->dthps_generation = help->dthps_generation; -+ vstate = &newhelp->dthps_vstate; -+ -+ /* -+ * Duplicate the helper actions. -+ */ -+ for (i = 0; i < DTRACE_NHELPER_ACTIONS; i++) { -+ helper = help->dthps_actions[i]; -+ if (helper == NULL) -+ continue; -+ -+ for (last = NULL; helper != NULL; helper = helper->dtha_next) { -+ new = kzalloc(sizeof(struct dtrace_helper_action), -+ GFP_KERNEL); -+ new->dtha_generation = helper->dtha_generation; -+ -+ dp = helper->dtha_predicate; -+ if (dp != NULL) { -+ dp = dtrace_difo_duplicate(dp, vstate); -+ new->dtha_predicate = dp; -+ } -+ -+ new->dtha_nactions = helper->dtha_nactions; -+ sz = sizeof(struct dtrace_difo *) * new->dtha_nactions; -+ new->dtha_actions = vmalloc(sz); -+ -+ for (j = 0; j < new->dtha_nactions; j++) { -+ struct dtrace_difo *dp; -+ -+ dp = helper->dtha_actions[j]; -+ ASSERT(dp != NULL); -+ -+ dp = dtrace_difo_duplicate(dp, vstate); -+ new->dtha_actions[j] = dp; -+ } -+ -+ if (last != NULL) -+ last->dtha_next = new; -+ else -+ newhelp->dthps_actions[i] = new; -+ -+ last = new; -+ } -+ } -+ -+ /* -+ * Duplicate the helper providers and register them with the -+ * DTrace framework. -+ */ -+ if (help->dthps_nprovs > 0) { -+ newhelp->dthps_nprovs = help->dthps_nprovs; -+ newhelp->dthps_maxprovs = help->dthps_nprovs; -+ newhelp->dthps_provs = vmalloc( -+ newhelp->dthps_nprovs * -+ sizeof(struct dtrace_helper_provider *)); -+ -+ for (i = 0; i < newhelp->dthps_nprovs; i++) { -+ newhelp->dthps_provs[i] = help->dthps_provs[i]; -+ newhelp->dthps_provs[i]->dthp_ref++; -+ } -+ -+ hasprovs = 1; -+ } -+ -+ mutex_unlock(&dtrace_lock); -+ -+ if (hasprovs) -+ dtrace_helper_provider_register(to, newhelp, NULL); -+} -+ -+int dtrace_helper_destroygen(int gen) -+{ -+ struct task_struct *p = current; -+ struct dtrace_helpers *dth; -+ struct dtrace_vstate *vstate; -+ int i; -+ -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ -+ if (current->dt_task == NULL) -+ return -ENOMEM; -+ -+ dth = current->dt_task->dt_helpers; -+ -+ if (dth == NULL || gen > dth->dthps_generation) -+ return -EINVAL; -+ -+ vstate = &dth->dthps_vstate; -+ -+ for (i = 0; i < DTRACE_NHELPER_ACTIONS; i++) { -+ struct dtrace_helper_action *last = NULL, *h, *next; -+ -+ for (h = dth->dthps_actions[i]; h != NULL; h = next) { -+ next = h->dtha_next; -+ -+ dt_dbg_dof(" Comparing action (agen %d vs rgen %d)\n", -+ h->dtha_generation, gen); -+ -+ if (h->dtha_generation == gen) { -+ if (last != NULL) -+ last->dtha_next = next; -+ else -+ dth->dthps_actions[i] = next; -+ -+ dtrace_helper_action_destroy(h, vstate); -+ } else -+ last = h; -+ } -+ } -+ -+ /* -+ * Iterate until we've cleared out all helper providers with the given -+ * generation number. -+ */ -+ for (;;) { -+ struct dtrace_helper_provider *prov = NULL; -+ -+ /* -+ * Look for a helper provider with the right generation. We -+ * have to start back at the beginning of the list each time -+ * because we drop dtrace_lock. It's unlikely that we'll make -+ * more than two passes. -+ */ -+ for (i = 0; i < dth->dthps_nprovs; i++) { -+ prov = dth->dthps_provs[i]; -+ -+ if (prov->dthp_generation == gen) -+ break; -+ } -+ -+ /* -+ * If there were no matches, we are done. -+ */ -+ if (i == dth->dthps_nprovs) -+ break; -+ -+ dt_dbg_dof(" Found provider with gen %d\n", gen); -+ -+ /* -+ * Move the last helper provider into this slot. -+ */ -+ dth->dthps_nprovs--; -+ dth->dthps_provs[i] = dth->dthps_provs[dth->dthps_nprovs]; -+ dth->dthps_provs[dth->dthps_nprovs] = NULL; -+ -+ mutex_unlock(&dtrace_lock); -+ -+ /* -+ * If we have a meta provider, remove this helper provider. -+ */ -+ mutex_lock(&dtrace_meta_lock); -+ -+ if (dtrace_meta_pid != NULL) { -+ ASSERT(dtrace_deferred_pid == NULL); -+ -+ dtrace_helper_provider_remove(&prov->dthp_prov, -+ p->pid); -+ } -+ -+ mutex_unlock(&dtrace_meta_lock); -+ -+ dtrace_helper_provider_destroy(prov); -+ -+ mutex_lock(&dtrace_lock); -+ } -+ -+ return 0; -+} -+ -+static void dtrace_helper_trace(struct dtrace_helper_action *helper, -+ struct dtrace_mstate *mstate, -+ struct dtrace_vstate *vstate, int where) -+{ -+ uint32_t size, next, nnext, i; -+ struct dtrace_helptrace *ent; -+ uint16_t flags = this_cpu_core->cpuc_dtrace_flags; -+ -+ if (!dtrace_helptrace_enabled) -+ return; -+ -+ ASSERT(vstate->dtvs_nlocals <= dtrace_helptrace_nlocals); -+ -+ /* -+ * What would a tracing framework be without its own tracing -+ * framework? (Well, a hell of a lot simpler, for starters...) -+ */ -+ size = sizeof(struct dtrace_helptrace) + dtrace_helptrace_nlocals * -+ sizeof(uint64_t) - sizeof(uint64_t); -+ -+ /* -+ * Iterate until we can allocate a slot in the trace buffer. -+ */ -+ do { -+ next = dtrace_helptrace_next; -+ -+ if (next + size < dtrace_helptrace_bufsize) -+ nnext = next + size; -+ else -+ nnext = size; -+ } while (cmpxchg(&dtrace_helptrace_next, next, nnext) != next); -+ -+ /* -+ * We have our slot; fill it in. -+ */ -+ if (nnext == size) -+ next = 0; -+ -+ ent = (struct dtrace_helptrace *)&dtrace_helptrace_buffer[next]; -+ ent->dtht_helper = helper; -+ ent->dtht_where = where; -+ ent->dtht_nlocals = vstate->dtvs_nlocals; -+ -+ ent->dtht_fltoffs = (mstate->dtms_present & DTRACE_MSTATE_FLTOFFS) -+ ? mstate->dtms_fltoffs -+ : -1; -+ ent->dtht_fault = DTRACE_FLAGS2FLT(flags); -+ ent->dtht_illval = this_cpu_core->cpuc_dtrace_illval; -+ -+ for (i = 0; i < vstate->dtvs_nlocals; i++) { -+ struct dtrace_statvar *svar; -+ -+ svar = vstate->dtvs_locals[i]; -+ if (svar == NULL) -+ continue; -+ -+ ASSERT(svar->dtsv_size >= NR_CPUS * sizeof(uint64_t)); -+ ent->dtht_locals[i] = -+ ((uint64_t *)(uintptr_t)svar->dtsv_data)[ -+ smp_processor_id()]; -+ } -+} -+ -+uint64_t dtrace_helper(int which, struct dtrace_mstate *mstate, -+ struct dtrace_state *state, uint64_t arg0, -+ uint64_t arg1) -+{ -+ uint16_t *flags = &this_cpu_core->cpuc_dtrace_flags; -+ uint64_t sarg0 = mstate->dtms_arg[0]; -+ uint64_t sarg1 = mstate->dtms_arg[1]; -+ uint64_t rval = 0; -+ struct dtrace_helpers *helpers; -+ struct dtrace_helper_action *helper; -+ struct dtrace_vstate *vstate; -+ struct dtrace_difo *pred; -+ int i, trace = dtrace_helptrace_enabled; -+ -+ ASSERT(which >= 0 && which < DTRACE_NHELPER_ACTIONS); -+ -+ if (current->dt_task == NULL) -+ return 0; -+ -+ helpers = current->dt_task->dt_helpers; -+ if (helpers == NULL) -+ return 0; -+ -+ helper = helpers->dthps_actions[which]; -+ if (helper == NULL) -+ return 0; -+ -+ vstate = &helpers->dthps_vstate; -+ mstate->dtms_arg[0] = arg0; -+ mstate->dtms_arg[1] = arg1; -+ -+ /* -+ * Now iterate over each helper. If its predicate evaluates to 'true', -+ * we'll call the corresponding actions. Note that the below calls -+ * to dtrace_dif_emulate() may set faults in machine state. This is -+ * okay: our caller (the outer dtrace_dif_emulate()) will simply plow -+ * the stored DIF offset with its own (which is the desired behavior). -+ * Also, note the calls to dtrace_dif_emulate() may allocate scratch -+ * from machine state; this is okay, too. -+ */ -+ for (; helper != NULL; helper = helper->dtha_next) { -+ pred = helper->dtha_predicate; -+ if (pred != NULL) { -+ if (trace) -+ dtrace_helper_trace(helper, mstate, vstate, 0); -+ -+ if (!dtrace_dif_emulate(pred, mstate, vstate, state)) -+ goto next; -+ -+ if (*flags & CPU_DTRACE_FAULT) -+ goto err; -+ } -+ -+ for (i = 0; i < helper->dtha_nactions; i++) { -+ if (trace) -+ dtrace_helper_trace(helper, mstate, vstate, -+ i + 1); -+ -+ rval = dtrace_dif_emulate(helper->dtha_actions[i], -+ mstate, vstate, state); -+ -+ if (*flags & CPU_DTRACE_FAULT) -+ goto err; -+ } -+ -+next: -+ if (trace) -+ dtrace_helper_trace(helper, mstate, vstate, -+ DTRACE_HELPTRACE_NEXT); -+ } -+ -+ if (trace) -+ dtrace_helper_trace(helper, mstate, vstate, -+ DTRACE_HELPTRACE_DONE); -+ -+ /* -+ * Restore the arg0 that we saved upon entry. -+ */ -+ mstate->dtms_arg[0] = sarg0; -+ mstate->dtms_arg[1] = sarg1; -+ -+ return rval; -+ -+err: -+ if (trace) -+ dtrace_helper_trace(helper, mstate, vstate, -+ DTRACE_HELPTRACE_ERR); -+ -+ /* -+ * Restore the arg0 that we saved upon entry. -+ */ -+ mstate->dtms_arg[0] = sarg0; -+ mstate->dtms_arg[1] = sarg1; -+ -+ return 0; -+} -diff --git a/dtrace/dtrace_ecb.c b/dtrace/dtrace_ecb.c -new file mode 100644 -index 000000000000..cc04d1a14661 ---- /dev/null -+++ b/dtrace/dtrace_ecb.c -@@ -0,0 +1,936 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_ecb.c -+ * DESCRIPTION: DTrace - ECB implementation -+ * -+ * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/slab.h> -+#include <linux/vmalloc.h> -+ -+#include "dtrace.h" -+ -+struct dtrace_ecb *dtrace_ecb_create_cache; -+ -+static struct dtrace_action * -+dtrace_ecb_aggregation_create(struct dtrace_ecb *ecb, -+ struct dtrace_actdesc *desc) -+{ -+ struct dtrace_aggregation *agg; -+ size_t size = sizeof(uint64_t); -+ int ntuple = desc->dtad_ntuple; -+ struct dtrace_action *act; -+ struct dtrace_recdesc *frec; -+ dtrace_aggid_t aggid; -+ struct dtrace_state *state = ecb->dte_state; -+ -+ agg = kzalloc(sizeof(struct dtrace_aggregation), GFP_KERNEL); -+ if (agg == NULL) -+ return NULL; -+ -+ agg->dtag_ecb = ecb; -+ -+ ASSERT(DTRACEACT_ISAGG(desc->dtad_kind)); -+ -+ switch (desc->dtad_kind) { -+ case DTRACEAGG_MIN: -+ agg->dtag_initial = INT64_MAX; -+ agg->dtag_aggregate = dtrace_aggregate_min; -+ break; -+ -+ case DTRACEAGG_MAX: -+ agg->dtag_initial = INT64_MIN; -+ agg->dtag_aggregate = dtrace_aggregate_max; -+ break; -+ -+ case DTRACEAGG_COUNT: -+ agg->dtag_aggregate = dtrace_aggregate_count; -+ break; -+ -+ case DTRACEAGG_QUANTIZE: -+ agg->dtag_aggregate = dtrace_aggregate_quantize; -+ size = (((sizeof(uint64_t) * NBBY) - 1) * 2 + 1) * -+ sizeof(uint64_t); -+ break; -+ -+ case DTRACEAGG_LQUANTIZE: { -+ uint16_t step = DTRACE_LQUANTIZE_STEP(desc->dtad_arg); -+ uint16_t levels = -+ DTRACE_LQUANTIZE_LEVELS(desc->dtad_arg); -+ -+ agg->dtag_initial = desc->dtad_arg; -+ agg->dtag_aggregate = dtrace_aggregate_lquantize; -+ -+ if (step == 0 || levels == 0) -+ goto err; -+ -+ size = levels * sizeof(uint64_t) + 3 * sizeof(uint64_t); -+ break; -+ } -+ -+ case DTRACEAGG_LLQUANTIZE: { -+ uint16_t factor = DTRACE_LLQUANTIZE_FACTOR(desc->dtad_arg); -+ uint16_t lmag = DTRACE_LLQUANTIZE_LMAG(desc->dtad_arg); -+ uint16_t hmag = DTRACE_LLQUANTIZE_HMAG(desc->dtad_arg); -+ uint16_t steps = DTRACE_LLQUANTIZE_STEPS(desc->dtad_arg); -+ uint64_t buf64s; -+ -+ agg->dtag_initial = desc->dtad_arg; -+ agg->dtag_aggregate = dtrace_aggregate_llquantize; -+ -+ /* -+ * 64 is the largest hmag can practically be (for the smallest -+ * possible value of factor, 2). libdtrace has already checked -+ * for overflow, so if hmag > 64, we have corrupted DOF. -+ */ -+ if (factor < 2 || steps == 0 || hmag > 64) -+ goto err; -+ -+ /* -+ * The size of the buffer for an llquantize() is given by: -+ * (hmag-lmag+1) logarithmic ranges -+ * x -+ * (steps - steps/factor) bins per range -+ * x -+ * 2 signs -+ * + -+ * two overflow bins -+ * + -+ * one underflow bin -+ * + -+ * beginning word to encode factor,lmag,hmag,steps -+ */ -+ buf64s = ((hmag-lmag+1)*(steps-steps/factor)*2+4); -+ size = buf64s * sizeof(uint64_t); -+ break; -+ } -+ -+ case DTRACEAGG_AVG: -+ agg->dtag_aggregate = dtrace_aggregate_avg; -+ size = sizeof(uint64_t) * 2; -+ break; -+ -+ case DTRACEAGG_STDDEV: -+ agg->dtag_aggregate = dtrace_aggregate_stddev; -+ size = sizeof(uint64_t) * 4; -+ break; -+ -+ case DTRACEAGG_SUM: -+ agg->dtag_aggregate = dtrace_aggregate_sum; -+ break; -+ -+ default: -+ goto err; -+ } -+ -+ agg->dtag_action.dta_rec.dtrd_size = size; -+ -+ if (ntuple == 0) -+ goto err; -+ -+ for (act = ecb->dte_action_last; act != NULL; act = act->dta_prev) { -+ if (DTRACEACT_ISAGG(act->dta_kind)) -+ break; -+ -+ if (--ntuple == 0) { -+ agg->dtag_first = act; -+ goto success; -+ } -+ } -+ -+ ASSERT(ntuple != 0); -+err: -+ kfree(agg); -+ return NULL; -+ -+success: -+ ASSERT(ecb->dte_action_last != NULL); -+ act = ecb->dte_action_last; -+ -+ if (act->dta_kind == DTRACEACT_DIFEXPR) { -+ ASSERT(act->dta_difo != NULL); -+ -+ if (act->dta_difo->dtdo_rtype.dtdt_size == 0) -+ agg->dtag_hasarg = 1; -+ } -+ -+ /* -+ * Get an ID for the aggregation (add it to the idr). -+ */ -+ idr_preload(GFP_KERNEL); -+ aggid = idr_alloc_cyclic(&state->dts_agg_idr, agg, 0, 0, GFP_NOWAIT); -+ idr_preload_end(); -+ if (aggid < 0) { -+ /* FIXME: need to handle this */ -+ } -+ -+ state->dts_naggs++; -+ agg->dtag_id = aggid; -+ -+ frec = &agg->dtag_first->dta_rec; -+ if (frec->dtrd_alignment < sizeof(dtrace_aggid_t)) -+ frec->dtrd_alignment = sizeof(dtrace_aggid_t); -+ -+ for (act = agg->dtag_first; act != NULL; act = act->dta_next) { -+ ASSERT(!act->dta_intuple); -+ -+ act->dta_intuple = 1; -+ } -+ -+ return &agg->dtag_action; -+} -+ -+void dtrace_ecb_aggregation_destroy(struct dtrace_ecb *ecb, -+ struct dtrace_action *act) -+{ -+ struct dtrace_aggregation *agg = (struct dtrace_aggregation *)act; -+ struct dtrace_state *state = ecb->dte_state; -+ -+ ASSERT(DTRACEACT_ISAGG(act->dta_kind)); -+ -+ idr_remove(&state->dts_agg_idr, agg->dtag_id); -+ state->dts_naggs--; -+ -+ kfree(agg); -+} -+ -+static int dtrace_ecb_action_add(struct dtrace_ecb *ecb, -+ struct dtrace_actdesc *desc) -+{ -+ struct dtrace_action *action, *last; -+ struct dtrace_difo *dp = desc->dtad_difo; -+ uint32_t size = 0, align = sizeof(uint8_t), mask; -+ uint16_t format = 0; -+ struct dtrace_recdesc *rec; -+ struct dtrace_state *state = ecb->dte_state; -+ dtrace_optval_t *opt = state->dts_options, nframes, strsize; -+ uint64_t arg = desc->dtad_arg; -+ -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ ASSERT(ecb->dte_action == NULL || ecb->dte_action->dta_refcnt == 1); -+ -+ if (DTRACEACT_ISAGG(desc->dtad_kind)) { -+ struct dtrace_action *act; -+ -+ for (act = ecb->dte_action; act != NULL; act = act->dta_next) { -+ if (act->dta_kind == DTRACEACT_COMMIT) -+ return -EINVAL; -+ -+ if (act->dta_kind == DTRACEACT_SPECULATE) -+ return -EINVAL; -+ } -+ -+ action = dtrace_ecb_aggregation_create(ecb, desc); -+ if (action == NULL) -+ return -EINVAL; -+ } else { -+ if (DTRACEACT_ISDESTRUCTIVE(desc->dtad_kind) || -+ (desc->dtad_kind == DTRACEACT_DIFEXPR && -+ dp != NULL && dp->dtdo_destructive)) -+ state->dts_destructive = 1; -+ -+ switch (desc->dtad_kind) { -+ case DTRACEACT_PRINTF: -+ case DTRACEACT_PRINTA: -+ case DTRACEACT_SYSTEM: -+ case DTRACEACT_FREOPEN: -+ if ((void *)(uintptr_t)arg == NULL) { -+ ASSERT(desc->dtad_kind == DTRACEACT_PRINTA); -+ -+ format = 0; -+ } else { -+ ASSERT((void *)(uintptr_t)arg != NULL); -+#ifdef FIXME -+ ASSERT(arg > KERNELBASE); -+#endif -+ -+ format = dtrace_format_add( -+ state, (char *)(uintptr_t)arg); -+ } -+ /* fallthru */ -+ -+ case DTRACEACT_TRACEMEM: -+ case DTRACEACT_LIBACT: -+ case DTRACEACT_DIFEXPR: -+ if (dp == NULL) -+ return -EINVAL; -+ -+ size = dp->dtdo_rtype.dtdt_size; -+ if (size != 0) -+ break; -+ -+ if (dp->dtdo_rtype.dtdt_kind == DIF_TYPE_STRING) { -+ if (!(dp->dtdo_rtype.dtdt_flags & DIF_TF_BYREF)) -+ return -EINVAL; -+ -+ size = opt[DTRACEOPT_STRSIZE]; -+ } -+ -+ break; -+ -+ case DTRACEACT_STACK: -+ nframes = arg; -+ if (nframes == 0) { -+ nframes = opt[DTRACEOPT_STACKFRAMES]; -+ -+ ASSERT(nframes > 0); -+ -+ arg = nframes; -+ } -+ -+ size = nframes * sizeof(uint64_t); -+ break; -+ -+ case DTRACEACT_JSTACK: -+ strsize = DTRACE_USTACK_STRSIZE(arg); -+ if (strsize == 0) -+ strsize = opt[DTRACEOPT_JSTACKSTRSIZE]; -+ -+ nframes = DTRACE_USTACK_NFRAMES(arg); -+ if (nframes == 0) -+ nframes = opt[DTRACEOPT_JSTACKFRAMES]; -+ -+ arg = DTRACE_USTACK_ARG(nframes, strsize); -+ /* fallthru */ -+ -+ case DTRACEACT_USTACK: -+ if (desc->dtad_kind != DTRACEACT_JSTACK && -+ (nframes = DTRACE_USTACK_NFRAMES(arg)) == 0) { -+ strsize = DTRACE_USTACK_STRSIZE(arg); -+ nframes = opt[DTRACEOPT_USTACKFRAMES]; -+ -+ ASSERT(nframes > 0); -+ -+ arg = DTRACE_USTACK_ARG(nframes, strsize); -+ } -+ -+ size = (nframes + 2) * sizeof(uint64_t); -+ size += DTRACE_USTACK_STRSIZE(arg); -+ size = P2ROUNDUP(size, (uint32_t)(sizeof(uintptr_t))); -+ -+ break; -+ -+ case DTRACEACT_SYM: -+ case DTRACEACT_MOD: -+ if (dp == NULL || ((size = dp->dtdo_rtype.dtdt_size) != -+ sizeof(uint64_t)) || -+ (dp->dtdo_rtype.dtdt_flags & DIF_TF_BYREF)) -+ return -EINVAL; -+ -+ break; -+ -+ case DTRACEACT_USYM: -+ case DTRACEACT_UMOD: -+ case DTRACEACT_UADDR: -+ if (dp == NULL || -+ (dp->dtdo_rtype.dtdt_size != sizeof(uint64_t)) || -+ (dp->dtdo_rtype.dtdt_flags & DIF_TF_BYREF)) -+ return -EINVAL; -+ -+ size = 3 * sizeof(uint64_t); -+ -+ break; -+ -+ case DTRACEACT_STOP: -+ case DTRACEACT_BREAKPOINT: -+ case DTRACEACT_PANIC: -+ break; -+ -+ case DTRACEACT_CHILL: -+ case DTRACEACT_DISCARD: -+ case DTRACEACT_RAISE: -+ if (dp == NULL) -+ return -EINVAL; -+ -+ break; -+ -+ case DTRACEACT_EXIT: -+ if (dp == NULL || (size = dp->dtdo_rtype.dtdt_size) != -+ sizeof(int) || -+ (dp->dtdo_rtype.dtdt_flags & DIF_TF_BYREF)) -+ return -EINVAL; -+ -+ break; -+ -+ case DTRACEACT_SPECULATE: -+ if (ecb->dte_size > sizeof(dtrace_epid_t)) -+ return -EINVAL; -+ -+ if (dp == NULL) -+ return -EINVAL; -+ -+ state->dts_speculates = 1; -+ -+ break; -+ -+ case DTRACEACT_COMMIT: { -+ struct dtrace_action *act = ecb->dte_action; -+ -+ for (; act != NULL; act = act->dta_next) { -+ if (act->dta_kind == DTRACEACT_COMMIT) -+ return -EINVAL; -+ } -+ -+ if (dp == NULL) -+ return -EINVAL; -+ -+ break; -+ } -+ -+ case DTRACEACT_PCAP: -+ size = dp->dtdo_rtype.dtdt_size; -+ break; -+ -+ default: -+ return -EINVAL; -+ } -+ -+ if (size != 0 || desc->dtad_kind == DTRACEACT_SPECULATE) { -+ struct dtrace_action *act = ecb->dte_action; -+ -+ for (; act != NULL; act = act->dta_next) { -+ if (act->dta_kind == DTRACEACT_COMMIT) -+ return -EINVAL; -+ } -+ } -+ -+ action = kzalloc(sizeof(struct dtrace_action), GFP_KERNEL); -+ if (action == NULL) -+ return -ENOMEM; -+ -+ action->dta_rec.dtrd_size = size; -+ } -+ -+ action->dta_refcnt = 1; -+ rec = &action->dta_rec; -+ size = rec->dtrd_size; -+ -+ for (mask = sizeof(uint64_t) - 1; size != 0 && mask > 0; mask >>= 1) { -+ if (!(size & mask)) { -+ align = mask + 1; -+ -+ break; -+ } -+ } -+ -+ action->dta_kind = desc->dtad_kind; -+ -+ action->dta_difo = dp; -+ if (action->dta_difo != NULL) -+ dtrace_difo_hold(dp); -+ -+ rec->dtrd_action = action->dta_kind; -+ rec->dtrd_arg = arg; -+ rec->dtrd_uarg = desc->dtad_uarg; -+ rec->dtrd_alignment = (uint16_t)align; -+ rec->dtrd_format = format; -+ -+ last = ecb->dte_action_last; -+ if (last != NULL) { -+ ASSERT(ecb->dte_action != NULL); -+ -+ action->dta_prev = last; -+ last->dta_next = action; -+ } else { -+ ASSERT(ecb->dte_action == NULL); -+ -+ ecb->dte_action = action; -+ } -+ -+ ecb->dte_action_last = action; -+ -+ return 0; -+} -+ -+static void dtrace_ecb_action_remove(struct dtrace_ecb *ecb) -+{ -+ struct dtrace_action *act = ecb->dte_action, *next; -+ struct dtrace_vstate *vstate = &ecb->dte_state->dts_vstate; -+ struct dtrace_difo *dp; -+ uint16_t format; -+ -+ if (act != NULL && act->dta_refcnt > 1) { -+ ASSERT(act->dta_next == NULL || act->dta_next->dta_refcnt == 1); -+ -+ act->dta_refcnt--; -+ } else { -+ for (; act != NULL; act = next) { -+ next = act->dta_next; -+ ASSERT(next != NULL || act == ecb->dte_action_last); -+ ASSERT(act->dta_refcnt == 1); -+ -+ format = act->dta_rec.dtrd_format; -+ if (format != 0) -+ dtrace_format_remove(ecb->dte_state, format); -+ -+ dp = act->dta_difo; -+ if (dp != NULL) -+ dtrace_difo_release(dp, vstate); -+ -+ if (DTRACEACT_ISAGG(act->dta_kind)) -+ dtrace_ecb_aggregation_destroy(ecb, act); -+ else -+ kfree(act); -+ } -+ } -+ -+ ecb->dte_action = NULL; -+ ecb->dte_action_last = NULL; -+ ecb->dte_size = sizeof(dtrace_epid_t); -+} -+ -+/* -+ * Disable the ECB by removing it from its probe. -+ */ -+void dtrace_ecb_disable(struct dtrace_ecb *ecb) -+{ -+ struct dtrace_ecb *pecb, *prev = NULL; -+ struct dtrace_probe *probe = ecb->dte_probe; -+ -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ -+ if (probe == NULL) -+ return; -+ -+ for (pecb = probe->dtpr_ecb; pecb != NULL; pecb = pecb->dte_next) { -+ if (pecb == ecb) -+ break; -+ -+ prev = pecb; -+ } -+ -+ ASSERT(pecb != NULL); -+ -+ if (prev == NULL) -+ probe->dtpr_ecb = ecb->dte_next; -+ else -+ prev->dte_next = ecb->dte_next; -+ -+ if (ecb == probe->dtpr_ecb_last) { -+ ASSERT(ecb->dte_next == NULL); -+ probe->dtpr_ecb_last = prev; -+ } -+ -+ /* -+ * The ECB has been disconnected from the probe; now sync to assure -+ * that all CPUs have seen the change before returning. -+ */ -+ dtrace_sync(); -+ -+ if (probe->dtpr_ecb == NULL) { -+ /* -+ * That was the last ECB on the probe; clear the predicate -+ * cache ID for the probe, disable it and sync one more time -+ * to assure that we'll never hit it again. -+ */ -+ struct dtrace_provider *prov = probe->dtpr_provider; -+ -+ ASSERT(ecb->dte_next == NULL); -+ ASSERT(probe->dtpr_ecb_last == NULL); -+ -+ probe->dtpr_predcache = DTRACE_CACHEIDNONE; -+ prov->dtpv_pops.dtps_disable(prov->dtpv_arg, -+ probe->dtpr_id, probe->dtpr_arg); -+ -+ dtrace_sync(); -+ } else { -+ /* -+ * There is at least one ECB remaining on the probe. If there -+ * is _exactly_ one, set the probe's predicate cache ID to be -+ * the predicate cache ID of the remaining ECB. -+ */ -+ ASSERT(probe->dtpr_ecb_last != NULL); -+ ASSERT(probe->dtpr_predcache == DTRACE_CACHEIDNONE); -+ -+ if (probe->dtpr_ecb == probe->dtpr_ecb_last) { -+ struct dtrace_predicate *p = -+ probe->dtpr_ecb->dte_predicate; -+ -+ ASSERT(probe->dtpr_ecb->dte_next == NULL); -+ -+ if (p != NULL) -+ probe->dtpr_predcache = p->dtp_cacheid; -+ } -+ -+ ecb->dte_next = NULL; -+ } -+} -+ -+static struct dtrace_ecb *dtrace_ecb_add(struct dtrace_state *state, -+ struct dtrace_probe *probe) -+{ -+ struct dtrace_ecb *ecb; -+ dtrace_epid_t epid; -+ -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ -+ ecb = kzalloc(sizeof(struct dtrace_ecb), GFP_KERNEL); -+ if (ecb == NULL) -+ return NULL; -+ -+ ecb->dte_predicate = NULL; -+ ecb->dte_probe = probe; -+ ecb->dte_size = ecb->dte_needed = sizeof(dtrace_epid_t); -+ ecb->dte_alignment = sizeof(dtrace_epid_t); -+ -+ epid = state->dts_epid++; -+ -+ if (epid - 1 >= state->dts_necbs) { -+ struct dtrace_ecb **oecbs = state->dts_ecbs, **ecbs; -+ int necbs = state->dts_necbs << 1; -+ -+ ASSERT(epid == state->dts_necbs + 1); -+ -+ if (necbs == 0) { -+ ASSERT(oecbs == NULL); -+ -+ necbs = 1; -+ } -+ -+ ecbs = vzalloc(necbs * sizeof(*ecbs)); -+ if (ecbs == NULL) { -+ kfree(ecb); -+ return NULL; -+ } -+ -+ if (oecbs != NULL) -+ memcpy(ecbs, oecbs, state->dts_necbs * sizeof(*ecbs)); -+ -+ dtrace_membar_producer(); -+ -+ state->dts_ecbs = ecbs; -+ -+ if (oecbs != NULL) { -+ if (state->dts_activity != DTRACE_ACTIVITY_INACTIVE) -+ dtrace_sync(); -+ -+ vfree(oecbs); -+ } -+ -+ dtrace_membar_producer(); -+ -+ state->dts_necbs = necbs; -+ } -+ -+ ecb->dte_state = state; -+ -+ ASSERT(state->dts_ecbs[epid - 1] == NULL); -+ -+ dtrace_membar_producer(); -+ -+ state->dts_ecbs[(ecb->dte_epid = epid) - 1] = ecb; -+ -+ return ecb; -+} -+ -+static struct dtrace_ecb * dtrace_ecb_create(struct dtrace_state *state, -+ struct dtrace_probe *probe, -+ struct dtrace_enabling *enab) -+{ -+ struct dtrace_ecb *ecb; -+ struct dtrace_predicate *pred; -+ struct dtrace_actdesc *act; -+ struct dtrace_provider *prov; -+ struct dtrace_ecbdesc *desc = enab->dten_current; -+ -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ ASSERT(state != NULL); -+ -+ ecb = dtrace_ecb_add(state, probe); -+ if (ecb == NULL) -+ return NULL; -+ -+ ecb->dte_uarg = desc->dted_uarg; -+ -+ pred = desc->dted_pred.dtpdd_predicate; -+ if (pred != NULL) { -+ dtrace_predicate_hold(pred); -+ ecb->dte_predicate = pred; -+ } -+ -+ if (probe != NULL) { -+ prov = probe->dtpr_provider; -+ -+ if (!(state->dts_cred.dcr_visible & DTRACE_CRV_ALLPROC) && -+ (prov->dtpv_priv.dtpp_flags & DTRACE_PRIV_USER)) -+ ecb->dte_cond |= DTRACE_COND_OWNER; -+ -+ if (!(state->dts_cred.dcr_visible & DTRACE_CRV_KERNEL) && -+ (prov->dtpv_priv.dtpp_flags & DTRACE_PRIV_KERNEL)) -+ ecb->dte_cond |= DTRACE_COND_USERMODE; -+ } -+ -+ if (dtrace_ecb_create_cache != NULL) { -+ struct dtrace_ecb *cached = dtrace_ecb_create_cache; -+ struct dtrace_action *act = cached->dte_action; -+ -+ if (act != NULL) { -+ ASSERT(act->dta_refcnt > 0); -+ -+ act->dta_refcnt++; -+ ecb->dte_action = act; -+ ecb->dte_action_last = cached->dte_action_last; -+ ecb->dte_needed = cached->dte_needed; -+ ecb->dte_size = cached->dte_size; -+ ecb->dte_alignment = cached->dte_alignment; -+ } -+ -+ return ecb; -+ } -+ -+ for (act = desc->dted_action; act != NULL; act = act->dtad_next) { -+ enab->dten_error = dtrace_ecb_action_add(ecb, act); -+ if (enab->dten_error != 0) { -+ dtrace_ecb_destroy(ecb); -+ return NULL; -+ } -+ } -+ -+ dtrace_ecb_resize(ecb); -+ -+ return (dtrace_ecb_create_cache = ecb); -+} -+ -+int dtrace_ecb_create_enable(struct dtrace_probe *probe, void *arg) -+{ -+ struct dtrace_ecb *ecb; -+ struct dtrace_enabling *enab = arg; -+ struct dtrace_state *state = enab->dten_vstate->dtvs_state; -+ -+ ASSERT(state != NULL); -+ -+ if (probe != NULL && probe->dtpr_gen < enab->dten_probegen) -+ return DTRACE_MATCH_NEXT; -+ -+ ecb = dtrace_ecb_create(state, probe, enab); -+ if (ecb == NULL) -+ return DTRACE_MATCH_DONE; -+ -+ if (dtrace_ecb_enable(ecb) < 0) -+ return DTRACE_MATCH_FAIL; -+ -+ return DTRACE_MATCH_NEXT; -+} -+ -+void dtrace_ecb_destroy(struct dtrace_ecb *ecb) -+{ -+ struct dtrace_state *state = ecb->dte_state; -+ struct dtrace_vstate *vstate = &state->dts_vstate; -+ struct dtrace_predicate *pred; -+ dtrace_epid_t epid = ecb->dte_epid; -+ -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ ASSERT(ecb->dte_next == NULL); -+ ASSERT(ecb->dte_probe == NULL || ecb->dte_probe->dtpr_ecb != ecb); -+ -+ pred = ecb->dte_predicate; -+ if (pred != NULL) -+ dtrace_predicate_release(pred, vstate); -+ -+ dtrace_ecb_action_remove(ecb); -+ -+ ASSERT(state->dts_ecbs[epid - 1] == ecb); -+ state->dts_ecbs[epid - 1] = NULL; -+ -+ kfree(ecb); -+} -+ -+void dtrace_ecb_resize(struct dtrace_ecb *ecb) -+{ -+ struct dtrace_action *act; -+ uint32_t maxalign = sizeof(dtrace_epid_t); -+ uint32_t align = sizeof(uint8_t), offs, diff; -+ int wastuple = 0; -+ uint32_t aggbase = UINT32_MAX; -+ struct dtrace_state *state = ecb->dte_state; -+ -+ /* -+ * If we record anything, we always record the epid. (And we always -+ * record it first.) -+ */ -+ offs = sizeof(dtrace_epid_t); -+ ecb->dte_size = ecb->dte_needed = sizeof(dtrace_epid_t); -+ -+ for (act = ecb->dte_action; act != NULL; act = act->dta_next) { -+ struct dtrace_recdesc *rec = &act->dta_rec; -+ -+ align = rec->dtrd_alignment; -+ if (align > maxalign) -+ maxalign = align; -+ -+ if (!wastuple && act->dta_intuple) { -+ /* -+ * This is the first record in a tuple. Align the -+ * offset to be at offset 4 in an 8-byte aligned -+ * block. -+ */ -+ diff = offs + sizeof(dtrace_aggid_t); -+ -+ diff &= sizeof(uint64_t) - 1; -+ if (diff) -+ offs += sizeof(uint64_t) - diff; -+ -+ aggbase = offs - sizeof(dtrace_aggid_t); -+ ASSERT(!(aggbase & (sizeof(uint64_t) - 1))); -+ } -+ -+ if (rec->dtrd_size != 0) { -+ diff = offs & (align - 1); -+ if (diff) -+ /* -+ * The current offset is not properly -+ * aligned; align it. -+ */ -+ offs += align - diff; -+ } -+ -+ rec->dtrd_offset = offs; -+ -+ if (offs + rec->dtrd_size > ecb->dte_needed) { -+ ecb->dte_needed = offs + rec->dtrd_size; -+ -+ if (ecb->dte_needed > state->dts_needed) -+ state->dts_needed = ecb->dte_needed; -+ } -+ -+ if (DTRACEACT_ISAGG(act->dta_kind)) { -+ struct dtrace_aggregation *agg; -+ struct dtrace_action *first, *prev; -+ -+ agg = (struct dtrace_aggregation *)act; -+ first = agg->dtag_first; -+ -+ ASSERT(rec->dtrd_size != 0 && first != NULL); -+ ASSERT(wastuple); -+ ASSERT(aggbase != UINT32_MAX); -+ -+ agg->dtag_base = aggbase; -+ -+ while ((prev = first->dta_prev) != NULL && -+ DTRACEACT_ISAGG(prev->dta_kind)) { -+ agg = (struct dtrace_aggregation *)prev; -+ first = agg->dtag_first; -+ } -+ -+ if (prev != NULL) { -+ offs = prev->dta_rec.dtrd_offset + -+ prev->dta_rec.dtrd_size; -+ } else -+ offs = sizeof(dtrace_epid_t); -+ -+ wastuple = 0; -+ } else { -+ if (!act->dta_intuple) -+ ecb->dte_size = offs + rec->dtrd_size; -+ -+ offs += rec->dtrd_size; -+ } -+ -+ wastuple = act->dta_intuple; -+ } -+ -+ act = ecb->dte_action; -+ if (act != NULL && -+ !(act->dta_kind == DTRACEACT_SPECULATE && act->dta_next == NULL) && -+ ecb->dte_size == sizeof(dtrace_epid_t)) { -+ /* -+ * If the size is still sizeof(dtrace_epid_t), then all -+ * actions store no data; set the size to 0. -+ */ -+ ecb->dte_alignment = maxalign; -+ ecb->dte_size = 0; -+ -+ /* -+ * If the needed space is still sizeof(dtrace_epid_t), then -+ * all actions need no additional space; set the needed -+ * size to 0. -+ */ -+ if (ecb->dte_needed == sizeof(dtrace_epid_t)) -+ ecb->dte_needed = 0; -+ -+ return; -+ } -+ -+ /* -+ * Set our alignment, and make sure that the dte_size and dte_needed -+ * are aligned to the size of an EPID. -+ */ -+ ecb->dte_alignment = maxalign; -+ ecb->dte_size = (ecb->dte_size + (sizeof(dtrace_epid_t) - 1)) & -+ ~(sizeof(dtrace_epid_t) - 1); -+ ecb->dte_needed = (ecb->dte_needed + (sizeof(dtrace_epid_t) - 1)) & -+ ~(sizeof(dtrace_epid_t) - 1); -+ ASSERT(ecb->dte_size <= ecb->dte_needed); -+} -+ -+int dtrace_ecb_enable(struct dtrace_ecb *ecb) -+{ -+ struct dtrace_probe *probe = ecb->dte_probe; -+ -+ ASSERT(MUTEX_HELD(&cpu_lock)); -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ ASSERT(ecb->dte_next == NULL); -+ -+ if (probe == NULL) -+ return 0; -+ -+ if (probe->dtpr_ecb == NULL) { -+ struct dtrace_provider *prov = probe->dtpr_provider; -+ -+ probe->dtpr_ecb = probe->dtpr_ecb_last = ecb; -+ -+ -+ if (ecb->dte_predicate != NULL) -+ probe->dtpr_predcache = ecb->dte_predicate->dtp_cacheid; -+ -+ return prov->dtpv_pops.dtps_enable(prov->dtpv_arg, -+ probe->dtpr_id, -+ probe->dtpr_arg); -+ } else { -+ ASSERT(probe->dtpr_ecb_last != NULL); -+ -+ probe->dtpr_ecb_last->dte_next = ecb; -+ probe->dtpr_ecb_last = ecb; -+ probe->dtpr_predcache = 0; -+ -+ dtrace_sync(); -+ -+ return 0; -+ } -+} -+ -+struct dtrace_ecb *dtrace_epid2ecb(struct dtrace_state *state, -+ dtrace_epid_t id) -+{ -+ struct dtrace_ecb *ecb; -+ -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ -+ if (id == 0 || id > state->dts_necbs) -+ return NULL; -+ -+ ASSERT(state->dts_necbs > 0 && state->dts_ecbs != NULL); -+ ecb = state->dts_ecbs[id - 1]; -+ ASSERT(ecb == NULL || ecb->dte_epid == id); -+ -+ return ecb; -+} -+ -+struct dtrace_aggregation *dtrace_aggid2agg(struct dtrace_state *state, -+ dtrace_aggid_t id) -+{ -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ -+ return idr_find(&state->dts_agg_idr, id); -+} -diff --git a/dtrace/dtrace_enable.c b/dtrace/dtrace_enable.c -new file mode 100644 -index 000000000000..72f30149cb9c ---- /dev/null -+++ b/dtrace/dtrace_enable.c -@@ -0,0 +1,449 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_enable.c -+ * DESCRIPTION: DTrace - probe enabling implementation -+ * -+ * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/mutex.h> -+#include <linux/slab.h> -+#include <linux/vmalloc.h> -+ -+#include "dtrace.h" -+ -+size_t dtrace_retain_max = 1024; -+struct dtrace_enabling *dtrace_retained; -+dtrace_genid_t dtrace_retained_gen; -+ -+struct dtrace_enabling *dtrace_enabling_create(struct dtrace_vstate *vstate) -+{ -+ struct dtrace_enabling *enab; -+ -+ enab = kzalloc(sizeof(struct dtrace_enabling), GFP_KERNEL); -+ if (enab == NULL) -+ return NULL; -+ -+ enab->dten_vstate = vstate; -+ -+ return enab; -+} -+ -+void dtrace_enabling_add(struct dtrace_enabling *enab, -+ struct dtrace_ecbdesc *ecb) -+{ -+ struct dtrace_ecbdesc **ndesc; -+ size_t osize, nsize; -+ -+ /* -+ * We can't add to enablings after we've enabled them, or after we've -+ * retained them. -+ */ -+ ASSERT(enab->dten_probegen == 0); -+ ASSERT(enab->dten_next == NULL && enab->dten_prev == NULL); -+ -+ if (enab->dten_ndesc < enab->dten_maxdesc) { -+ enab->dten_desc[enab->dten_ndesc++] = ecb; -+ return; -+ } -+ -+ osize = enab->dten_maxdesc * sizeof(struct dtrace_enabling *); -+ -+ if (enab->dten_maxdesc == 0) -+ enab->dten_maxdesc = 1; -+ else -+ enab->dten_maxdesc <<= 1; -+ -+ ASSERT(enab->dten_ndesc < enab->dten_maxdesc); -+ -+ nsize = enab->dten_maxdesc * sizeof(struct dtrace_enabling *); -+ ndesc = vzalloc(nsize); -+ memcpy(ndesc, enab->dten_desc, osize); -+ vfree(enab->dten_desc); -+ -+ enab->dten_desc = ndesc; -+ enab->dten_desc[enab->dten_ndesc++] = ecb; -+} -+ -+static void dtrace_enabling_addlike(struct dtrace_enabling *enab, -+ struct dtrace_ecbdesc *ecb, -+ struct dtrace_probedesc *pd) -+{ -+ struct dtrace_ecbdesc *new; -+ struct dtrace_predicate *pred; -+ struct dtrace_actdesc *act; -+ -+ /* -+ * We're going to create a new ECB description that matches the -+ * specified ECB in every way, but has the specified probe description. -+ */ -+ new = kzalloc(sizeof(struct dtrace_ecbdesc), GFP_KERNEL); -+ -+ pred = ecb->dted_pred.dtpdd_predicate; -+ if (pred != NULL) -+ dtrace_predicate_hold(pred); -+ -+ for (act = ecb->dted_action; act != NULL; act = act->dtad_next) -+ dtrace_actdesc_hold(act); -+ -+ new->dted_action = ecb->dted_action; -+ new->dted_pred = ecb->dted_pred; -+ new->dted_probe = *pd; -+ new->dted_uarg = ecb->dted_uarg; -+ -+ dtrace_enabling_add(enab, new); -+} -+ -+void dtrace_enabling_dump(struct dtrace_enabling *enab) -+{ -+ int i; -+ -+ for (i = 0; i < enab->dten_ndesc; i++) { -+ struct dtrace_probedesc *desc = -+ &enab->dten_desc[i]->dted_probe; -+ -+ pr_info("enabling probe %d (%s:%s:%s:%s)", -+ i, desc->dtpd_provider, desc->dtpd_mod, -+ desc->dtpd_func, desc->dtpd_name); -+ } -+} -+ -+void dtrace_enabling_destroy(struct dtrace_enabling *enab) -+{ -+ int i; -+ struct dtrace_ecbdesc *ep; -+ struct dtrace_vstate *vstate = enab->dten_vstate; -+ -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ -+ for (i = 0; i < enab->dten_ndesc; i++) { -+ struct dtrace_actdesc *act, *next; -+ struct dtrace_predicate *pred; -+ -+ ep = enab->dten_desc[i]; -+ -+ pred = ep->dted_pred.dtpdd_predicate; -+ if (pred != NULL) -+ dtrace_predicate_release(pred, vstate); -+ -+ for (act = ep->dted_action; act != NULL; act = next) { -+ next = act->dtad_next; -+ dtrace_actdesc_release(act, vstate); -+ } -+ -+ kfree(ep); -+ } -+ -+ vfree(enab->dten_desc); -+ -+ /* -+ * If this was a retained enabling, decrement the dts_nretained count -+ * and remove it from the dtrace_retained list. -+ */ -+ if (enab->dten_prev != NULL || enab->dten_next != NULL || -+ dtrace_retained == enab) { -+ ASSERT(enab->dten_vstate->dtvs_state != NULL); -+ ASSERT(enab->dten_vstate->dtvs_state->dts_nretained > 0); -+ enab->dten_vstate->dtvs_state->dts_nretained--; -+ dtrace_retained_gen++; -+ } -+ -+ if (enab->dten_prev == NULL) { -+ if (dtrace_retained == enab) { -+ dtrace_retained = enab->dten_next; -+ -+ if (dtrace_retained != NULL) -+ dtrace_retained->dten_prev = NULL; -+ } -+ } else { -+ ASSERT(enab != dtrace_retained); -+ ASSERT(dtrace_retained != NULL); -+ enab->dten_prev->dten_next = enab->dten_next; -+ } -+ -+ if (enab->dten_next != NULL) { -+ ASSERT(dtrace_retained != NULL); -+ enab->dten_next->dten_prev = enab->dten_prev; -+ } -+ -+ kfree(enab); -+} -+ -+int dtrace_enabling_retain(struct dtrace_enabling *enab) -+{ -+ struct dtrace_state *state; -+ -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ ASSERT(enab->dten_next == NULL && enab->dten_prev == NULL); -+ ASSERT(enab->dten_vstate != NULL); -+ -+ state = enab->dten_vstate->dtvs_state; -+ ASSERT(state != NULL); -+ -+ /* -+ * We only allow each state to retain dtrace_retain_max enablings. -+ */ -+ if (state->dts_nretained >= dtrace_retain_max) -+ return -ENOSPC; -+ -+ state->dts_nretained++; -+ dtrace_retained_gen++; -+ -+ if (dtrace_retained == NULL) { -+ dtrace_retained = enab; -+ return 0; -+ } -+ -+ enab->dten_next = dtrace_retained; -+ dtrace_retained->dten_prev = enab; -+ dtrace_retained = enab; -+ -+ return 0; -+} -+ -+int dtrace_enabling_replicate(struct dtrace_state *state, -+ struct dtrace_probedesc *match, -+ struct dtrace_probedesc *create) -+{ -+ struct dtrace_enabling *new, *enab; -+ int found = 0, err = -ENOENT; -+ -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ ASSERT(strlen(match->dtpd_provider) < DTRACE_PROVNAMELEN); -+ ASSERT(strlen(match->dtpd_mod) < DTRACE_MODNAMELEN); -+ ASSERT(strlen(match->dtpd_func) < DTRACE_FUNCNAMELEN); -+ ASSERT(strlen(match->dtpd_name) < DTRACE_NAMELEN); -+ -+ new = dtrace_enabling_create(&state->dts_vstate); -+ if (new == NULL) -+ return -ENOMEM; -+ -+ /* -+ * Iterate over all retained enablings, looking for enablings that -+ * match the specified state. -+ */ -+ for (enab = dtrace_retained; enab != NULL; enab = enab->dten_next) { -+ int i; -+ -+ /* -+ * dtvs_state can only be NULL for helper enablings -- and -+ * helper enablings can't be retained. -+ */ -+ ASSERT(enab->dten_vstate->dtvs_state != NULL); -+ -+ if (enab->dten_vstate->dtvs_state != state) -+ continue; -+ -+ /* -+ * Now iterate over each probe description; we're looking for -+ * an exact match to the specified probe description. -+ */ -+ for (i = 0; i < enab->dten_ndesc; i++) { -+ struct dtrace_ecbdesc *ep = enab->dten_desc[i]; -+ struct dtrace_probedesc *pd = &ep->dted_probe; -+ -+ if (strcmp(pd->dtpd_provider, match->dtpd_provider)) -+ continue; -+ -+ if (strcmp(pd->dtpd_mod, match->dtpd_mod)) -+ continue; -+ -+ if (strcmp(pd->dtpd_func, match->dtpd_func)) -+ continue; -+ -+ if (strcmp(pd->dtpd_name, match->dtpd_name)) -+ continue; -+ -+ /* -+ * We have a winning probe! Add it to our growing -+ * enabling. -+ */ -+ found = 1; -+ dtrace_enabling_addlike(new, ep, create); -+ } -+ } -+ -+ if (!found || (err = dtrace_enabling_retain(new)) != 0) { -+ dtrace_enabling_destroy(new); -+ return err; -+ } -+ -+ return 0; -+} -+ -+void dtrace_enabling_retract(struct dtrace_state *state) -+{ -+ struct dtrace_enabling *enab, *next; -+ -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ -+ /* -+ * Iterate over all retained enablings, destroy the enablings retained -+ * for the specified state. -+ */ -+ for (enab = dtrace_retained; enab != NULL; enab = next) { -+ next = enab->dten_next; -+ -+ /* -+ * dtvs_state can only be NULL for helper enablings, and helper -+ * enablings can't be retained. -+ */ -+ ASSERT(enab->dten_vstate->dtvs_state != NULL); -+ -+ if (enab->dten_vstate->dtvs_state == state) { -+ ASSERT(state->dts_nretained > 0); -+ dtrace_enabling_destroy(enab); -+ } -+ } -+ -+ ASSERT(state->dts_nretained == 0); -+} -+ -+int dtrace_enabling_match(struct dtrace_enabling *enab, int *nmatched) -+{ -+ int i; -+ int total_matched = 0, matched = 0; -+ -+ for (i = 0; i < enab->dten_ndesc; i++) { -+ struct dtrace_ecbdesc *ep = enab->dten_desc[i]; -+ -+ enab->dten_current = ep; -+ enab->dten_error = 0; -+ -+ dt_dbg_enable(" Matching enabling %p[%d] for %s:%s:%s:%s\n", -+ enab, i, ep->dted_probe.dtpd_provider, -+ ep->dted_probe.dtpd_mod, -+ ep->dted_probe.dtpd_func, -+ ep->dted_probe.dtpd_name); -+ -+ matched = dtrace_probe_enable(&ep->dted_probe, enab); -+ if (matched < 0) { -+ dt_dbg_enable(" Matching enabling %p[%d] failed: " -+ "busy\n", enab, i); -+ return -EBUSY; -+ } -+ -+ dt_dbg_enable(" Matching enabling %p[%d] found %d matches.\n", -+ enab, i, matched); -+ -+ total_matched += matched; -+ -+ if (enab->dten_error != 0) { -+ if (nmatched == NULL) -+ pr_warn("%s error on %p: %d\n", __func__, -+ (void *)ep, enab->dten_error); -+ -+ return enab->dten_error; -+ } -+ } -+ -+ enab->dten_probegen = dtrace_probegen; -+ if (nmatched != NULL) -+ *nmatched = total_matched; -+ -+ return 0; -+} -+ -+void dtrace_enabling_matchall(void) -+{ -+ struct dtrace_enabling *enab; -+ -+ mutex_lock(&cpu_lock); -+ mutex_lock(&dtrace_lock); -+ -+ for (enab = dtrace_retained; enab != NULL; enab = enab->dten_next) -+ (void) dtrace_enabling_match(enab, NULL); -+ -+ mutex_unlock(&dtrace_lock); -+ mutex_unlock(&cpu_lock); -+} -+ -+/* -+ * If an enabling is to be enabled without having matched probes (that is, if -+ * dtrace_state_go() is to be called on the underlying dtrace_state_t), the -+ * enabling must be _primed_ by creating an ECB for every ECB description. -+ * This must be done to assure that we know the number of speculations, the -+ * number of aggregations, the minimum buffer size needed, etc. before we -+ * transition out of DTRACE_ACTIVITY_INACTIVE. To do this without actually -+ * enabling any probes, we create ECBs for every ECB description, but with a -+ * NULL probe -- which is exactly what this function does. -+ */ -+void dtrace_enabling_prime(struct dtrace_state *state) -+{ -+ struct dtrace_enabling *enab; -+ int i; -+ -+ for (enab = dtrace_retained; enab != NULL; enab = enab->dten_next) { -+ ASSERT(enab->dten_vstate->dtvs_state != NULL); -+ -+ if (enab->dten_vstate->dtvs_state != state) -+ continue; -+ -+ /* -+ * We don't want to prime an enabling more than once, lest -+ * we allow a malicious user to induce resource exhaustion. -+ * (The ECBs that result from priming an enabling aren't -+ * leaked -- but they also aren't deallocated until the -+ * consumer state is destroyed.) -+ */ -+ if (enab->dten_primed) -+ continue; -+ -+ for (i = 0; i < enab->dten_ndesc; i++) { -+ enab->dten_current = enab->dten_desc[i]; -+ dtrace_probe_enable(NULL, enab); -+ } -+ -+ enab->dten_primed = 1; -+ } -+} -+ -+void dtrace_enabling_provide(struct dtrace_provider *prv) -+{ -+ int all = 0; -+ dtrace_genid_t gen; -+ -+ if (prv == NULL) { -+ all = 1; -+ prv = dtrace_provider; -+ } -+ -+ do { -+ struct dtrace_enabling *enab; -+ void *parg = prv->dtpv_arg; -+ -+retry: -+ gen = dtrace_retained_gen; -+ for (enab = dtrace_retained; enab != NULL; -+ enab = enab->dten_next) { -+ int i; -+ -+ for (i = 0; i < enab->dten_ndesc; i++) { -+ struct dtrace_probedesc desc; -+ -+ desc = enab->dten_desc[i]->dted_probe; -+ mutex_unlock(&dtrace_lock); -+ prv->dtpv_pops.dtps_provide(parg, &desc); -+ mutex_lock(&dtrace_lock); -+ -+ if (gen != dtrace_retained_gen) -+ goto retry; -+ } -+ } -+ } while (all && (prv = prv->dtpv_next) != NULL); -+ -+ mutex_unlock(&dtrace_lock); -+ dtrace_probe_provide(NULL, all ? NULL : prv); -+ mutex_lock(&dtrace_lock); -+} -diff --git a/dtrace/dtrace_fmt.c b/dtrace/dtrace_fmt.c -new file mode 100644 -index 000000000000..78fcc8e6efb8 ---- /dev/null -+++ b/dtrace/dtrace_fmt.c -@@ -0,0 +1,104 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_fmt.c -+ * DESCRIPTION: DTrace - format string implementation -+ * -+ * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/slab.h> -+#include <linux/vmalloc.h> -+ -+#include "dtrace.h" -+ -+uint16_t dtrace_format_add(struct dtrace_state *state, char *str) -+{ -+ char *fmt, **new; -+ uint16_t ndx; -+ -+ fmt = dtrace_strdup(str); -+ if (fmt == NULL) -+ return 0; -+ -+ for (ndx = 0; ndx < state->dts_nformats; ndx++) { -+ if (state->dts_formats[ndx] == NULL) { -+ state->dts_formats[ndx] = fmt; -+ -+ return ndx + 1; -+ } -+ } -+ -+ if (state->dts_nformats == UINT16_MAX) { -+ kfree(fmt); -+ -+ return 0; -+ } -+ -+ ndx = state->dts_nformats; -+ new = vmalloc((ndx + 1) * sizeof(char *)); -+ if (new == NULL) { -+ kfree(fmt); -+ return 0; -+ } -+ -+ state->dts_nformats++; -+ -+ if (state->dts_formats != NULL) { -+ ASSERT(ndx != 0); -+ memcpy(new, state->dts_formats, ndx * sizeof(char *)); -+ vfree(state->dts_formats); -+ } -+ -+ state->dts_formats = new; -+ state->dts_formats[ndx] = fmt; -+ -+ return ndx + 1; -+} -+ -+void dtrace_format_remove(struct dtrace_state *state, uint16_t format) -+{ -+ char *fmt; -+ -+ ASSERT(state->dts_formats != NULL); -+ ASSERT(format <= state->dts_nformats); -+ ASSERT(state->dts_formats[format - 1] != NULL); -+ -+ fmt = state->dts_formats[format - 1]; -+ kfree(fmt); -+ state->dts_formats[format - 1] = NULL; -+} -+ -+void dtrace_format_destroy(struct dtrace_state *state) -+{ -+ int i; -+ -+ if (state->dts_nformats == 0) { -+ ASSERT(state->dts_formats == NULL); -+ return; -+ } -+ -+ ASSERT(state->dts_formats != NULL); -+ -+ for (i = 0; i < state->dts_nformats; i++) { -+ char *fmt = state->dts_formats[i]; -+ -+ if (fmt == NULL) -+ continue; -+ -+ kfree(fmt); -+ } -+ -+ vfree(state->dts_formats); -+ state->dts_nformats = 0; -+ state->dts_formats = NULL; -+} -diff --git a/dtrace/dtrace_hash.c b/dtrace/dtrace_hash.c -new file mode 100644 -index 000000000000..0773c60e7897 ---- /dev/null -+++ b/dtrace/dtrace_hash.c -@@ -0,0 +1,266 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_hash.c -+ * DESCRIPTION: DTrace - hash table implementation -+ * -+ * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/slab.h> -+#include <linux/vmalloc.h> -+ -+#include "dtrace.h" -+ -+#define DTRACE_HASHSTR(hash, probe) \ -+ dtrace_hash_str(*((char **)((uintptr_t)(probe) + (hash)->dth_stroffs))) -+#define DTRACE_HASHEQ(hash, lhs, rhs) \ -+ (strcmp(*((char **)((uintptr_t)(lhs) + (hash)->dth_stroffs)), \ -+ *((char **)((uintptr_t)(rhs) + (hash)->dth_stroffs))) == 0) -+ -+static uint_t dtrace_hash_str(char *p) -+{ -+ uint_t g; -+ uint_t hval = 0; -+ -+ while (*p) { -+ hval = (hval << 4) + *p++; -+ g = hval & 0xf0000000; -+ if (g != 0) -+ hval ^= g >> 24; -+ -+ hval &= ~g; -+ } -+ -+ return hval; -+} -+ -+struct dtrace_hash *dtrace_hash_create(uintptr_t stroffs, uintptr_t nextoffs, -+ uintptr_t prevoffs) -+{ -+ struct dtrace_hash *hash; -+ -+ hash = kzalloc(sizeof(struct dtrace_hash), GFP_KERNEL); -+ if (hash == NULL) -+ return NULL; -+ -+ hash->dth_stroffs = stroffs; -+ hash->dth_nextoffs = nextoffs; -+ hash->dth_prevoffs = prevoffs; -+ -+ hash->dth_size = 1; -+ hash->dth_mask = hash->dth_size - 1; -+ -+ hash->dth_tab = vzalloc(hash->dth_size * -+ sizeof(struct dtrace_hashbucket *)); -+ -+ if (hash->dth_tab == NULL) { -+ kfree(hash); -+ return NULL; -+ } -+ -+ return hash; -+} -+ -+void dtrace_hash_destroy(struct dtrace_hash *hash) -+{ -+#ifdef DEBUG -+ int i; -+ -+ for (i = 0; i < hash->dth_size; i++) -+ ASSERT(hash->dth_tab[i] == NULL); -+#endif -+ -+ if (hash == NULL) -+ return; -+ -+ vfree(hash->dth_tab); -+ kfree(hash); -+} -+ -+static int dtrace_hash_resize(struct dtrace_hash *hash) -+{ -+ int size = hash->dth_size, i, ndx; -+ int new_size = hash->dth_size << 1; -+ int new_mask = new_size - 1; -+ struct dtrace_hashbucket **new_tab, *bucket, *next; -+ -+ ASSERT((new_size & new_mask) == 0); -+ -+ new_tab = vzalloc(new_size * sizeof(void *)); -+ if (new_tab == NULL) -+ return -ENOMEM; -+ -+ for (i = 0; i < size; i++) { -+ for (bucket = hash->dth_tab[i]; bucket != NULL; -+ bucket = next) { -+ struct dtrace_probe *probe = bucket->dthb_chain; -+ -+ ASSERT(probe != NULL); -+ ndx = DTRACE_HASHSTR(hash, probe) & new_mask; -+ -+ next = bucket->dthb_next; -+ bucket->dthb_next = new_tab[ndx]; -+ new_tab[ndx] = bucket; -+ } -+ } -+ -+ vfree(hash->dth_tab); -+ hash->dth_tab = new_tab; -+ hash->dth_size = new_size; -+ hash->dth_mask = new_mask; -+ -+ return 0; -+} -+ -+int dtrace_hash_add(struct dtrace_hash *hash, struct dtrace_probe *new) -+{ -+ int hashval = DTRACE_HASHSTR(hash, new); -+ int ndx = hashval & hash->dth_mask; -+ struct dtrace_hashbucket *bucket = hash->dth_tab[ndx]; -+ struct dtrace_probe **nextp, **prevp; -+ -+ for (; bucket != NULL; bucket = bucket->dthb_next) { -+ if (DTRACE_HASHEQ(hash, bucket->dthb_chain, new)) -+ goto add; -+ } -+ -+ if ((hash->dth_nbuckets >> 1) > hash->dth_size) { -+ int err = 0; -+ -+ err = dtrace_hash_resize(hash); -+ if (err != 0) -+ return err; -+ -+ dtrace_hash_add(hash, new); -+ return 0; -+ } -+ -+ bucket = kzalloc(sizeof(struct dtrace_hashbucket), GFP_KERNEL); -+ if (bucket == NULL) -+ return -ENOMEM; -+ -+ bucket->dthb_next = hash->dth_tab[ndx]; -+ hash->dth_tab[ndx] = bucket; -+ hash->dth_nbuckets++; -+ -+add: -+ nextp = DTRACE_HASHNEXT(hash, new); -+ -+ ASSERT(*nextp == NULL && *(DTRACE_HASHPREV(hash, new)) == NULL); -+ -+ *nextp = bucket->dthb_chain; -+ -+ if (bucket->dthb_chain != NULL) { -+ prevp = DTRACE_HASHPREV(hash, bucket->dthb_chain); -+ -+ ASSERT(*prevp == NULL); -+ -+ *prevp = new; -+ } -+ -+ bucket->dthb_chain = new; -+ bucket->dthb_len++; -+ -+ return 0; -+} -+ -+struct dtrace_probe *dtrace_hash_lookup(struct dtrace_hash *hash, -+ struct dtrace_probe *template) -+{ -+ int hashval = DTRACE_HASHSTR(hash, template); -+ int ndx = hashval & hash->dth_mask; -+ -+ struct dtrace_hashbucket *bucket = hash->dth_tab[ndx]; -+ -+ for (; bucket != NULL; bucket = bucket->dthb_next) { -+ if (DTRACE_HASHEQ(hash, bucket->dthb_chain, template)) -+ return bucket->dthb_chain; -+ } -+ -+ return NULL; -+} -+ -+/* -+ * FIXME: -+ * It would be more accurate to calculate a lookup cost based on the number -+ * of buckets in the hash table slot, the length of the chain, and the length -+ * of the string being looked up. -+ * The hash tables can also be optimized by storing the hashval in each element -+ * rather than always performing string comparisons. -+ */ -+int dtrace_hash_collisions(struct dtrace_hash *hash, -+ struct dtrace_probe *template) -+{ -+ int hashval = DTRACE_HASHSTR(hash, template); -+ int ndx = hashval & hash->dth_mask; -+ -+ struct dtrace_hashbucket *bucket = hash->dth_tab[ndx]; -+ -+ for (; bucket != NULL; bucket = bucket->dthb_next) { -+ if (DTRACE_HASHEQ(hash, bucket->dthb_chain, template)) -+ return bucket->dthb_len; -+ } -+ -+ return 0; -+} -+ -+void dtrace_hash_remove(struct dtrace_hash *hash, struct dtrace_probe *probe) -+{ -+ int ndx = DTRACE_HASHSTR(hash, probe) & hash->dth_mask; -+ -+ struct dtrace_hashbucket *bucket = hash->dth_tab[ndx]; -+ struct dtrace_probe **prevp = DTRACE_HASHPREV(hash, probe); -+ struct dtrace_probe **nextp = DTRACE_HASHNEXT(hash, probe); -+ -+ for (; bucket != NULL; bucket = bucket->dthb_next) { -+ if (DTRACE_HASHEQ(hash, bucket->dthb_chain, probe)) -+ break; -+ } -+ -+ ASSERT(bucket != NULL); -+ -+ if (*prevp == NULL) { -+ if (*nextp == NULL) { -+ /* -+ * This is the last probe in the bucket; we can remove -+ * the bucket. -+ */ -+ struct dtrace_hashbucket *b = hash->dth_tab[ndx]; -+ -+ ASSERT(bucket->dthb_chain == probe); -+ ASSERT(b != NULL); -+ -+ if (b == bucket) -+ hash->dth_tab[ndx] = bucket->dthb_next; -+ else { -+ while (b->dthb_next != bucket) -+ b = b->dthb_next; -+ -+ b->dthb_next = bucket->dthb_next; -+ } -+ -+ ASSERT(hash->dth_nbuckets > 0); -+ -+ hash->dth_nbuckets--; -+ kfree(bucket); -+ -+ return; -+ } -+ -+ bucket->dthb_chain = *nextp; -+ } else -+ *(DTRACE_HASHNEXT(hash, *prevp)) = *nextp; -+ -+ if (*nextp != NULL) -+ *(DTRACE_HASHPREV(hash, *nextp)) = *prevp; -+} -diff --git a/dtrace/dtrace_isa.c b/dtrace/dtrace_isa.c -new file mode 100644 -index 000000000000..f84ce1cd52cc ---- /dev/null -+++ b/dtrace/dtrace_isa.c -@@ -0,0 +1,361 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_isa.c -+ * DESCRIPTION: DTrace - architecture specific code -+ * -+ * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/dtrace_cpu.h> -+#include <linux/dtrace_task_impl.h> -+#include <linux/hardirq.h> -+#include <linux/mm.h> -+#include <linux/smp.h> -+#include <linux/uaccess.h> -+#include <linux/cpumask.h> -+#include <asm/cacheflush.h> -+#include <asm/ptrace.h> -+#include <asm/stacktrace.h> -+ -+#include "dtrace.h" -+ -+DEFINE_MUTEX(cpu_lock); -+EXPORT_SYMBOL(cpu_lock); -+ -+int dtrace_getipl(void) -+{ -+ return in_interrupt(); -+} -+ -+void dtrace_xcall(processorid_t cpu, dtrace_xcall_t func, void *arg) -+{ -+ if (cpu == DTRACE_CPUALL) -+ smp_call_function(func, arg, 1); -+ else -+ smp_call_function_single(cpu, func, arg, 1); -+} -+ -+void dtrace_toxic_ranges(void (*func)(uintptr_t, uintptr_t)) -+{ -+ /* FIXME */ -+} -+ -+/* -+ * Note: not called from probe context. This function is called -+ * asynchronously (and at a regular interval) from outside of probe context -+ * by the DTrace framework to sync shared data which DTrace probe context -+ * may access without locks. -+ * -+ * Whenever the framework updates data which can be accessed from probe context, -+ * the framework then calls dtrace_sync(). dtrace_sync() guarantees all probes -+ * are using the new data before returning. -+ * -+ * See the comment in dtrace_impl.h which describes this algorithm. -+ * The cpuc_in_probe_ctxt flag is an increasing 16-bit count. It is odd when -+ * in DTrace probe context and even when not in DTrace probe context. -+ * The upper 15 bits are a counter which are incremented when exiting DTrace -+ * probe context. These upper 15 bits are used to detect "sample aliasing": -+ * i.e. the target CPU is not in DTrace probe context between samples but -+ * continually enters probe context just before being sampled. -+ * -+ * dtrace_sync() loops over NCPUs. CPUs which are not in DTrace probe context -+ * (cpuc_in_probe_ctxt is even) are removed from the list. This is repeated -+ * until there are no CPUs left in the sync list. -+ * -+ * In the rare cases where dtrace_sync() loops over all NCPUs more than -+ * dtrace_sync_sample_count times, dtrace_sync() then spins on one CPU's -+ * cpuc_in_probe_ctxt count until the count increments. This is intended to -+ * avoid sample aliasing. -+ */ -+void dtrace_sync(void) -+{ -+ /* -+ * sync_cpus is a bitmap of CPUs that need to be synced with. -+ */ -+ cpumask_t sync_cpus; -+ uint64_t sample_count = 0; -+ int cpuid, sample_cpuid = 0; -+ int outstanding; -+ -+ /* -+ * Create bitmap of CPUs that need to be synced with. -+ */ -+ cpumask_copy(&sync_cpus, cpu_online_mask); -+ outstanding = 0; -+ for_each_cpu(cpuid, &sync_cpus) { -+ ++outstanding; -+ -+ /* -+ * Set a flag to let the CPU know we are syncing with it. -+ */ -+ DTRACE_SYNC_START(cpuid); -+ } -+ -+ /* -+ * The preceding stores by DTRACE_SYNC_START() must complete before -+ * subsequent loads or stores. No membar is needed because the -+ * atomic-add operation in DTRACE_SYNC_START is a memory barrier on -+ * SPARC and X86. -+ */ -+ -+ while (outstanding > 0) { -+ /* -+ * Loop over the map of CPUs that need to be synced with. -+ */ -+ for_each_cpu(cpuid, &sync_cpus) { -+ if (!DTRACE_SYNC_IN_CRITICAL(cpuid)) { -+ -+ /* Clear the CPU's sync request flag */ -+ DTRACE_SYNC_END(cpuid); -+ -+ /* -+ * remove cpuid from list of CPUs that -+ * still need to be synced with. -+ */ -+ DTRACE_SYNC_DONE(cpuid, &sync_cpus); -+ --outstanding; -+ } else { -+ /* -+ * Remember one of the outstanding CPUs to spin -+ * on once we reach the sampling limit. -+ */ -+ sample_cpuid = cpuid; -+ } -+ } -+ -+ /* -+ * dtrace_probe may be running in sibling threads in this core. -+ */ -+ if (outstanding > 0) { -+ dtrace_safe_smt_pause(); -+ -+ /* -+ * After sample_count loops, spin on one CPU's count -+ * instead of just checking for odd/even. -+ */ -+ if (++sample_count > dtrace_sync_sample_count) { -+ uint64_t count = -+ DTRACE_SYNC_CRITICAL_COUNT(sample_cpuid); -+ -+ /* -+ * Spin until critical section count increments. -+ */ -+ if (DTRACE_SYNC_IN_CRITICAL(sample_cpuid)) { -+ while (count == -+ DTRACE_SYNC_CRITICAL_COUNT( -+ sample_cpuid)) { -+ -+ dtrace_safe_smt_pause(); -+ } -+ } -+ -+ DTRACE_SYNC_END(sample_cpuid); -+ DTRACE_SYNC_DONE(sample_cpuid, &sync_cpus); -+ --outstanding; -+ } -+ } -+ } -+ -+/* -+ * All preceding loads by DTRACE_SYNC_IN_CRITICAL() and -+ * DTRACE_SYNC_CRITICAL_COUNT() must complete before subsequent loads -+ * or stores. No membar is needed because the atomic-add operation in -+ * DTRACE_SYNC_END() is a memory barrier on SPARC and X86. -+ */ -+} -+ -+/* -+ * Handle a few special cases where we store information in kernel memory that -+ * in other systems is typically found in userspace. -+ */ -+static int dtrace_fake_copyin(intptr_t addr, size_t size) -+{ -+ struct dtrace_psinfo *psinfo; -+ uintptr_t argv; -+ unsigned long argc; -+ uintptr_t envp; -+ unsigned long envc; -+ -+ if (current->dt_task == NULL) -+ return 0; -+ -+ psinfo = current->dt_task->dt_psinfo; -+ if (psinfo == NULL) -+ return 0; -+ -+ argv = (uintptr_t)psinfo->dtps_argv; -+ argc = psinfo->dtps_argc; -+ envp = (uintptr_t)psinfo->dtps_envp; -+ envc = psinfo->dtps_envc; -+ -+ /* -+ * Ensure addr is within the argv array (or the envp array): -+ * addr in [argv..argv + argc * sizeof(psinfo->argv[0])[ -+ * Ensure that addr + size is within the same array -+ * addr + size in [argv..argv * sizeof(psinfo->argv[0])] -+ * -+ * To guard against overflows on (addr + size) we rewrite this basic -+ * equation: -+ * addr + size <= argv + argc * sizeof(psinfo->argv[0]) -+ * into: -+ * addr - argv <= argc * sizeof(psinfo->argv[0]) - size -+ */ -+ return (addr >= argv && -+ addr - argv < argc * sizeof(psinfo->dtps_argv[0]) && -+ addr - argv <= argc * sizeof(psinfo->dtps_argv[0]) - size) || -+ (addr >= envp && -+ addr - envp < envc * sizeof(psinfo->dtps_envp[0]) && -+ addr - envp <= envc * sizeof(psinfo->dtps_envp[0]) - size); -+} -+ -+void dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size, -+ volatile uint16_t *flags) -+{ -+ if (dtrace_fake_copyin(uaddr, size)) { -+ memcpy((char *)kaddr, (char *)uaddr, size); -+ return; -+ } -+ -+ dtrace_copyin_arch(uaddr, kaddr, size, flags); -+} -+ -+void dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size, -+ volatile uint16_t *flags) -+{ -+ if (dtrace_fake_copyin(uaddr, size)) { -+ strncpy((char *)kaddr, (char *)uaddr, -+ min(size, (size_t)PR_PSARGS_SZ)); -+ return; -+ } -+ -+ dtrace_copyinstr_arch(uaddr, kaddr, size, flags); -+} -+ -+/* -+ * FIXME: aframes + 3 should really be aframes + 1, dtrace_stacktrace() in the -+ * kernel should do its own aframes + 2 -+ */ -+void dtrace_getpcstack(uint64_t *pcstack, int pcstack_limit, int aframes, -+ uint32_t *intrpc) -+{ -+ struct stacktrace_state st = { -+ pcstack, -+ NULL, -+ pcstack_limit, -+ aframes + 3, -+ STACKTRACE_KERNEL -+ }; -+ -+ dtrace_stacktrace(&st); -+ -+ while (st.depth < st.limit) -+ pcstack[st.depth++] = 0; -+} -+EXPORT_SYMBOL(dtrace_getpcstack); -+ -+/* -+ * Get user stack entries up to the pcstack_limit; return the number of entries -+ * acquired. If pcstack is NULL, return the number of entries potentially -+ * acquirable. -+ */ -+unsigned long dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, -+ int pcstack_limit) -+{ -+ struct task_struct *p = current; -+ struct stacktrace_state st; -+ unsigned long depth; -+ -+ if (pcstack) { -+ if (unlikely(pcstack_limit < 2)) { -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); -+ return 0; -+ } -+ *pcstack++ = (uint64_t)p->pid; -+ *pcstack++ = (uint64_t)p->tgid; -+ pcstack_limit -= 2; -+ } -+ -+ st.pcs = pcstack; -+ st.fps = fpstack; -+ st.limit = pcstack_limit; -+ st.depth = 0; -+ st.flags = STACKTRACE_USER; -+ -+ dtrace_stacktrace(&st); -+ -+ depth = st.depth; -+ if (pcstack) { -+ while (st.depth < st.limit) { -+ pcstack[st.depth++] = 0; -+ if (fpstack) -+ fpstack[st.depth++] = 0; -+ } -+ } -+ -+ return depth; -+} -+ -+void dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit) -+{ -+ dtrace_getufpstack(pcstack, NULL, pcstack_limit); -+} -+ -+/* -+ * FIXME: aframes + 3 should really be aframes + 1, dtrace_stacktrace() in the -+ * kernel should do its own aframes + 2 -+ */ -+int dtrace_getstackdepth(struct dtrace_mstate *mstate, int aframes) -+{ -+ uintptr_t old = mstate->dtms_scratch_ptr; -+ struct stacktrace_state st = { -+ NULL, -+ NULL, -+ 0, -+ aframes + 3, -+ STACKTRACE_KERNEL -+ }; -+ -+ st.pcs = (uint64_t *)ALIGN(old, 8); -+ if ((uintptr_t)st.pcs > -+ mstate->dtms_scratch_base + mstate->dtms_scratch_size) { -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); -+ return 0; -+ } -+ -+ /* -+ * Calculate how many (64-bit) PCs we can fit in the remaining scratch -+ * memory. -+ */ -+ st.limit = (mstate->dtms_scratch_base + mstate->dtms_scratch_size - -+ (uintptr_t)st.pcs) >> 3; -+ -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); -+ dtrace_stacktrace(&st); -+ DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); -+ -+ mstate->dtms_scratch_ptr = old; -+ -+ return st.depth; -+} -+ -+int dtrace_getustackdepth(void) -+{ -+ return dtrace_getufpstack(NULL, NULL, INT_MAX); -+} -+ -+void dtrace_probe_error(struct dtrace_state *state, dtrace_epid_t epid, -+ int act, int fltoffs, int flags, uintptr_t addr) -+{ -+ dtrace_probe(dtrace_probeid_error, (uintptr_t)state, epid, act, -+ fltoffs, flags, addr, 0); -+} -diff --git a/dtrace/dtrace_match.c b/dtrace/dtrace_match.c -new file mode 100644 -index 000000000000..a63e3f8be1cd ---- /dev/null -+++ b/dtrace/dtrace_match.c -@@ -0,0 +1,364 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_match.c -+ * DESCRIPTION: DTrace - probe match implementation -+ * -+ * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include "dtrace.h" -+ -+struct dtrace_hash *dtrace_bymod; -+struct dtrace_hash *dtrace_byfunc; -+struct dtrace_hash *dtrace_byname; -+ -+int dtrace_match_priv(const struct dtrace_probe *prp, uint32_t priv, -+ kuid_t uid) -+{ -+ if (priv != DTRACE_PRIV_ALL) { -+ uint32_t ppriv = -+ prp->dtpr_provider->dtpv_priv.dtpp_flags; -+ uint32_t match = priv & ppriv; -+ -+ if ((priv & (DTRACE_PRIV_PROC | DTRACE_PRIV_USER | -+ DTRACE_PRIV_KERNEL)) == 0) -+ return 0; -+ -+ if (match == 0 && ppriv != 0) -+ return 0; -+ -+ if (((ppriv & ~match) & DTRACE_PRIV_OWNER) != 0 && -+ !uid_eq(uid, make_kuid(init_user_namespace, -+ prp->dtpr_provider->dtpv_priv.dtpp_uid))) -+ return 0; -+ } -+ -+ return 1; -+} -+ -+int dtrace_match_probe(const struct dtrace_probe *prp, -+ const struct dtrace_probekey *pkp, -+ uint32_t priv, kuid_t uid) -+{ -+ struct dtrace_provider *pvp = prp->dtpr_provider; -+ int rv; -+ -+ if (pvp->dtpv_defunct) -+ return 0; -+ -+ rv = pkp->dtpk_pmatch(pvp->dtpv_name, pkp->dtpk_prov, 0); -+ if (rv <= 0) -+ return rv; -+ -+ rv = pkp->dtpk_mmatch(prp->dtpr_mod, pkp->dtpk_mod, 0); -+ if (rv <= 0) -+ return rv; -+ -+ rv = pkp->dtpk_fmatch(prp->dtpr_func, pkp->dtpk_func, 0); -+ if (rv <= 0) -+ return rv; -+ -+ rv = pkp->dtpk_nmatch(prp->dtpr_name, pkp->dtpk_name, 0); -+ if (rv <= 0) -+ return rv; -+ -+ if (dtrace_match_priv(prp, priv, uid) == 0) -+ return 0; -+ -+ return rv; -+} -+ -+int dtrace_match_glob(const char *s, const char *p, int depth) -+{ -+ const char *olds; -+ char s1, c; -+ int gs; -+ -+ if (depth > DTRACE_PROBEKEY_MAXDEPTH) -+ return -1; -+ -+ if (s == NULL) -+ s = ""; -+ -+top: -+ olds = s; -+ s1 = *s++; -+ -+ if (p == NULL) -+ return 0; -+ -+ c = *p++; -+ if (c == '\0') -+ return s1 == '\0'; -+ -+ switch (c) { -+ case '[': -+ { -+ int ok = 0, notflag = 0; -+ char lc = '\0'; -+ -+ if (s1 == '\0') -+ return 0; -+ -+ if (*p == '!') { -+ notflag = 1; -+ p++; -+ } -+ -+ c = *p++; -+ if (c == '\0') -+ return 0; -+ -+ do { -+ if (c == '-' && lc != '\0' && *p != ']') { -+ c = *p++; -+ if (c == '\0') -+ return 0; -+ if (c == '\\') { -+ c = *p++; -+ if (c == '\0') -+ return 0; -+ } -+ if (notflag) { -+ if (s1 < lc || s1 > c) -+ ok++; -+ else -+ return 0; -+ } else if (lc <= s1 && s1 <= c) -+ ok++; -+ } else if (c == '\\') { -+ c = *p++; -+ if (c == '\0') -+ return 0; -+ } -+ lc = c; -+ -+ if (notflag) { -+ if (s1 != c) -+ ok++; -+ else -+ return 0; -+ } else if (s1 == c) -+ ok++; -+ -+ c = *p++; -+ if (c == '\0') -+ return 0; -+ } while (c != ']'); -+ -+ if (ok) -+ goto top; -+ -+ return 0; -+ } -+ -+ case '\\': -+ c = *p++; -+ if (c == '\0') -+ return 0; -+ /* fallthru */ -+ default: -+ if (c != s1) -+ return 0; -+ /* fallthru */ -+ -+ case '?': -+ if (s1 != '\0') -+ goto top; -+ -+ return 0; -+ -+ case '*': -+ while (*p == '*') -+ p++; -+ -+ if (*p == '\0') -+ return 1; -+ -+ for (s = olds; *s != '\0'; s++) { -+ gs = dtrace_match_glob(s, p, depth + 1); -+ if (gs != 0) -+ return gs; -+ } -+ -+ return 0; -+ } -+} -+ -+int dtrace_match_string(const char *s, const char *p, int depth) -+{ -+ return s != NULL && strcmp(s, p) == 0; -+} -+ -+int dtrace_match_nul(const char *s, const char *p, int depth) -+{ -+ return 1; -+} -+ -+int dtrace_match_nonzero(const char *s, const char *p, int depth) -+{ -+ return s != NULL && s[0] != '\0'; -+} -+ -+struct probe_match { -+ const struct dtrace_probekey *pkp; -+ uint32_t priv; -+ kuid_t uid; -+ int (*matched)(struct dtrace_probe *, void *); -+ void *arg; -+ int nmatched; -+}; -+ -+static int dtrace_match_one(int id, void *p, void *data) -+{ -+ struct probe_match *pbm = (struct probe_match *)data; -+ struct dtrace_probe *probe = (struct dtrace_probe *)p; -+ int rc; -+ -+ if (dtrace_match_probe(probe, pbm->pkp, pbm->priv, pbm->uid) <= 0) -+ return 0; -+ -+ pbm->nmatched++; -+ -+ rc = (pbm->matched)(probe, pbm->arg); -+ if (rc != DTRACE_MATCH_NEXT) { -+ if (rc == DTRACE_MATCH_FAIL) -+ return DTRACE_MATCH_FAIL; -+ } -+ -+ return 0; -+} -+ -+int dtrace_match(const struct dtrace_probekey *pkp, uint32_t priv, kuid_t uid, -+ int (*matched)(struct dtrace_probe *, void *), void *arg) -+{ -+ struct dtrace_probe template, *probe; -+ struct dtrace_hash *hash = NULL; -+ int len, rc, best = INT_MAX, nmatched = 0; -+ -+ if (pkp->dtpk_id != DTRACE_IDNONE) { -+ probe = dtrace_probe_lookup_id(pkp->dtpk_id); -+ if (probe != NULL && -+ dtrace_match_probe(probe, pkp, priv, uid) > 0) { -+ if ((*matched)(probe, arg) == DTRACE_MATCH_FAIL) -+ return DTRACE_MATCH_FAIL; -+ -+ nmatched++; -+ } -+ -+ return nmatched; -+ } -+ -+ template.dtpr_mod = (char *)pkp->dtpk_mod; -+ template.dtpr_func = (char *)pkp->dtpk_func; -+ template.dtpr_name = (char *)pkp->dtpk_name; -+ -+ if (pkp->dtpk_mmatch == &dtrace_match_string) { -+ len = dtrace_hash_collisions(dtrace_bymod, &template); -+ if (len < best) { -+ best = len; -+ hash = dtrace_bymod; -+ } -+ } -+ -+ if (pkp->dtpk_fmatch == &dtrace_match_string) { -+ len = dtrace_hash_collisions(dtrace_byfunc, &template); -+ if (len < best) { -+ best = len; -+ hash = dtrace_byfunc; -+ } -+ } -+ -+ if (pkp->dtpk_nmatch == &dtrace_match_string) { -+ len = dtrace_hash_collisions(dtrace_byname, &template); -+ if (len < best) { -+ best = len; -+ hash = dtrace_byname; -+ } -+ } -+ -+ if (hash == NULL) { -+ struct probe_match pbm; -+ -+ pbm.pkp = pkp; -+ pbm.priv = priv; -+ pbm.uid = uid; -+ pbm.matched = matched; -+ pbm.arg = arg; -+ pbm.nmatched = 0; -+ -+ rc = dtrace_probe_for_each(dtrace_match_one, &pbm); -+ if (rc == DTRACE_MATCH_FAIL) -+ return DTRACE_MATCH_FAIL; -+ -+ return pbm.nmatched; -+ } -+ -+ for (probe = dtrace_hash_lookup(hash, &template); probe != NULL; -+ probe = *(DTRACE_HASHNEXT(hash, probe))) { -+ if (dtrace_match_probe(probe, pkp, priv, uid) <= 0) -+ continue; -+ -+ nmatched++; -+ -+ rc = (*matched)(probe, arg); -+ if (rc != DTRACE_MATCH_NEXT) { -+ if (rc == DTRACE_MATCH_FAIL) -+ return DTRACE_MATCH_FAIL; -+ -+ break; -+ } -+ } -+ -+ return nmatched; -+} -+ -+static dtrace_probekey_f *dtrace_probekey_func(const char *p) -+{ -+ char c; -+ -+ if (p == NULL || *p == '\0') -+ return &dtrace_match_nul; -+ -+ while ((c = *p++) != '\0') { -+ if (c == '[' || c == '?' || c == '*' || c == '\\') -+ return &dtrace_match_glob; -+ } -+ -+ return &dtrace_match_string; -+} -+ -+void dtrace_probekey(const struct dtrace_probedesc *pdp, -+ struct dtrace_probekey *pkp) -+{ -+ pkp->dtpk_prov = pdp->dtpd_provider; -+ pkp->dtpk_pmatch = dtrace_probekey_func(pdp->dtpd_provider); -+ -+ pkp->dtpk_mod = pdp->dtpd_mod; -+ pkp->dtpk_mmatch = dtrace_probekey_func(pdp->dtpd_mod); -+ -+ pkp->dtpk_func = pdp->dtpd_func; -+ pkp->dtpk_fmatch = dtrace_probekey_func(pdp->dtpd_func); -+ -+ pkp->dtpk_name = pdp->dtpd_name; -+ pkp->dtpk_nmatch = dtrace_probekey_func(pdp->dtpd_name); -+ -+ pkp->dtpk_id = pdp->dtpd_id; -+ -+ if (pkp->dtpk_id == DTRACE_IDNONE && -+ pkp->dtpk_pmatch == &dtrace_match_nul && -+ pkp->dtpk_mmatch == &dtrace_match_nul && -+ pkp->dtpk_fmatch == &dtrace_match_nul && -+ pkp->dtpk_nmatch == &dtrace_match_nul) -+ pkp->dtpk_fmatch = &dtrace_match_nonzero; -+} -diff --git a/dtrace/dtrace_mod.c b/dtrace/dtrace_mod.c -new file mode 100644 -index 000000000000..4da08c3cd816 ---- /dev/null -+++ b/dtrace/dtrace_mod.c -@@ -0,0 +1,45 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_mod.c -+ * DESCRIPTION: DTrace - framework kernel module -+ * -+ * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/module.h> -+ -+#include "dtrace_dev.h" -+ -+MODULE_AUTHOR("Kris Van Hees (kris.van.hees@oracle.com)"); -+MODULE_DESCRIPTION("Dynamic Tracing"); -+MODULE_VERSION("v0.1"); -+MODULE_LICENSE("GPL"); -+ -+/* -+ * Initialize the module. -+ */ -+static int __init dtrace_init(void) -+{ -+ return dtrace_dev_init(); -+} -+ -+/* -+ * Perform cleanup before the module is removed. -+ */ -+static void __exit dtrace_exit(void) -+{ -+ dtrace_dev_exit(); -+} -+ -+module_init(dtrace_init); -+module_exit(dtrace_exit); -diff --git a/dtrace/dtrace_predicate.c b/dtrace/dtrace_predicate.c -new file mode 100644 -index 000000000000..004a1c542c76 ---- /dev/null -+++ b/dtrace/dtrace_predicate.c -@@ -0,0 +1,80 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_predicate.c -+ * DESCRIPTION: DTrace - predicate cache implementation -+ * -+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/slab.h> -+ -+#include "dtrace.h" -+ -+static dtrace_cacheid_t dtrace_predcache_id = DTRACE_CACHEIDNONE + 1; -+ -+struct dtrace_predicate *dtrace_predicate_create(struct dtrace_difo *dp) -+{ -+ struct dtrace_predicate *pred; -+ -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ ASSERT(dp->dtdo_refcnt != 0); -+ -+ pred = kzalloc(sizeof(struct dtrace_predicate), GFP_KERNEL); -+ if (pred == NULL) -+ return NULL; -+ -+ pred->dtp_difo = dp; -+ pred->dtp_refcnt = 1; -+ -+ if (!dtrace_difo_cacheable(dp)) -+ return pred; -+ -+ /* -+ * This is only theoretically possible -- we have had 2^32 cacheable -+ * predicates on this machine. We cannot allow any more predicates to -+ * become cacheable: as unlikely as it is, there may be a thread -+ * caching a (now stale) predicate cache ID. (N.B.: the temptation is -+ * being successfully resisted to have this cmn_err() "Holy shit -- we -+ * executed this code!") -+ */ -+ if (dtrace_predcache_id == DTRACE_CACHEIDNONE) -+ return pred; -+ -+ pred->dtp_cacheid = dtrace_predcache_id++; -+ -+ return pred; -+} -+ -+void dtrace_predicate_hold(struct dtrace_predicate *pred) -+{ -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ ASSERT(pred->dtp_difo != NULL && pred->dtp_difo->dtdo_refcnt != 0); -+ ASSERT(pred->dtp_refcnt > 0); -+ -+ pred->dtp_refcnt++; -+} -+ -+void dtrace_predicate_release(struct dtrace_predicate *pred, -+ struct dtrace_vstate *vstate) -+{ -+ struct dtrace_difo *dp = pred->dtp_difo; -+ -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ ASSERT(dp != NULL && dp->dtdo_refcnt != 0); -+ ASSERT(pred->dtp_refcnt > 0); -+ -+ if (--pred->dtp_refcnt == 0) { -+ dtrace_difo_release(dp, vstate); -+ kfree(pred); -+ } -+} -diff --git a/dtrace/dtrace_priv.c b/dtrace/dtrace_priv.c -new file mode 100644 -index 000000000000..f50133de572d ---- /dev/null -+++ b/dtrace/dtrace_priv.c -@@ -0,0 +1,120 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_priv.c -+ * DESCRIPTION: DTrace - privilege support implementation -+ * -+ * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/dtrace_cpu.h> -+ -+#include "dtrace.h" -+ -+/* -+ * This privilege check should be used by actions and subroutines to -+ * verify that the user credentials of the process that enabled the -+ * invoking ECB match the target credentials -+ */ -+int dtrace_priv_proc_common_user(struct dtrace_state *state) -+{ -+ const struct cred *cr, *s_cr = state->dts_cred.dcr_cred; -+ -+ /* -+ * We should always have a non-NULL state cred here, since if cred -+ * is null (anonymous tracing), we fast-path bypass this routine. -+ */ -+ ASSERT(s_cr != NULL); -+ -+ cr = current_cred(); -+ if (cr != NULL && -+ uid_eq(s_cr->euid, cr->euid) && -+ uid_eq(s_cr->euid, cr->uid) && -+ uid_eq(s_cr->euid, cr->suid) && -+ gid_eq(s_cr->egid, cr->egid) && -+ gid_eq(s_cr->egid, cr->gid) && -+ gid_eq(s_cr->egid, cr->sgid)) -+ return 1; -+ -+ return 0; -+} -+ -+/* -+ * This privilege check should be used by actions and subroutines to -+ * verify that the process has not setuid or changed credentials. -+ */ -+int dtrace_priv_proc_common_nocd(void) -+{ -+#ifdef FIXME -+ proc_t *proc; -+ -+ proc = ttoproc(curthread); -+ if (proc != NULL && !(proc->p_flag & SNOCD)) -+ return 1; -+#endif -+ -+ return 0; -+} -+ -+int dtrace_priv_proc_destructive(struct dtrace_state *state) -+{ -+ int action = state->dts_cred.dcr_action; -+ -+ if (((action & DTRACE_CRA_PROC_DESTRUCTIVE_ALLUSER) == 0) && -+ dtrace_priv_proc_common_user(state) == 0) -+ goto bad; -+ -+ if (((action & DTRACE_CRA_PROC_DESTRUCTIVE_CREDCHG) == 0) && -+ dtrace_priv_proc_common_nocd() == 0) -+ goto bad; -+ -+ return 1; -+ -+bad: -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_UPRIV); -+ -+ return 0; -+} -+ -+int dtrace_priv_proc_control(struct dtrace_state *state) -+{ -+ if (state->dts_cred.dcr_action & DTRACE_CRA_PROC_CONTROL) -+ return 1; -+ -+ if (dtrace_priv_proc_common_user(state) && -+ dtrace_priv_proc_common_nocd()) -+ return 1; -+ -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_UPRIV); -+ -+ return 0; -+} -+ -+int dtrace_priv_proc(struct dtrace_state *state) -+{ -+ if (state->dts_cred.dcr_action & DTRACE_CRA_PROC) -+ return 1; -+ -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_UPRIV); -+ -+ return 0; -+} -+ -+int dtrace_priv_kernel(struct dtrace_state *state) -+{ -+ if (state->dts_cred.dcr_action & DTRACE_CRA_KERNEL) -+ return 1; -+ -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_KPRIV); -+ -+ return 0; -+} -diff --git a/dtrace/dtrace_probe.c b/dtrace/dtrace_probe.c -new file mode 100644 -index 000000000000..8e2e04cb9c13 ---- /dev/null -+++ b/dtrace/dtrace_probe.c -@@ -0,0 +1,1542 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_probe.c -+ * DESCRIPTION: DTrace - probe implementation -+ * -+ * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/dtrace_cpu.h> -+#include <linux/dtrace_task_impl.h> -+#include <linux/hardirq.h> -+#include <linux/highmem.h> -+#include <linux/idr.h> -+#include <linux/module.h> -+#include <linux/skbuff.h> -+#include <linux/slab.h> -+#include <linux/vmalloc.h> -+#include <asm/pgtable.h> -+#include <asm/cmpxchg.h> -+#include <linux/sched/signal.h> -+ -+#include "dtrace.h" -+ -+ktime_t dtrace_chill_interval = -+ KTIME_INIT(1, 0); -+ktime_t dtrace_chill_max = -+ KTIME_INIT(0, -+ 500 * (NANOSEC / MILLISEC)); -+ -+dtrace_genid_t dtrace_probegen; -+struct kmem_cache *dtrace_probe_cachep; -+ -+static struct idr dtrace_probe_idr; -+ -+static struct task_struct *dtrace_panicked; -+ -+/* -+ * Free probe structure (including partially filled in ones). -+ */ -+void dtrace_probe_free(struct dtrace_probe *probe) -+{ -+ if (probe == NULL) -+ return; -+ -+ dtrace_probe_remove_id(probe->dtpr_id); -+ -+ kfree(probe->dtpr_mod); -+ kfree(probe->dtpr_func); -+ kfree(probe->dtpr_name); -+ -+ kmem_cache_free(dtrace_probe_cachep, probe); -+} -+ -+/* -+ * Create a new probe. -+ */ -+dtrace_id_t dtrace_probe_create(dtrace_provider_id_t prov, const char *mod, -+ const char *func, const char *name, -+ int aframes, void *arg) -+{ -+ struct dtrace_probe *probe; -+ struct dtrace_provider *provider = (struct dtrace_provider *)prov; -+ dtrace_id_t id; -+ -+ probe = kmem_cache_alloc(dtrace_probe_cachep, GFP_KERNEL); -+ if (probe == NULL) -+ goto err_probe; -+ -+ /* -+ * The idr_preload() should be called without holding locks as it may -+ * block. At the same time it is required to protect DTrace structures. -+ * We can't drop it before idr_preload() and acquire after it because -+ * we can't sleep in atomic context (until we reach idr_preload_end()). -+ * -+ * It is better to delay DTrace framework than traced host so the lock -+ * is being held for the duration of idr allocation. -+ * -+ * When the provider is the DTrace core itself, dtrace_lock will be -+ * held when we enter this function. -+ */ -+ if (provider == dtrace_provider) -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ else -+ mutex_lock(&dtrace_lock); -+ -+ idr_preload(GFP_KERNEL); -+ id = idr_alloc_cyclic(&dtrace_probe_idr, probe, 0, 0, GFP_NOWAIT); -+ idr_preload_end(); -+ if (id < 0) -+ goto err_probe; -+ -+ probe->dtpr_id = id; -+ probe->dtpr_ecb = NULL; -+ probe->dtpr_ecb_last = NULL; -+ probe->dtpr_arg = arg; -+ probe->dtpr_predcache = DTRACE_CACHEIDNONE; -+ probe->dtpr_aframes = aframes; -+ probe->dtpr_provider = provider; -+ -+ probe->dtpr_mod = dtrace_strdup(mod); -+ if (probe->dtpr_mod == NULL) -+ goto err_probe; -+ -+ probe->dtpr_func = dtrace_strdup(func); -+ if (probe->dtpr_func == NULL) -+ goto err_probe; -+ -+ probe->dtpr_name = dtrace_strdup(name); -+ if (probe->dtpr_name == NULL) -+ goto err_probe; -+ -+ probe->dtpr_nextmod = probe->dtpr_prevmod = NULL; -+ probe->dtpr_nextfunc = probe->dtpr_prevfunc = NULL; -+ probe->dtpr_nextname = probe->dtpr_prevname = NULL; -+ probe->dtpr_gen = dtrace_probegen++; -+ -+ if (dtrace_hash_add(dtrace_bymod, probe) != 0) -+ goto err_probe; -+ -+ if (dtrace_hash_add(dtrace_byfunc, probe) != 0) -+ goto err_hash_byfunc; -+ -+ if (dtrace_hash_add(dtrace_byname, probe) != 0) -+ goto err_hash_byname; -+ -+ if (provider != dtrace_provider) -+ mutex_unlock(&dtrace_lock); -+ -+ return id; -+ -+err_hash_byname: -+ dtrace_hash_remove(dtrace_byfunc, probe); -+err_hash_byfunc: -+ dtrace_hash_remove(dtrace_bymod, probe); -+err_probe: -+ dtrace_probe_free(probe); -+ if (provider != dtrace_provider) -+ mutex_unlock(&dtrace_lock); -+ return DTRACE_IDNONE; -+} -+EXPORT_SYMBOL(dtrace_probe_create); -+ -+int dtrace_probe_enable(const struct dtrace_probedesc *desc, -+ struct dtrace_enabling *enab) -+{ -+ struct dtrace_probekey pkey; -+ uint32_t priv; -+ kuid_t uid; -+ -+ dtrace_ecb_create_cache = NULL; -+ -+ if (desc == NULL) { -+ (void) dtrace_ecb_create_enable(NULL, enab); -+ -+ return 0; -+ } -+ -+ dtrace_probekey(desc, &pkey); -+ dtrace_cred2priv(enab->dten_vstate->dtvs_state->dts_cred.dcr_cred, -+ &priv, &uid); -+ -+ return dtrace_match(&pkey, priv, uid, dtrace_ecb_create_enable, enab); -+} -+ -+/* -+ * Return the probe argument associated with the specified probe. -+ */ -+void *dtrace_probe_arg(dtrace_provider_id_t id, dtrace_id_t pid) -+{ -+ struct dtrace_probe *probe; -+ void *rval = NULL; -+ -+ mutex_lock(&dtrace_lock); -+ -+ probe = dtrace_probe_lookup_id(pid); -+ if (probe != NULL && -+ probe->dtpr_provider == (struct dtrace_provider *)id) -+ rval = probe->dtpr_arg; -+ -+ mutex_unlock(&dtrace_lock); -+ -+ return rval; -+} -+EXPORT_SYMBOL(dtrace_probe_arg); -+ -+/* -+ * Copy a probe into a probe description. -+ */ -+void dtrace_probe_description(const struct dtrace_probe *prp, -+ struct dtrace_probedesc *pdp) -+{ -+ memset(pdp, 0, sizeof(struct dtrace_probedesc)); -+ pdp->dtpd_id = prp->dtpr_id; -+ -+ strncpy(pdp->dtpd_provider, prp->dtpr_provider->dtpv_name, -+ DTRACE_PROVNAMELEN - 1); -+ -+ strncpy(pdp->dtpd_mod, prp->dtpr_mod, DTRACE_MODNAMELEN - 1); -+ strncpy(pdp->dtpd_func, prp->dtpr_func, DTRACE_FUNCNAMELEN - 1); -+ strncpy(pdp->dtpd_name, prp->dtpr_name, DTRACE_NAMELEN - 1); -+} -+ -+void dtrace_probe_provide(struct dtrace_probedesc *desc, -+ struct dtrace_provider *prv) -+{ -+ int all = 0; -+ -+ if (prv == NULL) { -+ all = 1; -+ prv = dtrace_provider; -+ } -+ -+ do { -+ prv->dtpv_pops.dtps_provide(prv->dtpv_arg, desc); -+ dtrace_for_each_module(prv->dtpv_pops.dtps_provide_module, -+ prv->dtpv_arg); -+ } while (all && (prv = prv->dtpv_next) != NULL); -+} -+ -+/* -+ * Atomically increment a specified error counter from probe context. -+ */ -+static void dtrace_error(uint32_t *counter) -+{ -+ /* -+ * Most counters stored to in probe context are per-CPU counters. -+ * However, there are some error conditions that are sufficiently -+ * arcane that they don't merit per-CPU storage. If these counters -+ * are incremented concurrently on different CPUs, scalability will be -+ * adversely affected -- but we don't expect them to be white-hot in a -+ * correctly constructed enabling... -+ */ -+ uint32_t oval, nval; -+ -+ do { -+ oval = *counter; -+ -+ nval = oval + 1; -+ if (nval == 0) { -+ /* -+ * If the counter would wrap, set it to 1 -- assuring -+ * that the counter is never zero when we have seen -+ * errors. (The counter must be 32-bits because we -+ * aren't guaranteed a 64-bit compare&swap operation.) -+ * To save this code both the infamy of being fingered -+ * by a priggish news story and the indignity of being -+ * the target of a neo-puritan witch trial, we're -+ * carefully avoiding any colorful description of the -+ * likelihood of this condition -- but suffice it to -+ * say that it is only slightly more likely than the -+ * overflow of predicate cache IDs, as discussed in -+ * dtrace_predicate_create(). -+ */ -+ nval = 1; -+ } -+ } while (cmpxchg(counter, oval, nval) != oval); -+} -+ -+static int dtrace_priv_kernel_destructive(struct dtrace_state *state) -+{ -+ if (state->dts_cred.dcr_action & DTRACE_CRA_KERNEL_DESTRUCTIVE) -+ return 1; -+ -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_KPRIV); -+ -+ return 0; -+} -+ -+static void dtrace_action_breakpoint(struct dtrace_ecb *ecb) -+{ -+ struct dtrace_probe *probe = ecb->dte_probe; -+ struct dtrace_provider *prov = probe->dtpr_provider; -+ char c[DTRACE_FULLNAMELEN + 80], *str; -+ char *msg = "dtrace: breakpoint action at probe "; -+ char *ecbmsg = " (ecb "; -+ uintptr_t mask = (0xf << (sizeof(uintptr_t) * NBBY / 4)); -+ uintptr_t val = (uintptr_t)ecb; -+ int shift = (sizeof(uintptr_t) * NBBY) - 4, i = 0; -+ -+ if (dtrace_destructive_disallow) -+ return; -+ -+ /* -+ * It's impossible to be taking action on the NULL probe. -+ */ -+ ASSERT(probe != NULL); -+ -+ /* -+ * This is a poor man's (destitute man's?) sprintf(): we want to -+ * print the provider name, module name, function name and name of -+ * the probe, along with the hex address of the ECB with the breakpoint -+ * action -- all of which we must place in the character buffer by -+ * hand. -+ */ -+ while (*msg != '\0') -+ c[i++] = *msg++; -+ -+ for (str = prov->dtpv_name; *str != '\0'; str++) -+ c[i++] = *str; -+ c[i++] = ':'; -+ -+ for (str = probe->dtpr_mod; *str != '\0'; str++) -+ c[i++] = *str; -+ c[i++] = ':'; -+ -+ for (str = probe->dtpr_func; *str != '\0'; str++) -+ c[i++] = *str; -+ c[i++] = ':'; -+ -+ for (str = probe->dtpr_name; *str != '\0'; str++) -+ c[i++] = *str; -+ -+ while (*ecbmsg != '\0') -+ c[i++] = *ecbmsg++; -+ -+ while (shift >= 0) { -+ mask = (uintptr_t)0xf << shift; -+ -+ if (val >= ((uintptr_t)1 << shift)) -+ c[i++] = "0123456789abcdef"[(val & mask) >> shift]; -+ -+ shift -= 4; -+ } -+ -+ c[i++] = ')'; -+ c[i] = '\0'; -+ -+// debug_enter(c); /* FIXME */ -+} -+ -+static void dtrace_action_panic(struct dtrace_ecb *ecb) -+{ -+ struct dtrace_probe *probe = ecb->dte_probe; -+ -+ /* -+ * It's impossible to be taking action on the NULL probe. -+ */ -+ ASSERT(probe != NULL); -+ -+ if (dtrace_destructive_disallow) -+ return; -+ -+ if (dtrace_panicked != NULL) -+ return; -+ -+ if (cmpxchg(&dtrace_panicked, NULL, current) != NULL) -+ return; -+ -+ /* -+ * We won the right to panic. (We want to be sure that only one -+ * thread calls panic() from dtrace_probe(), and that panic() is -+ * called exactly once.) -+ */ -+ dtrace_panic(KERN_EMERG -+ "dtrace: panic action at probe %s:%s:%s:%s (ecb %p)", -+ probe->dtpr_provider->dtpv_name, probe->dtpr_mod, -+ probe->dtpr_func, probe->dtpr_name, (void *)ecb); -+} -+ -+static void dtrace_action_raise(uint64_t sig) -+{ -+ if (current->dt_task == NULL) -+ return; -+ -+ if (dtrace_destructive_disallow) -+ return; -+ -+ if (sig >= _NSIG) { -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); -+ return; -+ } -+ -+ /* -+ * raise() has a queue depth of 1 -- we ignore all subsequent -+ * invocations of the raise() action. -+ */ -+ if (current->dt_task->dt_sig == 0) -+ current->dt_task->dt_sig = (uint8_t)sig; -+} -+ -+static void dtrace_action_stop(void) -+{ -+ if (current->dt_task == NULL) -+ return; -+ -+ if (dtrace_destructive_disallow) -+ return; -+ -+ if (!current->dt_task->dt_stop) { -+ current->dt_task->dt_stop = 1; -+// current->sig_check = 1; /* FIXME */ -+// aston(current); /* FIXME */ -+ } -+} -+ -+static void dtrace_action_chill(struct dtrace_mstate *mstate, ktime_t val) -+{ -+ ktime_t now; -+ volatile uint16_t *flags; -+ struct cpu_core *cpu = this_cpu_core; -+ -+ if (dtrace_destructive_disallow) -+ return; -+ -+ flags = (volatile uint16_t *)&cpu->cpuc_dtrace_flags; -+ -+ now = dtrace_gethrtime(); -+ -+ if (ktime_gt(ktime_sub(now, cpu->cpu_dtrace_chillmark), -+ dtrace_chill_interval)) { -+ /* -+ * We need to advance the mark to current time. -+ */ -+ cpu->cpu_dtrace_chillmark = now; -+ cpu->cpu_dtrace_chilled = ktime_set(0, 0); -+ } -+ -+ /* -+ * Now check to see if the requested chill time would take us over -+ * the maximum amount of time allowed in the chill interval. (Or -+ * worse, if the calculation itself induces overflow.) -+ */ -+ if (ktime_gt(ktime_add(cpu->cpu_dtrace_chilled, val), -+ dtrace_chill_max) || -+ ktime_lt(ktime_add(cpu->cpu_dtrace_chilled, val), -+ cpu->cpu_dtrace_chilled)) { -+ *flags |= CPU_DTRACE_ILLOP; -+ return; -+ } -+ -+ while (ktime_lt(ktime_sub(dtrace_gethrtime(), now), val)) -+ continue; -+ -+ /* -+ * Normally, we assure that the value of the variable "timestamp" does -+ * not change within an ECB. The presence of chill() represents an -+ * exception from this rule, however. -+ */ -+ mstate->dtms_present &= ~DTRACE_MSTATE_TIMESTAMP; -+ cpu->cpu_dtrace_chilled = ktime_add(cpu->cpu_dtrace_chilled, val); -+} -+ -+static void dtrace_action_ustack(struct dtrace_mstate *mstate, -+ struct dtrace_state *state, uint64_t *buf, -+ uint64_t arg) -+{ -+ int nframes = DTRACE_USTACK_NFRAMES(arg); -+ int strsize = DTRACE_USTACK_STRSIZE(arg); -+ uint64_t *pcs = &buf[2], *fps; -+ char *str = (char *)&pcs[nframes]; -+ int size, offs = 0, i, j; -+ uintptr_t old = mstate->dtms_scratch_ptr, saved; -+ uint16_t *flags = &this_cpu_core->cpuc_dtrace_flags; -+ char *sym; -+ -+ /* -+ * Should be taking a faster path if string space has not been -+ * allocated. -+ */ -+ ASSERT(strsize != 0); -+ -+ /* -+ * We will first allocate some temporary space for the frame pointers. -+ */ -+ fps = (uint64_t *)P2ROUNDUP(mstate->dtms_scratch_ptr, 8); -+ size = (uintptr_t)fps - mstate->dtms_scratch_ptr + -+ (nframes * sizeof(uint64_t)); -+ -+ if (!DTRACE_INSCRATCH(mstate, size)) { -+ /* -+ * Not enough room for our frame pointers -- need to indicate -+ * that we ran out of scratch space. -+ */ -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); -+ return; -+ } -+ -+ mstate->dtms_scratch_ptr += size; -+ saved = mstate->dtms_scratch_ptr; -+ -+ /* -+ * Now get a stack with both program counters and frame pointers. -+ */ -+ dtrace_getufpstack(buf, fps, nframes + 2); -+ -+ /* -+ * If that faulted, we're cooked. -+ */ -+ if (*flags & CPU_DTRACE_FAULT) -+ goto out; -+ -+ /* -+ * Now we want to walk up the stack, calling the USTACK helper. For -+ * each iteration, we restore the scratch pointer. -+ */ -+ for (i = 0; i < nframes; i++) { -+ mstate->dtms_scratch_ptr = saved; -+ -+ if (offs >= strsize) -+ break; -+ -+ sym = (char *)(uintptr_t)dtrace_helper( -+ DTRACE_HELPER_ACTION_USTACK, -+ mstate, state, pcs[i], fps[i]); -+ -+ /* -+ * If we faulted while running the helper, we're going to -+ * clear the fault and null out the corresponding string. -+ */ -+ if (*flags & CPU_DTRACE_FAULT) { -+ *flags &= ~CPU_DTRACE_FAULT; -+ str[offs++] = '\0'; -+ continue; -+ } -+ -+ if (sym == NULL) { -+ str[offs++] = '\0'; -+ continue; -+ } -+ -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); -+ -+ /* -+ * Now copy in the string that the helper returned to us. -+ */ -+ for (j = 0; offs + j < strsize; j++) { -+ str[offs + j] = sym[j]; -+ if (str[offs + j] == '\0') -+ break; -+ } -+ -+ DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); -+ -+ offs += j + 1; -+ } -+ -+ /* -+ * If we didn't have room for all of the strings, we don't abort -+ * processing -- this needn't be a fatal error -- but we still want -+ * to increment a counter (dts_stkstroverflows) to allow this condition -+ * to be warned about. (If this is from a jstack() action, it is -+ * easily tuned via jstackstrsize.) -+ */ -+ if (offs >= strsize) -+ dtrace_error(&state->dts_stkstroverflows); -+ -+ while (offs < strsize) -+ str[offs++] = '\0'; -+ -+out: -+ mstate->dtms_scratch_ptr = old; -+} -+ -+/* -+ * This macro is used by dtrace_probe_pcap() below. See linux/skbuff.h for the -+ * original. Only change is we pass in an already dereferenced page.p as -+ * the fragment f. -+ */ -+#define dtrace_skb_frag_foreach_page(f, f_off, f_len, p, p_off, p_len, copied) \ -+ for (p = f + ((f_off) >> PAGE_SHIFT), \ -+ p_off = (f_off) & (PAGE_SIZE - 1), \ -+ p_len = skb_frag_must_loop(p) ? \ -+ min_t(u32, f_len, PAGE_SIZE - p_off) : f_len, \ -+ copied = 0; \ -+ copied < f_len; \ -+ copied += p_len, p++, p_off = 0, \ -+ p_len = min_t(u32, f_len - copied, PAGE_SIZE)) \ -+ -+ -+/* -+ * Capture skb data in linear and non-linear portions. Returns 0 on success, -+ * -1 if an error is encountered. -+ */ -+static __always_inline int dtrace_probe_pcap(uint64_t val, size_t *valoffs, -+ size_t size, caddr_t tomax, -+ ktime_t now, -+ struct dtrace_mstate *mstate, -+ struct dtrace_vstate *vstate, -+ volatile uint16_t *flags) -+ -+{ -+ uintptr_t start = *valoffs, end = *valoffs + size; -+ uintptr_t skb_head, skb_data, skb_tail, shinfo; -+ uint32_t skb_end, tail, skb_len = 0; -+ uintptr_t baddr = val; -+ uint8_t nr_frags, f; -+ uint32_t data_len; -+ -+ DTRACE_STORE(uint64_t, tomax, start, ktime_to_ns(now)); -+ -+ *valoffs += (2 * sizeof(uint64_t)); -+ -+ /* -+ * Skip capture of NULL skbs. -+ */ -+ if ((void *)baddr == NULL) -+ goto pcap_done; -+ -+ if (!dtrace_canload(baddr, sizeof(struct sk_buff), mstate, vstate)) -+ return -1; -+ -+ skb_data = dtrace_loadptr(baddr + offsetof(struct sk_buff, data)); -+ skb_head = dtrace_loadptr(baddr + offsetof(struct sk_buff, head)); -+ skb_len = dtrace_load32(baddr + offsetof(struct sk_buff, len)); -+ tail = dtrace_load32(baddr + offsetof(struct sk_buff, tail)); -+ skb_tail = skb_head + tail; -+ -+ if (skb_tail < skb_data) { -+ *flags |= CPU_DTRACE_BADADDR; -+ return -1; -+ } -+ while (*valoffs < end && skb_data < skb_tail) { -+ DTRACE_STORE(uint8_t, tomax, (*valoffs)++, -+ dtrace_load8(skb_data++)); -+ } -+ -+ data_len = dtrace_load32(baddr + offsetof(struct sk_buff, data_len)); -+ -+ /* -+ * If skb is linear, no need to explore fragments. -+ */ -+ if (data_len == 0) -+ goto pcap_done; -+ -+ skb_end = dtrace_load32(baddr + offsetof(struct sk_buff, end)); -+ shinfo = skb_head + skb_end; -+ -+ if (!dtrace_canload(shinfo, sizeof(struct skb_shared_info), -+ mstate, vstate)) -+ return -1; -+ -+ nr_frags = dtrace_load8(shinfo + offsetof(struct skb_shared_info, -+ nr_frags)); -+ -+ /* -+ * See skb_frag_foreach_page() macro usage elsewhere to understand the -+ * manipulations here; the reason we need this complexity is to support -+ * compound pages. -+ */ -+ for (f = 0; f < nr_frags; f++) { -+ uint32_t poff, plen, copied, flen; -+ struct page *p, *frag; -+ uintptr_t foff, v; -+ void *vaddr; -+ -+ flen = dtrace_load32(shinfo + offsetof(struct skb_shared_info, -+ frags[f].bv_len)); -+ foff = dtrace_load32(shinfo + offsetof(struct skb_shared_info, -+ frags[f].bv_offset)); -+ frag = (struct page *)dtrace_loadptr(shinfo + offsetof( -+ struct skb_shared_info, -+ frags[f].bv_page)); -+ -+ dtrace_skb_frag_foreach_page(frag, foff, flen, -+ p, poff, plen, copied) { -+ if (data_len == 0) -+ break; -+ -+ vaddr = kmap_atomic(p); -+ v = (uintptr_t)vaddr + poff; -+ if (!dtrace_canload(v, plen, mstate, vstate)) { -+ kunmap_atomic(vaddr); -+ return -1; -+ } -+ while (*valoffs < end && data_len-- > 0) { -+ DTRACE_STORE(uint8_t, tomax, (*valoffs)++, -+ dtrace_load8(v++)); -+ } -+ kunmap_atomic(vaddr); -+ } -+ } -+ -+pcap_done: -+ /* -+ * Note that we store the skb len here rather than the portion of it we -+ * capture; we can determine the latter when collecting data by using -+ * the "pcapsize" option. Packet capture headers specify a packet size -+ * and a capture size, so we want to be able to provide both. Since -+ * the capture size can be determined from the packet length when -+ * consuming records, we don't need to store it. -+ */ -+ DTRACE_STORE(uint64_t, tomax, start + sizeof(uint64_t), -+ (uint64_t)skb_len); -+ -+ return 0; -+} -+void dtrace_probe(dtrace_id_t id, uintptr_t arg0, uintptr_t arg1, -+ uintptr_t arg2, uintptr_t arg3, uintptr_t arg4, -+ uintptr_t arg5, uintptr_t arg6) -+{ -+ processorid_t cpuid; -+ dtrace_icookie_t cookie; -+ struct dtrace_probe *probe; -+ struct dtrace_mstate mstate; -+ struct dtrace_ecb *ecb; -+ struct dtrace_action *act; -+ intptr_t offs; -+ size_t size; -+ int onintr; -+ int vtime; -+ volatile uint16_t *flags; -+ ktime_t now; -+ uint32_t re_entry; -+ struct dtrace_task *dtsk = current->dt_task; -+ dtrace_id_t old_id; -+ -+#ifdef FIXME -+ /* -+ * Kick out immediately if this CPU is still being born (in which case -+ * curthread will be set to -1) or the current thread can't allow -+ * probes in its current context. -+ */ -+ if (((uintptr_t)curthread & 1) || (curthread->t_flag & T_DONTDTRACE)) -+ return; -+#endif -+ -+ DTRACE_SYNC_ENTER_CRITICAL(cookie, re_entry); -+ -+ /* -+ * Probe context is not re-entrant, unless we're getting called to -+ * process an ERROR probe. -+ */ -+ flags = (volatile uint16_t *)&this_cpu_core->cpuc_dtrace_flags; -+ cpuid = smp_processor_id(); -+ if (re_entry && id != dtrace_probeid_error) { -+ dt_dbg_probe("Attempt to fire probe from within a probe " \ -+ "(ID %d, oID %d, CPU %d)\n", id, -+ (int)this_cpu_core->cpuc_current_probe, cpuid); -+ DTRACE_SYNC_EXIT_CRITICAL(cookie, re_entry); -+ return; -+ } -+ -+ probe = dtrace_probe_lookup_id(id); -+ onintr = in_interrupt(); -+ -+ if (!onintr && probe->dtpr_predcache != DTRACE_CACHEIDNONE && -+ dtsk != NULL && probe->dtpr_predcache == dtsk->dt_predcache) { -+ DTRACE_SYNC_EXIT_CRITICAL(cookie, re_entry); -+ return; -+ } -+ -+ if (oops_in_progress) { -+ DTRACE_SYNC_EXIT_CRITICAL(cookie, re_entry); -+ return; -+ } -+ -+ old_id = this_cpu_core->cpuc_current_probe; -+ this_cpu_core->cpuc_current_probe = id; -+ -+ now = dtrace_gethrtime(); -+ vtime = (dtrace_vtime_references > 0); -+ -+ if (vtime && dtsk != NULL && ktime_nz(dtsk->dt_start)) -+ dtsk->dt_vtime = ktime_add(dtsk->dt_vtime, -+ ktime_sub(now, dtsk->dt_start)); -+ -+ mstate.dtms_difo = NULL; -+ mstate.dtms_probe = probe; -+ mstate.dtms_strtok = (uintptr_t)NULL; -+ mstate.dtms_arg[0] = arg0; -+ mstate.dtms_arg[1] = arg1; -+ mstate.dtms_arg[2] = arg2; -+ mstate.dtms_arg[3] = arg3; -+ mstate.dtms_arg[4] = arg4; -+ mstate.dtms_arg[5] = arg5; -+ mstate.dtms_arg[6] = arg6; -+ -+ for (ecb = probe->dtpr_ecb; ecb != NULL; ecb = ecb->dte_next) { -+ struct dtrace_predicate *pred = ecb->dte_predicate; -+ struct dtrace_state *state = ecb->dte_state; -+ struct dtrace_buffer *buf = &state->dts_buffer[cpuid]; -+ struct dtrace_buffer *aggbuf = &state->dts_aggbuffer[cpuid]; -+ struct dtrace_vstate *vstate = &state->dts_vstate; -+ struct dtrace_provider *prov = probe->dtpr_provider; -+ int committed = 0; -+ caddr_t tomax; -+ -+ /* -+ * A little subtlety with the following (seemingly innocuous) -+ * declaration of the automatic 'val': by looking at the -+ * code, you might think that it could be declared in the -+ * action processing loop, below. (That is, it's only used in -+ * the action processing loop.) However, it must be declared -+ * out of that scope because in the case of DIF expression -+ * arguments to aggregating actions, one iteration of the -+ * action loop will use the last iteration's value. -+ */ -+ uint64_t val = 0; -+ -+ mstate.dtms_present = DTRACE_MSTATE_ARGS | DTRACE_MSTATE_PROBE; -+ *flags &= ~CPU_DTRACE_ERROR; -+ -+ if (prov == dtrace_provider) { -+ /* -+ * If dtrace itself is the provider of this probe, -+ * we're only going to continue processing the ECB if -+ * arg0 (the dtrace_state_t) is equal to the ECB's -+ * creating state. (This prevents disjoint consumers -+ * from seeing one another's metaprobes.) -+ */ -+ if (arg0 != (uint64_t)(uintptr_t)state) -+ continue; -+ } -+ -+ if (state->dts_activity != DTRACE_ACTIVITY_ACTIVE) { -+ /* -+ * We're not currently active. If our provider isn't -+ * the dtrace pseudo provider, we're not interested. -+ */ -+ if (prov != dtrace_provider) -+ continue; -+ -+ /* -+ * Now we must further check if we are in the BEGIN -+ * probe. If we are, we will only continue orocessing -+ * if we're still in WARMUP -- if one BEGIN enabling -+ * has invoked the exit() action, we don't want to -+ * evaluate subsequent BEGIN enablings. -+ */ -+ if (probe->dtpr_id == dtrace_probeid_begin && -+ state->dts_activity != DTRACE_ACTIVITY_WARMUP) { -+ ASSERT(state->dts_activity == -+ DTRACE_ACTIVITY_DRAINING); -+ continue; -+ } -+ } -+ -+ dt_dbg_probe("Probe (ID %d EPID %d) on CPU %d...\n", -+ id, ecb->dte_epid, cpuid); -+ if (ecb->dte_cond) { -+ /* -+ * If the dte_cond bits indicate that this -+ * consumer is only allowed to see user-mode firings -+ * of this probe, call the provider's dtps_usermode() -+ * entry point to check that the probe was fired -+ * while in a user context. Skip this ECB if that's -+ * not the case. -+ */ -+ if ((ecb->dte_cond & DTRACE_COND_USERMODE) && -+ prov->dtpv_pops.dtps_usermode( -+ prov->dtpv_arg, probe->dtpr_id, probe->dtpr_arg -+ ) == 0) { -+ dt_dbg_probe("Probe (ID %d EPID %d) Skipped\n", -+ id, ecb->dte_epid); -+ continue; -+ } -+ -+ /* -+ * This is more subtle than it looks. We have to be -+ * absolutely certain that current_cred() isn't going -+ * to change out from under us so it's only legit to -+ * examine that structure if we're in constrained -+ * situations. Currently, the only times we'll use this -+ * check is if a non-super-user has enabled the -+ * profile or syscall providers -- providers that -+ * allow visibility of all processes. For the -+ * profile case, the check above will ensure that -+ * we're examining a user context. -+ */ -+ if (ecb->dte_cond & DTRACE_COND_OWNER) { -+ const struct cred *cr; -+ const struct cred *s_cr = -+ ecb->dte_state->dts_cred.dcr_cred; -+ -+ ASSERT(s_cr != NULL); -+ -+ cr = current_cred(); -+ if (cr == NULL || -+ !uid_eq(s_cr->euid, cr->euid) || -+ !uid_eq(s_cr->euid, cr->uid) || -+ !uid_eq(s_cr->euid, cr->suid) || -+ !gid_eq(s_cr->egid, cr->egid) || -+ !gid_eq(s_cr->egid, cr->gid) || -+ !gid_eq(s_cr->egid, cr->sgid)) { -+ dt_dbg_probe("Probe (ID %d EPID %d) " -+ "Skipped\n", -+ id, ecb->dte_epid); -+ continue; -+ } -+ } -+ } -+ -+ if (ktime_gt(ktime_sub(now, state->dts_alive), -+ dtrace_deadman_timeout)) { -+ /* -+ * We seem to be dead. Unless we (a) have kernel -+ * destructive permissions (b) have expicitly enabled -+ * destructive actions and (c) destructive actions have -+ * not been disabled, we're going to transition into -+ * the KILLED state, from which no further processing -+ * on this state will be performed. -+ */ -+ if (!dtrace_priv_kernel_destructive(state) || -+ !state->dts_cred.dcr_destructive || -+ dtrace_destructive_disallow) { -+ enum dtrace_activity *activity = -+ &state->dts_activity; -+ enum dtrace_activity curr; -+ -+ do { -+ curr = state->dts_activity; -+ } while (cmpxchg(activity, curr, -+ DTRACE_ACTIVITY_KILLED) != curr); -+ -+ dt_dbg_probe("Probe (ID %d EPID %d) Skipped\n", -+ id, ecb->dte_epid); -+ continue; -+ } -+ } -+ -+ offs = dtrace_buffer_reserve(buf, ecb->dte_needed, -+ ecb->dte_alignment, state, -+ &mstate); -+ if (offs < 0) { -+ dt_dbg_probe("Probe (ID %d EPID %d) Skipped\n", -+ id, ecb->dte_epid); -+ continue; -+ } -+ -+ tomax = buf->dtb_tomax; -+ ASSERT(tomax != NULL); -+ -+ if (ecb->dte_size != 0) { -+ DTRACE_STORE(uint32_t, tomax, offs, ecb->dte_epid); -+ dt_dbg_buf(" Store: %p[%ld .. %ld] <- %d [EPID] " -+ "(from %s::%d)\n", -+ buf, offs, offs + sizeof(uint32_t) - 1, -+ ecb->dte_epid, __func__, __LINE__); -+ } -+ -+ mstate.dtms_epid = ecb->dte_epid; -+ mstate.dtms_present |= DTRACE_MSTATE_EPID; -+ -+ if (state->dts_cred.dcr_visible & DTRACE_CRV_KERNEL) -+ mstate.dtms_access = DTRACE_ACCESS_KERNEL; -+ else -+ mstate.dtms_access = 0; -+ -+ if (pred != NULL) { -+ struct dtrace_difo *dp = pred->dtp_difo; -+ int rval; -+ -+ dt_dbg_probe(" Evaluating predicate...\n"); -+ -+ rval = dtrace_dif_emulate(dp, &mstate, vstate, state); -+ -+ if (!(*flags & CPU_DTRACE_ERROR) && !rval) { -+ dtrace_cacheid_t cid = -+ probe->dtpr_predcache; -+ -+ if (cid != DTRACE_CACHEIDNONE && !onintr) { -+ /* -+ * Update the predicate cache... -+ */ -+ ASSERT(cid == pred->dtp_cacheid); -+ if (dtsk != NULL) -+ dtsk->dt_predcache = cid; -+ } -+ -+ dt_dbg_probe(" Predicate not met (%d)\n", -+ rval); -+ dt_dbg_probe("Probe (ID %d EPID %d) Done\n", -+ id, ecb->dte_epid); -+ continue; -+ } -+ -+ dt_dbg_probe(" Predicate met (%d)\n", rval); -+ } -+ -+ for (act = ecb->dte_action; -+ !(*flags & CPU_DTRACE_ERROR) && act != NULL; -+ act = act->dta_next) { -+ size_t valoffs; -+ struct dtrace_difo *dp; -+ struct dtrace_recdesc *rec = &act->dta_rec; -+ -+ dt_dbg_probe(" Evaluating action %p (kind %d)...\n", -+ act, act->dta_kind); -+ -+ size = rec->dtrd_size; -+ valoffs = offs + rec->dtrd_offset; -+ -+ if (DTRACEACT_ISAGG(act->dta_kind)) { -+ uint64_t v = 0xbad; -+ struct dtrace_aggregation *agg; -+ -+ agg = (struct dtrace_aggregation *)act; -+ -+ dp = act->dta_difo; -+ if (dp != NULL) -+ v = dtrace_dif_emulate(dp, &mstate, -+ vstate, state); -+ -+ if (*flags & CPU_DTRACE_ERROR) -+ continue; -+ -+ /* -+ * Note that we always pass the expression -+ * value from the previous iteration of the -+ * action loop. This value will only be used -+ * if there is an expression argument to the -+ * aggregating action, denoted by the -+ * dtag_hasarg field. -+ */ -+ dtrace_aggregate(agg, buf, offs, aggbuf, v, -+ val); -+ continue; -+ } -+ -+ switch (act->dta_kind) { -+ case DTRACEACT_STOP: -+ if (dtrace_priv_proc_destructive(state)) -+ dtrace_action_stop(); -+ continue; -+ -+ case DTRACEACT_BREAKPOINT: -+ if (dtrace_priv_kernel_destructive(state)) -+ dtrace_action_breakpoint(ecb); -+ continue; -+ -+ case DTRACEACT_PANIC: -+ if (dtrace_priv_kernel_destructive(state)) -+ dtrace_action_panic(ecb); -+ continue; -+ -+ case DTRACEACT_STACK: -+ if (!dtrace_priv_kernel(state)) -+ continue; -+ -+ dtrace_getpcstack( -+ (uint64_t *)(tomax + valoffs), -+ size / sizeof(pc_t), -+ probe->dtpr_aframes + 1, -+ DTRACE_ANCHORED(probe) -+ ? NULL -+ : (uint32_t *)arg0); -+ -+ continue; -+ -+ case DTRACEACT_JSTACK: -+ case DTRACEACT_USTACK: -+ if (!dtrace_priv_proc(state)) -+ continue; -+ -+ /* -+ * See comment in DIF_VAR_PID. -+ */ -+ if (DTRACE_ANCHORED(mstate.dtms_probe) && -+ in_interrupt()) { -+ int depth = DTRACE_USTACK_NFRAMES( -+ rec->dtrd_arg) + 2; -+ -+ dtrace_bzero((void *)(tomax + valoffs), -+ DTRACE_USTACK_STRSIZE( -+ rec->dtrd_arg) + -+ depth * sizeof(uint64_t)); -+ -+ continue; -+ } -+ -+ if (DTRACE_USTACK_STRSIZE(rec->dtrd_arg) != 0 && -+ dtsk != NULL && dtsk->dt_helpers != NULL) { -+ /* -+ * This is the slow path -- we have -+ * allocated string space, and we're -+ * getting the stack of a process that -+ * has helpers. Call into a separate -+ * routine to perform this processing. -+ */ -+ dtrace_action_ustack( -+ &mstate, state, -+ (uint64_t *)(tomax + valoffs), -+ rec->dtrd_arg); -+ continue; -+ } -+ -+ dtrace_getupcstack( -+ (uint64_t *)(tomax + valoffs), -+ DTRACE_USTACK_NFRAMES(rec->dtrd_arg) + -+ 2); -+ continue; -+ -+ default: -+ break; -+ } -+ -+ dp = act->dta_difo; -+ ASSERT(dp != NULL); -+ -+ val = dtrace_dif_emulate(dp, &mstate, vstate, state); -+ -+ if (*flags & CPU_DTRACE_ERROR) -+ continue; -+ -+ switch (act->dta_kind) { -+ case DTRACEACT_SPECULATE: -+ ASSERT(buf == &state->dts_buffer[cpuid]); -+ buf = dtrace_speculation_buffer(state, cpuid, -+ val); -+ -+ if (buf == NULL) { -+ *flags |= CPU_DTRACE_DROP; -+ continue; -+ } -+ -+ offs = dtrace_buffer_reserve(buf, -+ ecb->dte_needed, -+ ecb->dte_alignment, -+ state, NULL); -+ -+ if (offs < 0) { -+ *flags |= CPU_DTRACE_DROP; -+ continue; -+ } -+ -+ tomax = buf->dtb_tomax; -+ ASSERT(tomax != NULL); -+ -+ if (ecb->dte_size != 0) { -+ DTRACE_STORE(uint32_t, tomax, offs, -+ ecb->dte_epid); -+ dt_dbg_buf(" Store: %p[%ld .. %ld] " -+ "<- %d [EPID] " -+ "(from %s::%d)\n", -+ buf, offs, -+ offs + sizeof(uint32_t) - 1, -+ ecb->dte_epid, -+ __FUNCTION__, __LINE__); -+ } -+ -+ continue; -+ -+ case DTRACEACT_CHILL: -+ if (dtrace_priv_kernel_destructive(state)) -+ dtrace_action_chill(&mstate, -+ ns_to_ktime(val)); -+ -+ continue; -+ -+ case DTRACEACT_RAISE: -+ if (dtrace_priv_proc_destructive(state)) -+ dtrace_action_raise(val); -+ -+ continue; -+ -+ case DTRACEACT_COMMIT: -+ ASSERT(!committed); -+ -+ /* -+ * We need to commit our buffer state. -+ */ -+ if (ecb->dte_size) { -+ buf->dtb_offset = offs + ecb->dte_size; -+ dt_dbg_buf(" Consume: %p[%ld .. " -+ "%lld]\n", -+ buf, offs, -+ buf->dtb_offset - 1); -+ } -+ -+ buf = &state->dts_buffer[cpuid]; -+ dtrace_speculation_commit(state, cpuid, val); -+ committed = 1; -+ continue; -+ -+ case DTRACEACT_DISCARD: -+ dtrace_speculation_discard(state, cpuid, val); -+ continue; -+ -+ case DTRACEACT_DIFEXPR: -+ case DTRACEACT_LIBACT: -+ case DTRACEACT_PRINTF: -+ case DTRACEACT_PRINTA: -+ case DTRACEACT_SYSTEM: -+ case DTRACEACT_FREOPEN: -+ case DTRACEACT_TRACEMEM: -+ case DTRACEACT_PCAP: -+ break; -+ -+ case DTRACEACT_SYM: -+ case DTRACEACT_MOD: -+ if (!dtrace_priv_kernel(state)) -+ continue; -+ break; -+ -+ case DTRACEACT_USYM: -+ case DTRACEACT_UMOD: -+ case DTRACEACT_UADDR: { -+ pid_t pid = current->pid; -+ pid_t tgid = current->tgid; -+ -+ if (!dtrace_priv_proc(state)) -+ continue; -+ -+ DTRACE_STORE(uint64_t, tomax, valoffs, -+ (uint64_t)pid); -+ dt_dbg_buf(" Store: %p[%ld .. %ld] <- %lld " -+ "[PID] (from %s::%d)\n", -+ buf, valoffs, -+ valoffs + sizeof(uint64_t) - 1, -+ (uint64_t)pid, -+ __FUNCTION__, __LINE__); -+ DTRACE_STORE(uint64_t, tomax, -+ valoffs + sizeof(uint64_t), -+ (uint64_t)tgid); -+ dt_dbg_buf(" Store: %p[%ld .. %ld] <- %lld " -+ "[TGID] (from %s::%d)\n", -+ buf, valoffs + sizeof(uint64_t), -+ valoffs + 2 * sizeof(uint64_t) - 1, -+ (uint64_t)tgid, -+ __FUNCTION__, __LINE__); -+ DTRACE_STORE(uint64_t, tomax, -+ valoffs + 2 * sizeof(uint64_t), -+ val); -+ dt_dbg_buf(" Store: %p[%ld .. %ld] <- %lld " -+ "(from %s::%d)\n", -+ buf, valoffs + 2 * sizeof(uint64_t), -+ valoffs + 3 * sizeof(uint64_t) - 1, -+ val, __FUNCTION__, __LINE__); -+ -+ continue; -+ } -+ -+ case DTRACEACT_EXIT: { -+ /* -+ * For the exit action, we are going to attempt -+ * to atomically set our activity to be -+ * draining. If this fails (either because -+ * another CPU has beat us to the exit action, -+ * or because our current activity is something -+ * other than ACTIVE or WARMUP), we will -+ * continue. This assures that the exit action -+ * can be successfully recorded at most once -+ * when we're in the ACTIVE state. If we're -+ * encountering the exit() action while in -+ * COOLDOWN, however, we want to honor the new -+ * status code. (We know that we're the only -+ * thread in COOLDOWN, so there is no race.) -+ */ -+ enum dtrace_activity *activity = -+ &state->dts_activity; -+ enum dtrace_activity curr = -+ state->dts_activity; -+ -+ if (curr == DTRACE_ACTIVITY_COOLDOWN) -+ break; -+ -+ if (curr != DTRACE_ACTIVITY_WARMUP) -+ curr = DTRACE_ACTIVITY_ACTIVE; -+ -+ if (cmpxchg(activity, curr, -+ DTRACE_ACTIVITY_DRAINING) != curr) { -+ *flags |= CPU_DTRACE_DROP; -+ continue; -+ } -+ -+ break; -+ } -+ -+ default: -+ ASSERT(0); -+ } -+ -+ if (dp->dtdo_rtype.dtdt_flags & DIF_TF_BYREF) { -+ uintptr_t end = valoffs + size; -+ -+ if (!dtrace_vcanload((void *)(uintptr_t)val, -+ &dp->dtdo_rtype, &mstate, -+ vstate)) -+ continue; -+ -+ if (act->dta_kind == DTRACEACT_PCAP) { -+ if (dtrace_probe_pcap(val, &valoffs, -+ size, tomax, now, -+ &mstate, vstate, -+ flags) == -1) -+ break; -+ continue; -+ } -+ -+ /* -+ * If this is a string, we're going to only -+ * load until we find the zero byte -- after -+ * which we'll store zero bytes. -+ */ -+ if (dp->dtdo_rtype.dtdt_kind == -+ DIF_TYPE_STRING) { -+ char c = '\0' + 1; -+ int intuple = act->dta_intuple; -+ size_t s; -+ -+ for (s = 0; s < size; s++) { -+ if (c != '\0') -+ c = dtrace_load8(val++); -+ -+ DTRACE_STORE(uint8_t, tomax, -+ valoffs++, c); -+ dt_dbg_buf(" Store: %p[%ld]" -+ " <- %d (from " -+ "%s::%d)\n", -+ buf, valoffs, c, -+ __FUNCTION__, -+ __LINE__); -+ -+ if (c == '\0' && intuple) -+ break; -+ } -+ -+ continue; -+ } -+ -+ while (valoffs < end) { -+ DTRACE_STORE(uint8_t, tomax, valoffs++, -+ dtrace_load8(val++)); -+ dt_dbg_buf(" Store: %p[%ld] <- ??? " -+ "(from %s::%d)\n", -+ buf, valoffs, -+ __FUNCTION__, __LINE__); -+ } -+ -+ continue; -+ } -+ -+ switch (size) { -+ case 0: -+ break; -+ case sizeof(uint8_t): -+ DTRACE_STORE(uint8_t, tomax, valoffs, val); -+ dt_dbg_buf(" Store: %p[%ld] <- %d " -+ "(from %s::%d)\n", -+ buf, valoffs, (uint8_t)val, -+ __FUNCTION__, __LINE__); -+ break; -+ case sizeof(uint16_t): -+ DTRACE_STORE(uint16_t, tomax, valoffs, val); -+ dt_dbg_buf(" Store: %p[%ld .. %ld] <- %d " -+ "(from %s::%d)\n", -+ buf, valoffs, -+ valoffs + sizeof(uint16_t) - 1, -+ (uint16_t)val, -+ __FUNCTION__, __LINE__); -+ break; -+ case sizeof(uint32_t): -+ DTRACE_STORE(uint32_t, tomax, valoffs, val); -+ dt_dbg_buf(" Store: %p[%ld] <- %d " -+ "(from %s::%d)\n", -+ buf, valoffs, -+ (uint32_t)val, -+ __FUNCTION__, __LINE__); -+ break; -+ case sizeof(uint64_t): -+ DTRACE_STORE(uint64_t, tomax, valoffs, val); -+ dt_dbg_buf(" Store: %p[%ld] <- %lld " -+ "(from %s::%d)\n", -+ buf, valoffs, -+ val, -+ __FUNCTION__, __LINE__); -+ break; -+ default: -+ /* -+ * Any other size should have been returned by -+ * reference, not by value. -+ */ -+ ASSERT(0); -+ break; -+ } -+ } -+ -+ if (*flags & CPU_DTRACE_DROP) { -+ dt_dbg_probe(" -> Dropped\n"); -+ continue; -+ } -+ -+ if (*flags & CPU_DTRACE_FAULT) { -+ int ndx; -+ struct dtrace_action *err; -+ -+ dt_dbg_probe(" -> Failed (%x)\n", *flags); -+ -+ buf->dtb_errors++; -+ -+ if (probe->dtpr_id == dtrace_probeid_error) { -+ /* -+ * There's nothing we can do -- we had an -+ * error on the error probe. We bump an -+ * error counter to at least indicate that -+ * this condition happened. -+ */ -+ dtrace_error(&state->dts_dblerrors); -+ continue; -+ } -+ -+ if (vtime && dtsk != NULL) -+ /* -+ * Before recursing on dtrace_probe(), we -+ * need to explicitly clear out our start -+ * time to prevent it from being accumulated -+ * into the dtrace_vtime. -+ */ -+ dtsk->dt_start = ktime_set(0, 0); -+ -+ /* -+ * Iterate over the actions to figure out which action -+ * we were processing when we experienced the error. -+ * Note that act points _past_ the faulting action; if -+ * act is ecb->dte_action, the fault was in the -+ * predicate, if it's ecb->dte_action->dta_next it's -+ * in action #1, and so on. -+ */ -+ for (err = ecb->dte_action, ndx = 0; -+ err != act; err = err->dta_next, ndx++) -+ continue; -+ -+ dtrace_probe_error( -+ state, ecb->dte_epid, ndx, -+ (mstate.dtms_present & DTRACE_MSTATE_FLTOFFS) -+ ? mstate.dtms_fltoffs -+ : -1, -+ DTRACE_FLAGS2FLT(*flags), -+ this_cpu_core->cpuc_dtrace_illval); -+ -+ continue; -+ } -+ -+ if (!committed) { -+ buf->dtb_offset = offs + ecb->dte_size; -+ dt_dbg_buf(" Consume: %p[%ld .. %lld]\n", -+ buf, offs, buf->dtb_offset); -+ } -+ -+ dt_dbg_probe("Probe (ID %d EPID %d) Done\n", -+ id, ecb->dte_epid); -+ } -+ -+ if (vtime && dtsk != NULL) -+ dtsk->dt_start = dtrace_gethrtime(); -+ -+ this_cpu_core->cpuc_current_probe = old_id; -+ DTRACE_SYNC_EXIT_CRITICAL(cookie, re_entry); -+ -+ if (dtsk != NULL && dtsk->dt_sig != 0) { -+ int sig = dtsk->dt_sig; -+ -+ dtsk->dt_sig = 0; -+ -+ send_sig(sig, current, 0); -+ } -+} -+EXPORT_SYMBOL(dtrace_probe); -+ -+int dtrace_probe_init(void) -+{ -+ dtrace_id_t id; -+ -+ dtrace_probe_cachep = KMEM_CACHE(dtrace_probe, SLAB_HWCACHE_ALIGN); -+ if (dtrace_probe_cachep == NULL) -+ return -ENOMEM; -+ -+ idr_init(&dtrace_probe_idr); -+ -+ /* -+ * We create a ID 0 entry as a sentinel, so we can always depend on it -+ * being the very first entry. This is used in functionality that runs -+ * through the list of probes. -+ */ -+ idr_preload(GFP_KERNEL); -+ id = idr_alloc_cyclic(&dtrace_probe_idr, NULL, 0, 0, GFP_NOWAIT); -+ idr_preload_end(); -+ -+ return id == 0 ? 0 : -EAGAIN; -+} -+ -+void dtrace_probe_exit(void) -+{ -+ idr_destroy(&dtrace_probe_idr); -+ kmem_cache_destroy(dtrace_probe_cachep); -+} -+ -+void dtrace_probe_remove_id(dtrace_id_t id) -+{ -+ idr_remove(&dtrace_probe_idr, id); -+} -+ -+struct dtrace_probe *dtrace_probe_lookup_id(dtrace_id_t id) -+{ -+ return idr_find(&dtrace_probe_idr, id); -+} -+ -+static int dtrace_probe_lookup_match(struct dtrace_probe *probe, void *arg) -+{ -+ *((dtrace_id_t *)arg) = probe->dtpr_id; -+ -+ return DTRACE_MATCH_DONE; -+} -+ -+dtrace_id_t dtrace_probe_lookup(dtrace_provider_id_t prid, const char *mod, -+ const char *func, const char *name) -+{ -+ struct dtrace_probekey pkey; -+ dtrace_id_t id; -+ int match; -+ -+ pkey.dtpk_prov = ((struct dtrace_provider *)prid)->dtpv_name; -+ pkey.dtpk_pmatch = &dtrace_match_string; -+ pkey.dtpk_mod = mod; -+ pkey.dtpk_mmatch = mod ? &dtrace_match_string : &dtrace_match_nul; -+ pkey.dtpk_func = func; -+ pkey.dtpk_fmatch = func ? &dtrace_match_string : &dtrace_match_nul; -+ pkey.dtpk_name = name; -+ pkey.dtpk_nmatch = name ? &dtrace_match_string : &dtrace_match_nul; -+ pkey.dtpk_id = DTRACE_IDNONE; -+ -+ mutex_lock(&dtrace_lock); -+ match = dtrace_match(&pkey, DTRACE_PRIV_ALL, -+ make_kuid(init_user_namespace, 0), -+ dtrace_probe_lookup_match, &id); -+ mutex_unlock(&dtrace_lock); -+ -+ ASSERT(match == 1 || match == 0); -+ -+ return match ? id : 0; -+} -+EXPORT_SYMBOL(dtrace_probe_lookup); -+ -+struct dtrace_probe *dtrace_probe_get_next(dtrace_id_t *idp) -+{ -+ return idr_get_next(&dtrace_probe_idr, idp); -+} -+ -+int dtrace_probe_for_each(int (*fn)(int id, void *p, void *data), void *data) -+{ -+ return idr_for_each(&dtrace_probe_idr, fn, data); -+} -diff --git a/dtrace/dtrace_probe_ctx.c b/dtrace/dtrace_probe_ctx.c -new file mode 100644 -index 000000000000..f04b5b269222 ---- /dev/null -+++ b/dtrace/dtrace_probe_ctx.c -@@ -0,0 +1,659 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_probe_ctx.c -+ * DESCRIPTION: DTrace - probe context safe functions -+ * -+ * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/dtrace_cpu.h> -+ -+#include "dtrace.h" -+ -+void dtrace_panic(const char *fmt, ...) -+{ -+ va_list alist; -+ -+ va_start(alist, fmt); -+ vprintk(fmt, alist); -+ va_end(alist); -+ -+ BUG(); -+} -+EXPORT_SYMBOL(dtrace_panic); -+ -+int dtrace_assfail(const char *a, const char *f, int l) -+{ -+ dtrace_panic(KERN_EMERG "assertion failed: %s, file: %s, line: %d", -+ a, f, l); -+ -+ /* -+ * FIXME: We can do better than this. The OpenSolaris DTrace source -+ * states that this cannot be optimized away. -+ */ -+ return a[(uintptr_t)f]; -+} -+EXPORT_SYMBOL(dtrace_assfail); -+ -+#define DT_MASK_LO 0x00000000FFFFFFFFULL -+ -+static void dtrace_add_128(uint64_t *addend1, uint64_t *addend2, uint64_t *sum) -+{ -+ uint64_t result[2]; -+ -+ result[0] = addend1[0] + addend2[0]; -+ result[1] = addend1[1] + addend2[1] + -+ (result[0] < addend1[0] || result[0] < addend2[0] ? 1 : 0); -+ -+ sum[0] = result[0]; -+ sum[1] = result[1]; -+} -+ -+static void dtrace_shift_128(uint64_t *a, int b) -+{ -+ uint64_t mask; -+ -+ if (b == 0) -+ return; -+ -+ if (b < 0) { -+ b = -b; -+ -+ if (b >= 64) { -+ a[0] = a[1] >> (b - 64); -+ a[1] = 0; -+ } else { -+ a[0] >>= b; -+ mask = 1LL << (64 - b); -+ mask -= 1; -+ a[0] |= ((a[1] & mask) << (64 - b)); -+ a[1] >>= b; -+ } -+ } else { -+ if (b >= 64) { -+ a[1] = a[0] << (b - 64); -+ a[0] = 0; -+ } else { -+ a[1] <<= b; -+ mask = a[0] >> (64 - b); -+ a[1] |= mask; -+ a[0] <<= b; -+ } -+ } -+} -+ -+static void dtrace_multiply_128(uint64_t factor1, uint64_t factor2, -+ uint64_t *product) -+{ -+ uint64_t hi1, hi2, lo1, lo2; -+ uint64_t tmp[2]; -+ -+ hi1 = factor1 >> 32; -+ hi2 = factor2 >> 32; -+ -+ lo1 = factor1 & DT_MASK_LO; -+ lo2 = factor2 & DT_MASK_LO; -+ -+ product[0] = lo1 * lo2; -+ product[1] = hi1 * hi2; -+ -+ tmp[0] = hi1 * lo2; -+ tmp[1] = 0; -+ dtrace_shift_128(tmp, 32); -+ dtrace_add_128(product, tmp, product); -+ -+ tmp[0] = hi2 * lo1; -+ tmp[1] = 0; -+ dtrace_shift_128(tmp, 32); -+ dtrace_add_128(product, tmp, product); -+} -+ -+void dtrace_aggregate_min(uint64_t *oval, uint64_t nval, uint64_t arg) -+{ -+ if ((int64_t)nval < (int64_t)*oval) -+ *oval = nval; -+} -+ -+void dtrace_aggregate_max(uint64_t *oval, uint64_t nval, uint64_t arg) -+{ -+ if ((int64_t)nval > (int64_t)*oval) -+ *oval = nval; -+} -+ -+void dtrace_aggregate_quantize(uint64_t *quanta, uint64_t nval, uint64_t incr) -+{ -+ int i, zero = DTRACE_QUANTIZE_ZEROBUCKET; -+ int64_t val = (int64_t)nval; -+ -+ if (val < 0) { -+ for (i = 0; i < zero; i++) { -+ if (val <= DTRACE_QUANTIZE_BUCKETVAL(i)) { -+ quanta[i] += incr; -+ -+ return; -+ } -+ } -+ } else { -+ for (i = zero + 1; i < DTRACE_QUANTIZE_NBUCKETS; i++) { -+ if (val < DTRACE_QUANTIZE_BUCKETVAL(i)) { -+ quanta[i - 1] += incr; -+ -+ return; -+ } -+ } -+ -+ quanta[DTRACE_QUANTIZE_NBUCKETS - 1] += incr; -+ -+ return; -+ } -+ -+ ASSERT(0); -+} -+ -+void dtrace_aggregate_lquantize(uint64_t *lquanta, uint64_t nval, -+ uint64_t incr) -+{ -+ uint64_t arg = *lquanta++; -+ int32_t base = DTRACE_LQUANTIZE_BASE(arg); -+ uint16_t step = DTRACE_LQUANTIZE_STEP(arg); -+ uint16_t levels = DTRACE_LQUANTIZE_LEVELS(arg); -+ int64_t val = (int64_t)nval, level; -+ -+ ASSERT(step != 0); -+ ASSERT(levels != 0); -+ -+ if (val < base) { -+ lquanta[0] += incr; -+ -+ return; -+ } -+ -+ level = (val - base) / step; -+ -+ if (level < levels) { -+ lquanta[level + 1] += incr; -+ -+ return; -+ } -+ -+ lquanta[levels + 1] += incr; -+} -+ -+static uint64_t dtrace_pow(uint64_t base, uint64_t exp) -+{ -+ uint64_t p, r; -+ -+ p = base; -+ r = 1; -+ while (exp > 0) { -+ if (exp & 1) -+ r *= p; -+ -+ p *= p; -+ exp >>= 1; -+ } -+ -+ return (r); -+} -+ -+void dtrace_aggregate_llquantize(uint64_t *llquanta, uint64_t nval, -+ uint64_t incr) -+{ -+ uint64_t arg = *llquanta++; -+ int factor = DTRACE_LLQUANTIZE_FACTOR(arg); -+ int lmag = DTRACE_LLQUANTIZE_LMAG(arg); -+ int hmag = DTRACE_LLQUANTIZE_HMAG(arg); -+ int steps = DTRACE_LLQUANTIZE_STEPS(arg); -+ int i, signbit, steps_factor, mag, underflow_bin; -+ uint64_t val, bucket_max; -+ -+ ASSERT(steps != 0); -+ ASSERT(factor > 1); -+ -+ if (nval >> (64 - 1)) { -+ signbit = -1; -+ val = 1 + ~nval; -+ } else { -+ signbit = +1; -+ val = nval; -+ } -+ -+ /* -+ * Compute steps/factor. -+ * Notice that while we say there are "steps" bins per logarithmic -+ * range, steps/factor of them actually overlap with lower ranges. -+ * E.g., if factor=10 and steps=20, for mag=2 we have the 20 bins -+ * 0 50 100 150 200 250 300 350 ... 800 850 900 950 -+ * but the first two actually belong to lower ranges. -+ */ -+ steps_factor = steps/factor; -+ -+ /* the underflow bin is in the middle */ -+ underflow_bin = 1 + (hmag-lmag+1) * (steps-steps_factor); -+ -+ bucket_max = dtrace_pow(factor, lmag); -+ -+ /* check for "underflow" (smaller than the smallest bin) */ -+ if (val < bucket_max) { -+ llquanta[underflow_bin] += incr; -+ return; -+ } -+ -+ /* loop over the logarithmic ranges */ -+ i = 0; -+ for (mag = lmag; mag <= hmag; mag++) { -+ bucket_max *= factor; -+ if (val >= bucket_max) -+ continue; -+ -+ /* -+ * We want -+ * i = val * steps / bucket_max; -+ * but val*steps could overflow. An alternative is -+ * i = val / ( bucket_max/steps ) -+ * but bucket_max/steps might not divide evenly. -+ * (Plus, we end up with an extra divide.) -+ * -+ * From Solaris, we inherit constraints on factor and steps -+ * that mean bucket_max/steps divides evenly when mag>0. -+ * Meanwhile, if mag==0, val*steps cannot overflow. -+ * So between our two expressions for i, at least one -+ * will work and we just have to pick which one to use. -+ */ -+ if (mag == 0) -+ i = val * steps / bucket_max; -+ else -+ i = val / (bucket_max/steps); -+ -+ // shift for low indices that can never happen -+ i -= steps_factor; -+ break; -+ } -+ i = underflow_bin+signbit*((steps-steps_factor)*(mag-lmag)+i+1); -+ llquanta[i] += incr; -+} -+ -+void dtrace_aggregate_avg(uint64_t *data, uint64_t nval, uint64_t arg) -+{ -+ data[0]++; -+ data[1] += nval; -+} -+ -+void dtrace_aggregate_stddev(uint64_t *data, uint64_t nval, uint64_t arg) -+{ -+ int64_t snval = (int64_t)nval; -+ uint64_t tmp[2]; -+ -+ data[0]++; -+ data[1] += nval; -+ -+ if (snval < 0) -+ snval = -snval; -+ -+ dtrace_multiply_128((uint64_t)snval, (uint64_t)snval, tmp); -+ dtrace_add_128(data + 2, tmp, data + 2); -+} -+ -+void dtrace_aggregate_count(uint64_t *oval, uint64_t nval, uint64_t arg) -+{ -+ *oval = *oval + 1; -+} -+ -+void dtrace_aggregate_sum(uint64_t *oval, uint64_t nval, uint64_t arg) -+{ -+ *oval += nval; -+} -+ -+/* -+ * DTrace Aggregation Buffers -+ * -+ * Aggregation buffers use much of the same mechanism as described above -+ * ("DTrace Buffers"). However, because an aggregation is fundamentally a -+ * hash, there exists dynamic metadata associated with an aggregation buffer -+ * that is not associated with other kinds of buffers. This aggregation -+ * metadata is _only_ relevant for the in-kernel implementation of -+ * aggregations; it is not actually relevant to user-level consumers. To do -+ * this, we allocate dynamic aggregation data (hash keys and hash buckets) -+ * starting below the _limit_ of the buffer, and we allocate data from the -+ * _base_ of the buffer. When the aggregation buffer is copied out, _only_ the -+ * data is copied out; the metadata is simply discarded. Schematically, -+ * aggregation buffers look like: -+ * -+ * base of data buffer ---> +-------+------+-----------+-------+ -+ * | aggid | key | value | aggid | -+ * +-------+------+-----------+-------+ -+ * | key | -+ * +-------+-------+-----+------------+ -+ * | value | aggid | key | value | -+ * +-------+------++-----+------+-----+ -+ * | aggid | key | value | | -+ * +-------+------+-------------+ | -+ * | || | -+ * | || | -+ * | \/ | -+ * : : -+ * . . -+ * . . -+ * . . -+ * : : -+ * | /\ | -+ * | || +------------+ -+ * | || | | -+ * +---------------------+ | -+ * | hash keys | -+ * | (dtrace_aggkey structures) | -+ * | | -+ * +----------------------------------+ -+ * | hash buckets | -+ * | (dtrace_aggbuffer structure) | -+ * | | -+ * limit of data buffer ---> +----------------------------------+ -+ * -+ * As implied above, just as we assure that ECBs always store a constant -+ * amount of data, we assure that a given aggregation -- identified by its -+ * aggregation ID -- always stores data of a constant quantity and type. -+ * As with EPIDs, this allows the aggregation ID to serve as the metadata for a -+ * given record. -+ * -+ * Note that the size of the dtrace_aggkey structure must be sizeof (uintptr_t) -+ * aligned. (If this the structure changes such that this becomes false, an -+ * assertion will fail in dtrace_aggregate().) -+ */ -+#define DTRACE_AGGHASHSIZE_SLEW 17 -+ -+struct dtrace_aggkey { -+ uint32_t dtak_hashval; /* hash value */ -+ uint32_t dtak_action:4; /* action -- 4 bits */ -+ uint32_t dtak_size:28; /* size -- 28 bits */ -+ caddr_t dtak_data; /* data pointer */ -+ struct dtrace_aggkey *dtak_next; /* next in hash chain */ -+}; -+ -+struct dtrace_aggbuffer { -+ uintptr_t dtagb_hashsize; /* number of buckets */ -+ uintptr_t dtagb_free; /* free list of keys */ -+ struct dtrace_aggkey **dtagb_hash; /* hash table */ -+}; -+ -+#define DTRACEACT_ISSTRING(act) \ -+ ((act)->dta_kind == DTRACEACT_DIFEXPR && \ -+ (act)->dta_difo->dtdo_rtype.dtdt_kind == DIF_TYPE_STRING) -+ -+/* -+ * Aggregate given the tuple in the principal data buffer, and the aggregating -+ * action denoted by the specified dtrace_aggregation_t. The aggregation -+ * buffer is specified as the buf parameter. This routine does not return -+ * failure; if there is no space in the aggregation buffer, the data will be -+ * dropped, and a corresponding counter incremented. -+ */ -+void dtrace_aggregate(struct dtrace_aggregation *agg, -+ struct dtrace_buffer *dbuf, -+ intptr_t offset, struct dtrace_buffer *buf, -+ uint64_t expr, uint64_t arg) -+{ -+ struct dtrace_recdesc *rec = &agg->dtag_action.dta_rec; -+ uint32_t i, ndx, size, fsize; -+ uint32_t align = sizeof(uint64_t) - 1; -+ struct dtrace_aggbuffer *agb; -+ struct dtrace_aggkey *key; -+ uint32_t hashval = 0, limit, isstr; -+ caddr_t tomax, data, kdata; -+ dtrace_actkind_t action; -+ struct dtrace_action *act; -+ uintptr_t offs; -+ -+ if (buf == NULL) -+ return; -+ -+ if (!agg->dtag_hasarg) -+ /* -+ * Currently, only quantize(), lquantize() and llquantize() -+ * take additional arguments, and they have the same semantics: -+ * an increment value that defaults to 1 when not present. If -+ * additional aggregating actions take arguments, the setting -+ * of the default argument value will presumably have to -+ * become more sophisticated... -+ */ -+ arg = 1; -+ -+ action = agg->dtag_action.dta_kind - DTRACEACT_AGGREGATION; -+ size = rec->dtrd_offset - agg->dtag_base; -+ fsize = size + rec->dtrd_size; -+ -+ ASSERT(dbuf->dtb_tomax != NULL); -+ data = dbuf->dtb_tomax + offset + agg->dtag_base; -+ -+ tomax = buf->dtb_tomax; -+ if (tomax == NULL) { -+ dtrace_buffer_drop(buf); -+ return; -+ } -+ -+ /* -+ * The metastructure is always at the bottom of the buffer. -+ */ -+ agb = (struct dtrace_aggbuffer *)(tomax + buf->dtb_size - -+ sizeof(struct dtrace_aggbuffer)); -+ -+ if (buf->dtb_offset == 0) { -+ /* -+ * We just kludge up approximately 1/8th of the size to be -+ * buckets. If this guess ends up being routinely -+ * off-the-mark, we may need to dynamically readjust this -+ * based on past performance. -+ */ -+ uintptr_t hashsize = (buf->dtb_size >> 3) / -+ sizeof(uintptr_t); -+ -+ if ((uintptr_t)agb - hashsize * sizeof(struct dtrace_aggkey *) < -+ (uintptr_t)tomax || hashsize == 0) { -+ /* -+ * We've been given a ludicrously small buffer; -+ * increment our drop count and leave. -+ */ -+ dtrace_buffer_drop(buf); -+ return; -+ } -+ -+ /* -+ * And now, a pathetic attempt to try to get a an odd (or -+ * perchance, a prime) hash size for better hash distribution. -+ */ -+ if (hashsize > (DTRACE_AGGHASHSIZE_SLEW << 3)) -+ hashsize -= DTRACE_AGGHASHSIZE_SLEW; -+ -+ agb->dtagb_hashsize = hashsize; -+ agb->dtagb_hash = (struct dtrace_aggkey **)((uintptr_t)agb - -+ agb->dtagb_hashsize * sizeof(struct dtrace_aggkey *)); -+ agb->dtagb_free = (uintptr_t)agb->dtagb_hash; -+ -+ for (i = 0; i < agb->dtagb_hashsize; i++) -+ agb->dtagb_hash[i] = NULL; -+ } -+ -+ ASSERT(agg->dtag_first != NULL); -+ ASSERT(agg->dtag_first->dta_intuple); -+ -+ /* -+ * Calculate the hash value based on the key. Note that we _don't_ -+ * include the aggid in the hashing (but we will store it as part of -+ * the key). The hashing algorithm is Bob Jenkins' "One-at-a-time" -+ * algorithm: a simple, quick algorithm that has no known funnels, and -+ * gets good distribution in practice. The efficacy of the hashing -+ * algorithm (and a comparison with other algorithms) may be found by -+ * running the ::dtrace_aggstat MDB dcmd. -+ */ -+ for (act = agg->dtag_first; act->dta_intuple; act = act->dta_next) { -+ i = act->dta_rec.dtrd_offset - agg->dtag_base; -+ limit = i + act->dta_rec.dtrd_size; -+ ASSERT(limit <= size); -+ isstr = DTRACEACT_ISSTRING(act); -+ -+ for (; i < limit; i++) { -+ hashval += data[i]; -+ hashval += (hashval << 10); -+ hashval ^= (hashval >> 6); -+ -+ if (isstr && data[i] == '\0') -+ break; -+ } -+ } -+ -+ hashval += (hashval << 3); -+ hashval ^= (hashval >> 11); -+ hashval += (hashval << 15); -+ -+ /* -+ * Yes, the divide here is expensive -- but it's generally the least -+ * of the performance issues given the amount of data that we iterate -+ * over to compute hash values, compare data, etc. -+ */ -+ ndx = hashval % agb->dtagb_hashsize; -+ -+ for (key = agb->dtagb_hash[ndx]; key != NULL; key = key->dtak_next) { -+ ASSERT((caddr_t)key >= tomax); -+ ASSERT((caddr_t)key < tomax + buf->dtb_size); -+ -+ if (hashval != key->dtak_hashval || key->dtak_size != size) -+ continue; -+ -+ kdata = key->dtak_data; -+ ASSERT(kdata >= tomax && kdata < tomax + buf->dtb_size); -+ -+ for (act = agg->dtag_first; act->dta_intuple; -+ act = act->dta_next) { -+ i = act->dta_rec.dtrd_offset - agg->dtag_base; -+ limit = i + act->dta_rec.dtrd_size; -+ ASSERT(limit <= size); -+ isstr = DTRACEACT_ISSTRING(act); -+ -+ for (; i < limit; i++) { -+ if (kdata[i] != data[i]) -+ goto next; -+ -+ if (isstr && data[i] == '\0') -+ break; -+ } -+ } -+ -+ if (action != key->dtak_action) { -+ /* -+ * We are aggregating on the same value in the same -+ * aggregation with two different aggregating actions. -+ * (This should have been picked up in the compiler, -+ * so we may be dealing with errant or devious DIF.) -+ * This is an error condition; we indicate as much, -+ * and return. -+ */ -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); -+ return; -+ } -+ -+ /* -+ * This is a hit: we need to apply the aggregator to -+ * the value at this key. -+ */ -+ dt_dbg_agg(" Aggregate [accum]: Buf %p, offs %d, act %d, " -+ "%lld (%lld, %lld)\n", -+ buf, size, -+ agg->dtag_action.dta_kind - DTRACEACT_AGGREGATION, -+ *(uint64_t *)(kdata + size), expr, arg); -+ agg->dtag_aggregate((uint64_t *)(kdata + size), expr, arg); -+ return; -+next: -+ continue; -+ } -+ -+ /* -+ * We didn't find it. We need to allocate some zero-filled space, -+ * link it into the hash table appropriately, and apply the aggregator -+ * to the (zero-filled) value. -+ */ -+ offs = buf->dtb_offset; -+ while (offs & (align - 1)) -+ offs += sizeof(uint32_t); -+ -+ /* -+ * If we don't have enough room to both allocate a new key _and_ -+ * its associated data, increment the drop count and return. -+ */ -+ if ((uintptr_t)tomax + offs + fsize > -+ agb->dtagb_free - sizeof(struct dtrace_aggkey)) { -+ dtrace_buffer_drop(buf); -+ return; -+ } -+ -+ ASSERT(!(sizeof(struct dtrace_aggkey) & (sizeof(uintptr_t) - 1))); -+ key = (struct dtrace_aggkey *) -+ (agb->dtagb_free - sizeof(struct dtrace_aggkey)); -+ agb->dtagb_free -= sizeof(struct dtrace_aggkey); -+ -+ key->dtak_data = kdata = tomax + offs; -+ buf->dtb_offset = offs + fsize; -+ -+ /* -+ * Now copy the data across. -+ */ -+ *((dtrace_aggid_t *)kdata) = agg->dtag_id; -+ -+ for (i = sizeof(dtrace_aggid_t); i < size; i++) -+ kdata[i] = data[i]; -+ -+ /* -+ * Because strings are not zeroed out by default, we need to iterate -+ * looking for actions that store strings, and we need to explicitly -+ * pad these strings out with zeroes. -+ */ -+ for (act = agg->dtag_first; act->dta_intuple; act = act->dta_next) { -+ int nul; -+ -+ if (!DTRACEACT_ISSTRING(act)) -+ continue; -+ -+ i = act->dta_rec.dtrd_offset - agg->dtag_base; -+ limit = i + act->dta_rec.dtrd_size; -+ ASSERT(limit <= size); -+ -+ for (nul = 0; i < limit; i++) { -+ if (nul) { -+ kdata[i] = '\0'; -+ continue; -+ } -+ -+ if (data[i] != '\0') -+ continue; -+ -+ nul = 1; -+ } -+ } -+ -+ for (i = size; i < fsize; i++) -+ kdata[i] = 0; -+ -+ key->dtak_hashval = hashval; -+ key->dtak_size = size; -+ key->dtak_action = action; -+ key->dtak_next = agb->dtagb_hash[ndx]; -+ agb->dtagb_hash[ndx] = key; -+ -+ /* -+ * Finally, apply the aggregator. -+ */ -+ *((uint64_t *)(key->dtak_data + size)) = agg->dtag_initial; -+ dt_dbg_agg(" Aggregate [initial]: Buf %p, offs %d, act %d, " -+ "%lld (%lld, %lld)\n", -+ buf, size, -+ agg->dtag_action.dta_kind - DTRACEACT_AGGREGATION, -+ *(uint64_t *)(key->dtak_data + size), expr, arg); -+ agg->dtag_aggregate((uint64_t *)(key->dtak_data + size), expr, arg); -+} -diff --git a/dtrace/dtrace_ptofapi.c b/dtrace/dtrace_ptofapi.c -new file mode 100644 -index 000000000000..c42a8471879c ---- /dev/null -+++ b/dtrace/dtrace_ptofapi.c -@@ -0,0 +1,649 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_ptofapi.c -+ * DESCRIPTION: DTrace - (meta) provider-to-framework API -+ * -+ * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/idr.h> -+#include <linux/list.h> -+#include <linux/module.h> -+#include <linux/slab.h> -+ -+#include "dtrace.h" -+ -+struct dtrace_provider *dtrace_provider; -+struct dtrace_meta *dtrace_meta_pid; -+struct dtrace_helpers *dtrace_deferred_pid; -+ -+DEFINE_MUTEX(dtrace_provider_lock); -+DEFINE_MUTEX(dtrace_meta_lock); -+ -+/* -+ * Register the calling provider with the DTrace core. This should generally -+ * be called by providers during module initialization. -+ */ -+int dtrace_register(const char *name, const struct dtrace_pattr *pap, -+ uint32_t priv, const struct cred *cr, -+ const struct dtrace_pops *pops, void *arg, -+ dtrace_provider_id_t *idp) -+{ -+ struct dtrace_provider *provider; -+ -+ if (name == NULL || pap == NULL || pops == NULL || idp == NULL) { -+ pr_warn("Failed to register provider %s: invalid args\n", -+ name ? name : "<NULL>"); -+ return -EINVAL; -+ } -+ -+ if (name[0] == '\0' || dtrace_badname(name)) { -+ pr_warn("Failed to register provider %s: invalid name\n", -+ name); -+ return -EINVAL; -+ } -+ -+ if ((pops->dtps_provide == NULL && pops->dtps_provide_module == NULL) || -+ pops->dtps_enable == NULL || pops->dtps_disable == NULL || -+ pops->dtps_destroy == NULL || -+ ((pops->dtps_resume == NULL) != (pops->dtps_suspend == NULL))) { -+ pr_warn("Failed to register provider %s: invalid ops\n", -+ name); -+ return -EINVAL; -+ } -+ -+ if (dtrace_badattr(&pap->dtpa_provider) || -+ dtrace_badattr(&pap->dtpa_mod) || -+ dtrace_badattr(&pap->dtpa_func) || -+ dtrace_badattr(&pap->dtpa_name) || -+ dtrace_badattr(&pap->dtpa_args)) { -+ pr_warn("Failed to register provider %s: invalid attributes\n", -+ name); -+ return -EINVAL; -+ } -+ -+ if (priv & ~DTRACE_PRIV_ALL) { -+ pr_warn("Failed to register provider %s: invalid privilege " -+ "attributes\n", name); -+ return -EINVAL; -+ } -+ -+ if ((priv & DTRACE_PRIV_KERNEL) && -+ (priv & (DTRACE_PRIV_USER | DTRACE_PRIV_OWNER)) && -+ pops->dtps_usermode == NULL) { -+ pr_warn("Failed to register provider %s: need " -+ "dtps_usermode() op for given privilege " -+ "attributes\n", name); -+ return -EINVAL; -+ } -+ -+ dt_dbg_prov("Registering provider '%s'...\n", name); -+ provider = kzalloc(sizeof(struct dtrace_provider), GFP_KERNEL); -+ if (provider == NULL) { -+ dt_dbg_prov(" Failed to allocate provider struct\n"); -+ return -ENOMEM; -+ } -+ provider->dtpv_name = dtrace_strdup(name); -+ if (provider->dtpv_name == NULL) { -+ kfree(provider); -+ dt_dbg_prov(" Failed to allocate provider name\n"); -+ return -ENOMEM; -+ } -+ provider->dtpv_attr = *pap; -+ provider->dtpv_priv.dtpp_flags = priv; -+ -+ if (cr != NULL) { -+ provider->dtpv_priv.dtpp_uid = -+ from_kuid(init_user_namespace, get_cred(cr)->uid); -+ put_cred(cr); -+ } -+ -+ provider->dtpv_pops = *pops; -+ -+ if (pops->dtps_provide == NULL) { -+ ASSERT(pops->dtps_provide_module != NULL); -+ provider->dtpv_pops.dtps_provide = -+ (void (*)(void *, const struct dtrace_probedesc *)) -+ dtrace_nullop; -+ } -+ -+ if (pops->dtps_provide_module == NULL) { -+ ASSERT(pops->dtps_provide != NULL); -+ provider->dtpv_pops.dtps_provide_module = -+ (void (*)(void *, struct module *))dtrace_nullop; -+ } -+ -+ if (pops->dtps_destroy_module == NULL) { -+ provider->dtpv_pops.dtps_destroy_module = -+ (void (*)(void *, struct module *))dtrace_nullop; -+ } -+ -+ if (pops->dtps_suspend == NULL) { -+ ASSERT(pops->dtps_resume == NULL); -+ provider->dtpv_pops.dtps_suspend = -+ (void (*)(void *, dtrace_id_t, void *))dtrace_nullop; -+ provider->dtpv_pops.dtps_resume = -+ (void (*)(void *, dtrace_id_t, void *))dtrace_nullop; -+ } -+ -+ provider->dtpv_arg = arg; -+ *idp = (dtrace_provider_id_t)provider; -+ -+ if (pops == &dtrace_provider_ops) { -+ ASSERT(MUTEX_HELD(&dtrace_provider_lock)); -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ ASSERT(dtrace_anon.dta_enabling == NULL); -+ -+ /* -+ * The DTrace provider must be at the head of the provider -+ * chain. -+ */ -+ provider->dtpv_next = dtrace_provider; -+ dtrace_provider = provider; -+ -+ dt_dbg_prov(" Done registering %s\n", name); -+ -+ return 0; -+ } -+ -+ mutex_lock(&module_mutex); -+ mutex_lock(&dtrace_provider_lock); -+ mutex_lock(&dtrace_lock); -+ -+ /* -+ * If there is at least one provider registered, we'll add this new one -+ * after the first provider. -+ */ -+ if (dtrace_provider != NULL) { -+ provider->dtpv_next = dtrace_provider->dtpv_next; -+ dtrace_provider->dtpv_next = provider; -+ } else -+ dtrace_provider = provider; -+ -+ if (dtrace_retained != NULL) { -+ dt_dbg_prov(" Processing retained enablings for %s\n", name); -+ dtrace_enabling_provide(provider); -+ -+ /* -+ * We must now call dtrace_enabling_matchall() which needs to -+ * acquire cpu_lock and dtrace_lock. We therefore need to drop -+ * our locks before calling it. -+ */ -+ mutex_unlock(&dtrace_lock); -+ mutex_unlock(&dtrace_provider_lock); -+ mutex_unlock(&module_mutex); -+ dtrace_enabling_matchall(); -+ -+ dt_dbg_prov(" Done registering %s\n", name); -+ -+ return 0; -+ } -+ -+ mutex_unlock(&dtrace_lock); -+ mutex_unlock(&dtrace_provider_lock); -+ mutex_unlock(&module_mutex); -+ -+ dt_dbg_prov(" Done registering %s\n", name); -+ -+ return 0; -+} -+EXPORT_SYMBOL(dtrace_register); -+ -+struct unreg_state { -+ struct dtrace_provider *prov; -+ struct dtrace_probe *first; -+}; -+ -+/* -+ * Check whether the given probe is still enabled for the given provider. -+ */ -+static int dtrace_unregister_check(int id, void *p, void *data) -+{ -+ struct dtrace_probe *probe = (struct dtrace_probe *)p; -+ struct unreg_state *st = (struct unreg_state *)data; -+ -+ if (probe->dtpr_provider != st->prov) -+ return 0; -+ -+ if (probe->dtpr_ecb == NULL) -+ return 0; -+ -+ return -EBUSY; -+} -+ -+/* -+ * Remove the given probe from the hash tables and the probe IDR, if it is -+ * associated with the given provider. The probes are chained for further -+ * processing. -+ */ -+static int dtrace_unregister_probe(int id, void *p, void *data) -+{ -+ struct dtrace_probe *probe = (struct dtrace_probe *)p; -+ struct unreg_state *st = (struct unreg_state *)data; -+ -+ if (probe->dtpr_provider != st->prov) -+ return 0; -+ -+ dtrace_hash_remove(dtrace_bymod, probe); -+ dtrace_hash_remove(dtrace_byfunc, probe); -+ dtrace_hash_remove(dtrace_byname, probe); -+ -+ if (st->first == NULL) { -+ st->first = probe; -+ probe->dtpr_nextmod = NULL; -+ } else { -+ probe->dtpr_nextmod = st->first; -+ st->first = probe; -+ } -+ -+ return 0; -+} -+ -+/* -+ * Remove the given probe from the hash tables and the probe IDR, if it is -+ * associated with the given provider and if it does not have any enablings. -+ * The probes are chained for further processing. -+ */ -+static int dtrace_condense_probe(int id, void *p, void *data) -+{ -+ struct dtrace_probe *probe = (struct dtrace_probe *)p; -+ struct unreg_state *st = (struct unreg_state *)data; -+ -+ if (probe->dtpr_provider != st->prov) -+ return 0; -+ -+ if (probe->dtpr_ecb == NULL) -+ return 0; -+ -+ dtrace_hash_remove(dtrace_bymod, probe); -+ dtrace_hash_remove(dtrace_byfunc, probe); -+ dtrace_hash_remove(dtrace_byname, probe); -+ -+ if (st->first == NULL) { -+ st->first = probe; -+ probe->dtpr_nextmod = NULL; -+ } else { -+ probe->dtpr_nextmod = st->first; -+ st->first = probe; -+ } -+ -+ return 0; -+} -+ -+/* -+ * Unregister the specified provider from the DTrace core. This should be -+ * called by provider during module cleanup. -+ * -+ * The mutex_lock is already held during this call. -+ */ -+int dtrace_unregister(dtrace_provider_id_t id) -+{ -+ struct dtrace_provider *old = (struct dtrace_provider *)id; -+ struct dtrace_provider *prev = NULL; -+ int err, self = 0; -+ struct dtrace_probe *probe; -+ struct unreg_state st = { old, NULL }; -+ -+ ASSERT(MUTEX_HELD(&module_mutex)); -+ -+ dt_dbg_prov("Unregistering provider '%s'...\n", old->dtpv_name); -+ -+ if (old->dtpv_pops.dtps_enable == -+ (int (*)(void *, dtrace_id_t, void *))dtrace_enable_nullop) { -+ /* -+ * When the provider is the DTrace core itself, we're called -+ * with locks already held. -+ */ -+ ASSERT(old == dtrace_provider); -+ ASSERT(MUTEX_HELD(&dtrace_provider_lock)); -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ -+ self = 1; -+ -+ if (dtrace_provider->dtpv_next != NULL) { -+ /* -+ * We cannot and should not remove the DTrace provider -+ * if there is any other provider left. -+ */ -+ dt_dbg_prov(" Failed to unregister %s - not last\n", -+ old->dtpv_name); -+ -+ return -EBUSY; -+ } -+ } else { -+ mutex_lock(&dtrace_provider_lock); -+ mutex_lock(&dtrace_lock); -+ } -+ -+ /* -+ * If /dev/dtrace/dtrace is still held open by a process, or if there -+ * are anonymous probes that are still enabled, we refuse to deregister -+ * providers, unless the provider has been invalidated explicitly. -+ */ -+ if (!old->dtpv_defunct && -+ (dtrace_opens || (dtrace_anon.dta_state != NULL && -+ dtrace_anon.dta_state->dts_necbs > 0))) { -+ if (!self) { -+ mutex_unlock(&dtrace_lock); -+ mutex_unlock(&dtrace_provider_lock); -+ } -+ -+ dt_dbg_prov(" Failed to unregister %s - dtrace in use\n", -+ old->dtpv_name); -+ -+ return -EBUSY; -+ } -+ -+ /* -+ * Check whether any of the probes associated with this provider are -+ * still enabled (having at least one ECB). If any are found, we -+ * cannot remove this provider. -+ */ -+ st.prov = old; -+ err = dtrace_probe_for_each(dtrace_unregister_check, &st); -+ if (err < 0) { -+ if (!self) { -+ mutex_unlock(&dtrace_lock); -+ mutex_unlock(&dtrace_provider_lock); -+ } -+ -+ dt_dbg_prov(" Failed to unregister %s - provider in use\n", -+ old->dtpv_name); -+ -+ return err; -+ } -+ -+ /* -+ * All the probes associated with this provider are disabled. We can -+ * safely remove these probes from the hashtables and the probe array. -+ * We chain all the probes together for further processing. -+ */ -+ dtrace_probe_for_each(dtrace_unregister_probe, &st); -+ -+ /* -+ * The probes associated with the provider have been removed. Ensure -+ * synchronization on probe IDR processing. -+ */ -+ dtrace_sync(); -+ -+ /* -+ * Now get rid of the actual probes. -+ */ -+ for (probe = st.first; probe != NULL; probe = st.first) { -+ int probe_id = probe->dtpr_id; -+ -+ st.first = probe->dtpr_nextmod; -+ -+ old->dtpv_pops.dtps_destroy(old->dtpv_arg, probe_id, -+ probe->dtpr_arg); -+ -+ kfree(probe->dtpr_mod); -+ kfree(probe->dtpr_func); -+ kfree(probe->dtpr_name); -+ kmem_cache_free(dtrace_probe_cachep, probe); -+ -+ dtrace_probe_remove_id(probe_id); -+ } -+ -+ prev = dtrace_provider; -+ if (prev == old) { -+ /* -+ * We are removing the provider at the head of the chain. -+ */ -+ ASSERT(self); -+ ASSERT(old->dtpv_next == NULL); -+ -+ dtrace_provider = old->dtpv_next; -+ } else { -+ while (prev != NULL && prev->dtpv_next != old) -+ prev = prev->dtpv_next; -+ -+ if (prev == NULL) { -+ pr_err("Attempt to unregister non-existent DTrace " -+ "provider %p\n", (void *)id); -+ BUG(); -+ } -+ -+ prev->dtpv_next = old->dtpv_next; -+ } -+ -+ if (!self) { -+ mutex_unlock(&dtrace_lock); -+ mutex_unlock(&dtrace_provider_lock); -+ } -+ -+ kfree(old->dtpv_name); -+ kfree(old); -+ -+ dt_dbg_prov(" Done unregistering\n"); -+ -+ return 0; -+} -+EXPORT_SYMBOL(dtrace_unregister); -+ -+/* -+ * Invalidate the specified provider. All subsequent probe lookups for the -+ * specified provider will fail, but the probes will not be removed. -+ */ -+void dtrace_invalidate(dtrace_provider_id_t id) -+{ -+ struct dtrace_provider *pvp = (struct dtrace_provider *)id; -+ -+ ASSERT(pvp->dtpv_pops.dtps_enable != -+ (int (*)(void *, dtrace_id_t, void *))dtrace_enable_nullop); -+ -+ mutex_lock(&dtrace_provider_lock); -+ mutex_lock(&dtrace_lock); -+ -+ pvp->dtpv_defunct = 1; -+ -+ mutex_unlock(&dtrace_lock); -+ mutex_unlock(&dtrace_provider_lock); -+} -+EXPORT_SYMBOL(dtrace_invalidate); -+ -+/* -+ * Indicate whether or not DTrace has attached. -+ */ -+int dtrace_attached(void) -+{ -+ /* -+ * dtrace_provider will be non-NULL iff the DTrace driver has -+ * attached. (It's non-NULL because DTrace is always itself a -+ * provider.) -+ */ -+ return dtrace_provider != NULL; -+} -+EXPORT_SYMBOL(dtrace_attached); -+ -+/* -+ * Remove all the unenabled probes for the given provider. This function is -+ * not unlike dtrace_unregister(), except that it doesn't remove the provider -+ * -- just as many of its associated probes as it can. -+ */ -+int dtrace_condense(dtrace_provider_id_t id) -+{ -+ struct dtrace_provider *prov = (struct dtrace_provider *)id; -+ struct dtrace_probe *probe; -+ struct unreg_state st = { prov, NULL }; -+ -+ /* -+ * Make sure this isn't the DTrace provider itself. -+ */ -+ ASSERT(prov->dtpv_pops.dtps_enable != -+ (int (*)(void *, dtrace_id_t, void *))dtrace_enable_nullop); -+ -+ mutex_lock(&dtrace_provider_lock); -+ mutex_lock(&dtrace_lock); -+ -+ /* -+ * Attempt to destroy the probes associated with this provider. -+ */ -+ dtrace_probe_for_each(dtrace_condense_probe, &st); -+ -+ /* -+ * The probes associated with the provider have been removed. Ensure -+ * synchronization on probe IDR processing. -+ */ -+ dtrace_sync(); -+ -+ /* -+ * Now get rid of the actual probes. -+ */ -+ for (probe = st.first; probe != NULL; probe = st.first) { -+ int probe_id = probe->dtpr_id; -+ -+ st.first = probe->dtpr_nextmod; -+ -+ prov->dtpv_pops.dtps_destroy(prov->dtpv_arg, probe_id, -+ probe->dtpr_arg); -+ -+ kfree(probe->dtpr_mod); -+ kfree(probe->dtpr_func); -+ kfree(probe->dtpr_name); -+ kfree(probe); -+ -+ dtrace_probe_remove_id(probe_id); -+ } -+ -+ mutex_unlock(&dtrace_lock); -+ mutex_unlock(&dtrace_provider_lock); -+ -+ return 0; -+} -+EXPORT_SYMBOL(dtrace_condense); -+ -+int dtrace_meta_register(const char *name, const struct dtrace_mops *mops, -+ void *arg, dtrace_meta_provider_id_t *idp) -+{ -+ struct dtrace_meta *meta; -+ struct dtrace_helpers *help, *next; -+ int i; -+ -+ *idp = DTRACE_METAPROVNONE; -+ -+ /* -+ * We strictly don't need the name, but we hold onto it for -+ * debuggability. All hail error queues! -+ */ -+ if (name == NULL) { -+ pr_warn("failed to register meta-provider: invalid name\n"); -+ return -EINVAL; -+ } -+ -+ if (mops == NULL || -+ mops->dtms_create_probe == NULL || -+ mops->dtms_provide_pid == NULL || -+ mops->dtms_remove_pid == NULL) { -+ pr_warn("failed to register meta-register %s: invalid ops\n", -+ name); -+ return -EINVAL; -+ } -+ -+ dt_dbg_prov("Registering provider '%s'...\n", name); -+ meta = kzalloc(sizeof(struct dtrace_meta), GFP_KERNEL); -+ if (meta == NULL) { -+ dt_dbg_prov(" Failed to allocate meta provider struct\n"); -+ return -ENOMEM; -+ } -+ meta->dtm_mops = *mops; -+ meta->dtm_name = kmalloc(strlen(name) + 1, GFP_KERNEL); -+ if (meta->dtm_name == NULL) { -+ kfree(meta); -+ dt_dbg_prov(" Failed to allocate meta provider name\n"); -+ return -ENOMEM; -+ } -+ strcpy(meta->dtm_name, name); -+ meta->dtm_arg = arg; -+ -+ mutex_lock(&dtrace_meta_lock); -+ mutex_lock(&dtrace_lock); -+ -+ if (dtrace_meta_pid != NULL) { -+ mutex_unlock(&dtrace_lock); -+ mutex_unlock(&dtrace_meta_lock); -+ pr_warn("failed to register meta-register %s: user-land " -+ "meta-provider exists", name); -+ kfree(meta->dtm_name); -+ kfree(meta); -+ return -EINVAL; -+ } -+ -+ dtrace_meta_pid = meta; -+ *idp = (dtrace_meta_provider_id_t)meta; -+ -+ /* -+ * If there are providers and probes ready to go, pass them -+ * off to the new meta provider now. -+ */ -+ help = dtrace_deferred_pid; -+ dtrace_deferred_pid = NULL; -+ -+ mutex_unlock(&dtrace_lock); -+ -+ while (help != NULL) { -+ for (i = 0; i < help->dthps_nprovs; i++) { -+ dtrace_helper_provide(&help->dthps_provs[i]->dthp_prov, -+ help->dthps_pid); -+ } -+ -+ next = help->dthps_next; -+ help->dthps_next = NULL; -+ help->dthps_prev = NULL; -+ help->dthps_deferred = 0; -+ help = next; -+ } -+ -+ mutex_unlock(&dtrace_meta_lock); -+ -+ dt_dbg_prov(" Done registering %s\n", name); -+ -+ return 0; -+} -+EXPORT_SYMBOL(dtrace_meta_register); -+ -+int dtrace_meta_unregister(dtrace_meta_provider_id_t id) -+{ -+ struct dtrace_meta **pp, *old = (struct dtrace_meta *)id; -+ -+ dt_dbg_prov("Unregistering meta provider '%s'...\n", old->dtm_name); -+ mutex_lock(&dtrace_meta_lock); -+ mutex_lock(&dtrace_lock); -+ -+ if (old == dtrace_meta_pid) { -+ pp = &dtrace_meta_pid; -+ } else { -+ pr_err("Attempt to unregister non-existent DTrace meta-" -+ "provider %p\n", (void *)old); -+ BUG(); -+ } -+ -+ if (old->dtm_count != 0) { -+ mutex_unlock(&dtrace_lock); -+ mutex_unlock(&dtrace_meta_lock); -+ return -EBUSY; -+ } -+ -+ *pp = NULL; -+ -+ mutex_unlock(&dtrace_lock); -+ mutex_unlock(&dtrace_meta_lock); -+ -+ kfree(old->dtm_name); -+ kfree(old); -+ -+ dt_dbg_prov(" Done unregistering\n"); -+ -+ return 0; -+} -+EXPORT_SYMBOL(dtrace_meta_unregister); -diff --git a/dtrace/dtrace_spec.c b/dtrace/dtrace_spec.c -new file mode 100644 -index 000000000000..4ca9bb7a6427 ---- /dev/null -+++ b/dtrace/dtrace_spec.c -@@ -0,0 +1,434 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_spec.c -+ * DESCRIPTION: DTrace - speculation implementation -+ * -+ * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/dtrace_cpu.h> -+#include <linux/smp.h> -+#include <asm/cmpxchg.h> -+ -+#include "dtrace.h" -+ -+/* -+ * Given consumer state, this routine finds a speculation in the INACTIVE -+ * state and transitions it into the ACTIVE state. If there is no speculation -+ * in the INACTIVE state, 0 is returned. In this case, no error counter is -+ * incremented -- it is up to the caller to take appropriate action. -+ */ -+int dtrace_speculation(struct dtrace_state *state) -+{ -+ int i = 0; -+ uint32_t count, *stat = &state->dts_speculations_unavail; -+ enum dtrace_speculation_state curr; -+ -+ while (i < state->dts_nspeculations) { -+ struct dtrace_speculation *spec = &state->dts_speculations[i]; -+ -+ curr = spec->dtsp_state; -+ -+ if (curr != DTRACESPEC_INACTIVE) { -+ if (curr == DTRACESPEC_COMMITTINGMANY || -+ curr == DTRACESPEC_COMMITTING || -+ curr == DTRACESPEC_DISCARDING) -+ stat = &state->dts_speculations_busy; -+ -+ i++; -+ continue; -+ } -+ -+ if (cmpxchg((uint32_t *)&spec->dtsp_state, curr, -+ DTRACESPEC_ACTIVE) == curr) -+ return i + 1; -+ } -+ -+ /* -+ * We couldn't find a speculation. If we found as much as a single -+ * busy speculation buffer, we'll attribute this failure as "busy" -+ * instead of "unavail". -+ */ -+ do { -+ count = *stat; -+ } while (cmpxchg(stat, count, count + 1) != count); -+ -+ return 0; -+} -+ -+/* -+ * This routine commits an active speculation. If the specified speculation -+ * is not in a valid state to perform a commit(), this routine will silently do -+ * nothing. The state of the specified speculation is transitioned according -+ * to the state transition diagram outlined in <sys/dtrace_impl.h> -+ */ -+void dtrace_speculation_commit(struct dtrace_state *state, processorid_t cpu, -+ dtrace_specid_t which) -+{ -+ struct dtrace_speculation *spec; -+ struct dtrace_buffer *src, *dest; -+ uintptr_t daddr, saddr, dlimit; -+ enum dtrace_speculation_state curr, new = 0; -+ intptr_t offs; -+ -+ if (which == 0) -+ return; -+ -+ if (which > state->dts_nspeculations) { -+ per_cpu_core(cpu)->cpuc_dtrace_flags |= CPU_DTRACE_ILLOP; -+ return; -+ } -+ -+ spec = &state->dts_speculations[which - 1]; -+ src = &spec->dtsp_buffer[cpu]; -+ dest = &state->dts_buffer[cpu]; -+ -+ do { -+ curr = spec->dtsp_state; -+ -+ if (curr == DTRACESPEC_COMMITTINGMANY) -+ break; -+ -+ switch (curr) { -+ case DTRACESPEC_INACTIVE: -+ case DTRACESPEC_DISCARDING: -+ return; -+ -+ case DTRACESPEC_COMMITTING: -+ /* -+ * This is only possible if we are (a) commit()'ing -+ * without having done a prior speculate() on this CPU -+ * and (b) racing with another commit() on a different -+ * CPU. There's nothing to do -- we just assert that -+ * our offset is 0. -+ */ -+ ASSERT(src->dtb_offset == 0); -+ return; -+ -+ case DTRACESPEC_ACTIVE: -+ new = DTRACESPEC_COMMITTING; -+ break; -+ -+ case DTRACESPEC_ACTIVEONE: -+ /* -+ * This speculation is active on one CPU. If our -+ * buffer offset is non-zero, we know that the one CPU -+ * must be us. Otherwise, we are committing on a -+ * different CPU from the speculate(), and we must -+ * rely on being asynchronously cleaned. -+ */ -+ if (src->dtb_offset != 0) { -+ new = DTRACESPEC_COMMITTING; -+ break; -+ } -+ /*FALLTHROUGH*/ -+ -+ case DTRACESPEC_ACTIVEMANY: -+ new = DTRACESPEC_COMMITTINGMANY; -+ break; -+ -+ default: -+ ASSERT(0); -+ } -+ } while (cmpxchg((uint32_t *)&spec->dtsp_state, curr, new) != -+ curr); -+ -+ /* -+ * We have set the state to indicate that we are committing this -+ * speculation. Now reserve the necessary space in the destination -+ * buffer. -+ */ -+ offs = dtrace_buffer_reserve(dest, src->dtb_offset, sizeof(uint64_t), -+ state, NULL); -+ if (offs < 0) { -+ dtrace_buffer_drop(dest); -+ goto out; -+ } -+ -+ /* -+ * We have the space; copy the buffer across. (Note that this is a -+ * highly subobtimal bcopy(); in the unlikely event that this becomes -+ * a serious performance issue, a high-performance DTrace-specific -+ * bcopy() should obviously be invented.) -+ */ -+ daddr = (uintptr_t)dest->dtb_tomax + offs; -+ dlimit = daddr + src->dtb_offset; -+ saddr = (uintptr_t)src->dtb_tomax; -+ -+ /* -+ * First, the aligned portion. -+ */ -+ while (dlimit - daddr >= sizeof(uint64_t)) { -+ *((uint64_t *)daddr) = *((uint64_t *)saddr); -+ *((uint64_t *)daddr) = *((uint64_t *)saddr); -+ -+ daddr += sizeof(uint64_t); -+ saddr += sizeof(uint64_t); -+ } -+ -+ /* -+ * Now any left-over bit... -+ */ -+ while (dlimit - daddr) -+ *((uint8_t *)daddr++) = *((uint8_t *)saddr++); -+ -+ /* -+ * Finally, commit the reserved space in the destination buffer. -+ */ -+ dest->dtb_offset = offs + src->dtb_offset; -+ -+out: -+ /* -+ * If we're lucky enough to be the only active CPU on this speculation -+ * buffer, we can just set the state back to DTRACESPEC_INACTIVE. -+ */ -+ if (curr == DTRACESPEC_ACTIVE || -+ (curr == DTRACESPEC_ACTIVEONE && new == DTRACESPEC_COMMITTING)) { -+ /* -+ * Will cause unused warning if DEBUG is not defined. -+ */ -+ uint32_t rval = -+ cmpxchg((uint32_t *)&spec->dtsp_state, -+ DTRACESPEC_COMMITTING, -+ DTRACESPEC_INACTIVE); -+ -+ ASSERT(rval == DTRACESPEC_COMMITTING); -+ rval = 0; /* Avoid warning about unused variable if !DEBUG */ -+ } -+ -+ src->dtb_offset = 0; -+ src->dtb_xamot_drops += src->dtb_drops; -+ src->dtb_drops = 0; -+} -+ -+/* -+ * This routine discards an active speculation. If the specified speculation -+ * is not in a valid state to perform a discard(), this routine will silently -+ * do nothing. The state of the specified speculation is transitioned -+ * according to the state transition diagram outlined in <sys/dtrace_impl.h> -+ */ -+void dtrace_speculation_discard(struct dtrace_state *state, processorid_t cpu, -+ dtrace_specid_t which) -+{ -+ struct dtrace_speculation *spec; -+ enum dtrace_speculation_state curr, new = 0; -+ struct dtrace_buffer *buf; -+ -+ if (which == 0) -+ return; -+ -+ if (which > state->dts_nspeculations) { -+ per_cpu_core(cpu)->cpuc_dtrace_flags |= CPU_DTRACE_ILLOP; -+ return; -+ } -+ -+ spec = &state->dts_speculations[which - 1]; -+ buf = &spec->dtsp_buffer[cpu]; -+ -+ do { -+ curr = spec->dtsp_state; -+ -+ switch (curr) { -+ case DTRACESPEC_INACTIVE: -+ case DTRACESPEC_COMMITTINGMANY: -+ case DTRACESPEC_COMMITTING: -+ case DTRACESPEC_DISCARDING: -+ return; -+ -+ case DTRACESPEC_ACTIVE: -+ case DTRACESPEC_ACTIVEMANY: -+ new = DTRACESPEC_DISCARDING; -+ break; -+ -+ case DTRACESPEC_ACTIVEONE: -+ if (buf->dtb_offset != 0) -+ new = DTRACESPEC_INACTIVE; -+ else -+ new = DTRACESPEC_DISCARDING; -+ -+ break; -+ -+ default: -+ ASSERT(0); -+ } -+ } while (cmpxchg((uint32_t *)&spec->dtsp_state, curr, new) != curr); -+ -+ buf->dtb_offset = 0; -+ buf->dtb_drops = 0; -+} -+ -+/* -+ * Note: not called from probe context. This function is called -+ * asynchronously from cross call context to clean any speculations that are -+ * in the COMMITTINGMANY or DISCARDING states. These speculations may not be -+ * transitioned back to the INACTIVE state until all CPUs have cleaned the -+ * speculation. -+ */ -+void dtrace_speculation_clean_here(struct dtrace_state *state) -+{ -+ dtrace_icookie_t cookie; -+ processorid_t cpu = smp_processor_id(); -+ struct dtrace_buffer *dest = &state->dts_buffer[cpu]; -+ dtrace_specid_t i; -+ uint32_t re_entry; -+ -+ DTRACE_SYNC_ENTER_CRITICAL(cookie, re_entry); -+ -+ if (dest->dtb_tomax == NULL) { -+ DTRACE_SYNC_EXIT_CRITICAL(cookie, re_entry); -+ return; -+ } -+ -+ for (i = 0; i < state->dts_nspeculations; i++) { -+ struct dtrace_speculation *spec = &state->dts_speculations[i]; -+ struct dtrace_buffer *src = &spec->dtsp_buffer[cpu]; -+ -+ if (src->dtb_tomax == NULL) -+ continue; -+ -+ if (spec->dtsp_state == DTRACESPEC_DISCARDING) { -+ src->dtb_offset = 0; -+ continue; -+ } -+ -+ if (spec->dtsp_state != DTRACESPEC_COMMITTINGMANY) -+ continue; -+ -+ if (src->dtb_offset == 0) -+ continue; -+ -+ dtrace_speculation_commit(state, cpu, i + 1); -+ } -+ -+ DTRACE_SYNC_EXIT_CRITICAL(cookie, re_entry); -+} -+ -+void dtrace_speculation_clean(struct dtrace_state *state) -+{ -+ int work = 0, rv; -+ dtrace_specid_t i; -+ -+ for (i = 0; i < state->dts_nspeculations; i++) { -+ struct dtrace_speculation *spec = &state->dts_speculations[i]; -+ -+ ASSERT(!spec->dtsp_cleaning); -+ -+ if (spec->dtsp_state != DTRACESPEC_DISCARDING && -+ spec->dtsp_state != DTRACESPEC_COMMITTINGMANY) -+ continue; -+ -+ work++; -+ spec->dtsp_cleaning = 1; -+ } -+ -+ if (!work) -+ return; -+ -+ dtrace_xcall(DTRACE_CPUALL, -+ (dtrace_xcall_t)dtrace_speculation_clean_here, state); -+ -+ /* -+ * We now know that all CPUs have committed or discarded their -+ * speculation buffers, as appropriate. We can now set the state -+ * to inactive. -+ */ -+ for (i = 0; i < state->dts_nspeculations; i++) { -+ struct dtrace_speculation *spec = -+ &state->dts_speculations[i]; -+ enum dtrace_speculation_state curr, new; -+ -+ if (!spec->dtsp_cleaning) -+ continue; -+ -+ curr = spec->dtsp_state; -+ ASSERT(curr == DTRACESPEC_DISCARDING || -+ curr == DTRACESPEC_COMMITTINGMANY); -+ -+ new = DTRACESPEC_INACTIVE; -+ -+ rv = cmpxchg((uint32_t *)&spec->dtsp_state, curr, new); -+ ASSERT(rv == curr); -+ spec->dtsp_cleaning = 0; -+ } -+} -+ -+/* -+ * Called as part of a speculate() to get the speculative buffer associated -+ * with a given speculation. Returns NULL if the specified speculation is not -+ * in an ACTIVE state. If the speculation is in the ACTIVEONE state -- and -+ * the active CPU is not the specified CPU -- the speculation will be -+ * atomically transitioned into the ACTIVEMANY state. -+ */ -+struct dtrace_buffer *dtrace_speculation_buffer(struct dtrace_state *state, -+ processorid_t cpu, -+ dtrace_specid_t which) -+{ -+ struct dtrace_speculation *spec; -+ enum dtrace_speculation_state curr, new = 0; -+ struct dtrace_buffer *buf; -+ -+ if (which == 0) -+ return NULL; -+ -+ if (which > state->dts_nspeculations) { -+ per_cpu_core(cpu)->cpuc_dtrace_flags |= CPU_DTRACE_ILLOP; -+ return NULL; -+ } -+ -+ spec = &state->dts_speculations[which - 1]; -+ buf = &spec->dtsp_buffer[cpu]; -+ -+ do { -+ curr = spec->dtsp_state; -+ -+ switch (curr) { -+ case DTRACESPEC_INACTIVE: -+ case DTRACESPEC_COMMITTINGMANY: -+ case DTRACESPEC_DISCARDING: -+ return NULL; -+ -+ case DTRACESPEC_COMMITTING: -+ ASSERT(buf->dtb_offset == 0); -+ return NULL; -+ -+ case DTRACESPEC_ACTIVEONE: -+ /* -+ * This speculation is currently active on one CPU. -+ * Check the offset in the buffer; if it's non-zero, -+ * that CPU must be us (and we leave the state alone). -+ * If it's zero, assume that we're starting on a new -+ * CPU -- and change the state to indicate that the -+ * speculation is active on more than one CPU. -+ */ -+ if (buf->dtb_offset != 0) -+ return buf; -+ -+ new = DTRACESPEC_ACTIVEMANY; -+ break; -+ -+ case DTRACESPEC_ACTIVEMANY: -+ return buf; -+ -+ case DTRACESPEC_ACTIVE: -+ new = DTRACESPEC_ACTIVEONE; -+ break; -+ -+ default: -+ ASSERT(0); -+ } -+ } while (cmpxchg((uint32_t *)&spec->dtsp_state, curr, new) != curr); -+ -+ ASSERT(new == DTRACESPEC_ACTIVEONE || new == DTRACESPEC_ACTIVEMANY); -+ -+ return buf; -+} -diff --git a/dtrace/dtrace_state.c b/dtrace/dtrace_state.c -new file mode 100644 -index 000000000000..7fb696e8f1a9 ---- /dev/null -+++ b/dtrace/dtrace_state.c -@@ -0,0 +1,1108 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_state.c -+ * DESCRIPTION: DTrace - consumer state implementation -+ * -+ * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/cyclic.h> -+#include <linux/fs.h> -+#include <linux/idr.h> -+#include <linux/slab.h> -+#include <linux/smp.h> -+#include <linux/vmalloc.h> -+#include <asm/cmpxchg.h> -+ -+#include "dtrace.h" -+ -+int dtrace_destructive_disallow = 0; -+dtrace_optval_t dtrace_nspec_default = 1; -+dtrace_optval_t dtrace_specsize_default = 32 * 1024; -+dtrace_optval_t dtrace_dstate_defsize = 1 * 1024 * 1024; -+size_t dtrace_strsize_default = 256; -+dtrace_optval_t dtrace_stackframes_default = 20; -+dtrace_optval_t dtrace_ustackframes_default = 100; -+dtrace_optval_t dtrace_cleanrate_default = 9900990; -+dtrace_optval_t dtrace_cleanrate_min = 20000; -+dtrace_optval_t dtrace_cleanrate_max = (uint64_t)60 * NANOSEC; -+dtrace_optval_t dtrace_aggrate_default = NANOSEC; -+dtrace_optval_t dtrace_switchrate_default = NANOSEC; -+dtrace_optval_t dtrace_statusrate_default = NANOSEC; -+dtrace_optval_t dtrace_statusrate_max = (uint64_t)10 * NANOSEC; -+dtrace_optval_t dtrace_jstackframes_default = 50; -+dtrace_optval_t dtrace_jstackstrsize_default = 512; -+ktime_t dtrace_deadman_interval = KTIME_INIT(1, 0); -+ktime_t dtrace_deadman_timeout = KTIME_INIT(10, 0); -+ktime_t dtrace_deadman_user = KTIME_INIT(30, 0); -+ -+ /* Sampling before counting */ -+uint64_t dtrace_sync_sample_count = 100; -+ -+dtrace_id_t dtrace_probeid_begin; -+dtrace_id_t dtrace_probeid_end; -+dtrace_id_t dtrace_probeid_error; -+ -+struct dtrace_dynvar dtrace_dynhash_sink; -+ -+#define DTRACE_DYNHASH_FREE 0 -+#define DTRACE_DYNHASH_SINK 1 -+#define DTRACE_DYNHASH_VALID 2 -+ -+#define DTRACE_DYNVAR_CHUNKSIZE 256 -+ -+static void dtrace_dynvar_clean(struct dtrace_dstate *dstate) -+{ -+ struct dtrace_dynvar *dirty; -+ struct dtrace_dstate_percpu *dcpu; -+ int i, work = 0; -+ -+ for (i = 0; i < NR_CPUS; i++) { -+ dcpu = &dstate->dtds_percpu[i]; -+ -+ ASSERT(dcpu->dtdsc_rinsing == NULL); -+ -+ /* -+ * If the dirty list is NULL, there is no dirty work to do. -+ */ -+ if (dcpu->dtdsc_dirty == NULL) -+ continue; -+ -+ /* -+ * If the clean list is non-NULL, then we're not going to do -+ * any work for this CPU -- it means that there has not been -+ * a dtrace_dynvar() allocation on this CPU (or from this CPU) -+ * since the last time we cleaned house. -+ */ -+ if (dcpu->dtdsc_clean != NULL) -+ continue; -+ -+ work = 1; -+ -+ /* -+ * Atomically move the dirty list aside. -+ */ -+ do { -+ dirty = dcpu->dtdsc_dirty; -+ -+ /* -+ * Before we zap the dirty list, set the rinsing list. -+ * (This allows for a potential assertion in -+ * dtrace_dynvar(): if a free dynamic variable appears -+ * on a hash chain, either the dirty list or the -+ * rinsing list for some CPU must be non-NULL.) -+ */ -+ dcpu->dtdsc_rinsing = dirty; -+ dtrace_membar_producer(); -+ } while (cmpxchg(&dcpu->dtdsc_dirty, dirty, NULL) != dirty); -+ } -+ -+ /* -+ * No work to do; return. -+ */ -+ if (!work) -+ return; -+ -+ dtrace_sync(); -+ -+ for (i = 0; i < NR_CPUS; i++) { -+ dcpu = &dstate->dtds_percpu[i]; -+ -+ if (dcpu->dtdsc_rinsing == NULL) -+ continue; -+ -+ /* -+ * We are now guaranteed that no hash chain contains a pointer -+ * into this dirty list; we can make it clean. -+ */ -+ ASSERT(dcpu->dtdsc_clean == NULL); -+ dcpu->dtdsc_clean = dcpu->dtdsc_rinsing; -+ dcpu->dtdsc_rinsing = NULL; -+ } -+ -+ /* -+ * Before we actually set the state to be DTRACE_DSTATE_CLEAN, make -+ * sure that all CPUs have seen all of the dtdsc_clean pointers. -+ * This prevents a race whereby a CPU incorrectly decides that -+ * the state should be something other than DTRACE_DSTATE_CLEAN -+ * after dtrace_dynvar_clean() has completed. -+ */ -+ dtrace_sync(); -+ -+ dstate->dtds_state = DTRACE_DSTATE_CLEAN; -+} -+ -+int dtrace_dstate_init(struct dtrace_dstate *dstate, size_t size) -+{ -+ size_t hashsize, maxper, min, -+ chunksize = dstate->dtds_chunksize; -+ void *base, *percpu; -+ uintptr_t limit; -+ struct dtrace_dynvar *dvar, *next, *start; -+ int i; -+ -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ ASSERT(dstate->dtds_base == NULL && dstate->dtds_percpu == NULL); -+ -+ memset(dstate, 0, sizeof(struct dtrace_dstate)); -+ -+ dstate->dtds_chunksize = chunksize; -+ if (dstate->dtds_chunksize == 0) -+ dstate->dtds_chunksize = DTRACE_DYNVAR_CHUNKSIZE; -+ -+ min = dstate->dtds_chunksize + sizeof(struct dtrace_dynhash); -+ if (size < min) -+ size = min; -+ -+ base = dtrace_vzalloc_try(size); -+ if (base == NULL) -+ return -ENOMEM; -+ percpu = kmem_cache_alloc(dtrace_state_cachep, GFP_KERNEL); -+ if (percpu == NULL) { -+ vfree(base); -+ return -ENOMEM; -+ } -+ -+ dstate->dtds_size = size; -+ dstate->dtds_base = base; -+ dstate->dtds_percpu = percpu; -+ memset(dstate->dtds_percpu, 0, -+ NR_CPUS * sizeof(struct dtrace_dstate_percpu)); -+ -+ hashsize = size / -+ (dstate->dtds_chunksize + sizeof(struct dtrace_dynhash)); -+ -+ if (hashsize != 1 && (hashsize & 1)) -+ hashsize--; -+ -+ dstate->dtds_hashsize = hashsize; -+ dstate->dtds_hash = dstate->dtds_base; -+ -+ /* -+ * Set all of our hash buckets to point to the single sink, and (if -+ * it hasn't already been set), set the sink's hash value to be the -+ * sink sentinel value. The sink is needed for dynamic variable -+ * lookups to know that they have iterated over an entire, valid hash -+ * chain. -+ */ -+ for (i = 0; i < hashsize; i++) -+ dstate->dtds_hash[i].dtdh_chain = &dtrace_dynhash_sink; -+ -+ if (dtrace_dynhash_sink.dtdv_hashval != DTRACE_DYNHASH_SINK) -+ dtrace_dynhash_sink.dtdv_hashval = DTRACE_DYNHASH_SINK; -+ -+ /* -+ * Determine number of active CPUs. Divide free list evenly among -+ * active CPUs. -+ */ -+ start = (struct dtrace_dynvar *)((uintptr_t)base + -+ hashsize * sizeof(struct dtrace_dynhash)); -+ limit = (uintptr_t)base + size; -+ -+ maxper = (limit - (uintptr_t)start) / NR_CPUS; -+ maxper = (maxper / dstate->dtds_chunksize) * dstate->dtds_chunksize; -+ -+ for (i = 0; i < NR_CPUS; i++) { -+ dstate->dtds_percpu[i].dtdsc_free = dvar = start; -+ -+ /* -+ * If we don't even have enough chunks to make it once through -+ * NCPUs, we're just going to allocate everything to the first -+ * CPU. And if we're on the last CPU, we're going to allocate -+ * whatever is left over. In either case, we set the limit to -+ * be the limit of the dynamic variable space. -+ */ -+ if (maxper == 0 || i == NR_CPUS - 1) { -+ limit = (uintptr_t)base + size; -+ start = NULL; -+ } else { -+ limit = (uintptr_t)start + maxper; -+ start = (struct dtrace_dynvar *)limit; -+ } -+ -+ ASSERT(limit <= (uintptr_t)base + size); -+ -+ for (;;) { -+ next = (struct dtrace_dynvar *)((uintptr_t)dvar + -+ dstate->dtds_chunksize); -+ -+ if ((uintptr_t)next + dstate->dtds_chunksize >= limit) -+ break; -+ -+ dvar->dtdv_next = next; -+ dvar = next; -+ } -+ -+ if (maxper == 0) -+ break; -+ } -+ -+ return 0; -+} -+ -+void dtrace_dstate_fini(struct dtrace_dstate *dstate) -+{ -+ ASSERT(MUTEX_HELD(&cpu_lock)); -+ -+ if (dstate->dtds_base == NULL) -+ return; -+ -+ vfree(dstate->dtds_base); -+ kmem_cache_free(dtrace_state_cachep, dstate->dtds_percpu); -+} -+ -+void dtrace_vstate_fini(struct dtrace_vstate *vstate) -+{ -+ /* -+ * If only there was a logical XOR operator... -+ */ -+ ASSERT((vstate->dtvs_nglobals == 0) ^ (vstate->dtvs_globals != NULL)); -+ -+ if (vstate->dtvs_nglobals > 0) -+ vfree(vstate->dtvs_globals); -+ -+ if (vstate->dtvs_ntlocals > 0) -+ vfree(vstate->dtvs_tlocals); -+ -+ ASSERT((vstate->dtvs_nlocals == 0) ^ (vstate->dtvs_locals != NULL)); -+ -+ if (vstate->dtvs_nlocals > 0) -+ vfree(vstate->dtvs_locals); -+} -+ -+static void dtrace_state_clean(struct dtrace_state *state) -+{ -+ dtrace_optval_t *opt = state->dts_options; -+ -+ if (state->dts_activity != DTRACE_ACTIVITY_ACTIVE && -+ state->dts_activity != DTRACE_ACTIVITY_DRAINING) -+ return; -+ -+ dtrace_dynvar_clean(&state->dts_vstate.dtvs_dynvars); -+ dtrace_speculation_clean(state); -+ -+ cyclic_reprogram(state->dts_cleaner, ns_to_ktime( -+ opt[DTRACEOPT_CLEANRATE])); -+} -+ -+static void dtrace_state_deadman(struct dtrace_state *state) -+{ -+ ktime_t now; -+ -+ dtrace_sync(); -+ -+ now = dtrace_gethrtime(); -+ if (state != dtrace_anon.dta_state && -+ ktime_ge(ktime_sub(now, state->dts_laststatus), -+ dtrace_deadman_user)) -+ return; -+ -+ /* -+ * We must be sure that dts_alive never appears to be less than the -+ * value upon entry to dtrace_state_deadman(), and because we lack a -+ * dtrace_cas64(), we cannot store to it atomically. We thus instead -+ * store KTIME_MAX to it, followed by a memory barrier, followed by -+ * the new value. This assures that dts_alive never appears to be -+ * less than its true value, regardless of the order in which the -+ * stores to the underlying storage are issued. -+ */ -+ state->dts_alive = ktime_set(KTIME_SEC_MAX, 0); -+ dtrace_membar_producer(); -+ state->dts_alive = now; -+} -+ -+struct dtrace_state *dtrace_state_create(struct file *file) -+{ -+ struct dtrace_state *state; -+ dtrace_optval_t *opt; -+ int bufsize = NR_CPUS * sizeof(struct dtrace_buffer), i; -+#ifdef FIXME -+ const struct cred *cr = file->f_cred; -+#endif -+ dtrace_aggid_t aggid; -+ -+ ASSERT(MUTEX_HELD(&cpu_lock)); -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ -+ state = kzalloc(sizeof(struct dtrace_state), GFP_KERNEL); -+ if (state == NULL) -+ return NULL; -+ -+ state->dts_epid = DTRACE_EPIDNONE + 1; -+ state->dts_buffer = vzalloc(bufsize); -+ if (state->dts_buffer == NULL) { -+ kfree(state); -+ return NULL; -+ } -+ -+ state->dts_aggbuffer = vzalloc(bufsize); -+ if (state->dts_aggbuffer == NULL) { -+ vfree(state->dts_buffer); -+ kfree(state); -+ return NULL; -+ } -+ -+ idr_init(&state->dts_agg_idr); -+ state->dts_naggs = 0; -+ state->dts_cleaner = 0; -+ state->dts_deadman = 0; -+ state->dts_vstate.dtvs_state = state; -+ -+ /* -+ * Create a first entry in the aggregation IDR, so that ID 0 is used as -+ * that gets used as meaning 'none'. -+ */ -+ idr_preload(GFP_KERNEL); -+ aggid = idr_alloc_cyclic(&state->dts_agg_idr, NULL, 0, 0, GFP_NOWAIT); -+ idr_preload_end(); -+ -+ ASSERT(aggid == 0); -+ -+ for (i = 0; i < DTRACEOPT_MAX; i++) -+ state->dts_options[i] = DTRACEOPT_UNSET; -+ -+ /* -+ * Set the default options. -+ */ -+ opt = state->dts_options; -+ opt[DTRACEOPT_BUFPOLICY] = DTRACEOPT_BUFPOLICY_SWITCH; -+ opt[DTRACEOPT_BUFRESIZE] = DTRACEOPT_BUFRESIZE_AUTO; -+ opt[DTRACEOPT_NSPEC] = dtrace_nspec_default; -+ opt[DTRACEOPT_SPECSIZE] = dtrace_specsize_default; -+ opt[DTRACEOPT_CPU] = (dtrace_optval_t)DTRACE_CPUALL; -+ opt[DTRACEOPT_STRSIZE] = dtrace_strsize_default; -+ opt[DTRACEOPT_STACKFRAMES] = dtrace_stackframes_default; -+ opt[DTRACEOPT_USTACKFRAMES] = dtrace_ustackframes_default; -+ opt[DTRACEOPT_CLEANRATE] = dtrace_cleanrate_default; -+ opt[DTRACEOPT_AGGRATE] = dtrace_aggrate_default; -+ opt[DTRACEOPT_SWITCHRATE] = dtrace_switchrate_default; -+ opt[DTRACEOPT_STATUSRATE] = dtrace_statusrate_default; -+ opt[DTRACEOPT_JSTACKFRAMES] = dtrace_jstackframes_default; -+ opt[DTRACEOPT_JSTACKSTRSIZE] = dtrace_jstackstrsize_default; -+ -+ state->dts_activity = DTRACE_ACTIVITY_INACTIVE; -+ -+#ifdef FIXME -+ /* -+ * Set probe visibility and destructiveness based on user credential -+ * information. For actual anonymous tracing or if all privileges are -+ * set, checks are bypassed. -+ */ -+ if (cr == NULL || -+ PRIV_POLICY_ONLY(cr, PRIV_ALL, FALSE)) { -+ state->dts_cred.dcr_visible = DTRACE_CRV_ALL; -+ state->dts_cred.dcr_action = DTRACE_CRA_ALL; -+ } else { -+ state->dts_cred.dcr_cred = get_cred(cr); -+ -+ /* -+ * CRA_PROC means "we have *some* privilege for dtrace" and -+ * it unlocks the use of variables like pid, etc. -+ */ -+ if (PRIV_POLICY_ONLY(cr, PRIV_DTRACE_USER, FALSE) || -+ PRIV_POLICY_ONLY(cr, PRIV_DTRACE_PROC, FALSE)) -+ state->dts_cred.dcr_action |= DTRACE_CRA_PROC; -+ -+ /* -+ * The DTRACE_USER privilege allows the use of syscall and -+ * profile providers. If the user also has PROC_OWNER, we -+ * extend the scope to include additional visibility and -+ * destructive power. -+ */ -+ if (PRIV_POLICY_ONLY(cr, PRIV_DTRACE_USER, FALSE)) { -+ if (PRIV_POLICY_ONLY(cr, PRIV_PROC_OWNER, FALSE)) -+ state->dts_cred.dcr_visible |= -+ DTRACE_CRV_ALLPROC; -+ -+ state->dts_cred.dcr_action |= -+ DTRACE_CRA_PROC_DESTRUCTIVE_ALLUSER; -+ } -+ -+ /* -+ * Holding the DTRACE_KERNEL privilege also implies that -+ * the user has the DTRACE_USER privilege from a visibility -+ * perspective. But without further privileges, some -+ * destructive actions are not available. -+ */ -+ if (PRIV_POLICY_ONLY(cr, PRIV_DTRACE_KERNEL, FALSE)) { -+ /* -+ * Make all probes in all zones visible. However, -+ * this doesn't mean that all actions become available -+ * to all zones. -+ */ -+ state->dts_cred.dcr_visible |= DTRACE_CRV_KERNEL | -+ DTRACE_CRV_ALLPROC; -+ state->dts_cred.dcr_action |= DTRACE_CRA_KERNEL | -+ DTRACE_CRA_PROC; -+ -+ /* -+ * Holding PROC_OWNER means that destructive actions -+ * are allowed. -+ */ -+ if (PRIV_POLICY_ONLY(cr, PRIV_PROC_OWNER, FALSE)) -+ state->dts_cred.dcr_action |= -+ DTRACE_CRA_PROC_DESTRUCTIVE_ALLUSER; -+ } -+ -+ /* -+ * Holding the DTRACE_PROC privilege gives control over the -+ * fasttrap and pid providers. We need to grant wider -+ * destructive privileges in the event that the user has -+ * PROC_OWNER . -+ */ -+ if (PRIV_POLICY_ONLY(cr, PRIV_DTRACE_PROC, FALSE)) { -+ if (PRIV_POLICY_ONLY(cr, PRIV_PROC_OWNER, FALSE)) -+ state->dts_cred.dcr_action |= -+ DTRACE_CRA_PROC_DESTRUCTIVE_ALLUSER; -+ } -+ } -+#else -+ state->dts_cred.dcr_visible = DTRACE_CRV_ALLPROC | DTRACE_CRV_KERNEL; -+ state->dts_cred.dcr_action = DTRACE_CRA_ALL; -+#endif -+ -+ return state; -+} -+ -+static int dtrace_state_buffer(struct dtrace_state *state, -+ struct dtrace_buffer *buf, int which) -+{ -+ dtrace_optval_t *opt = state->dts_options, size; -+ processorid_t cpu = DTRACE_CPUALL; -+ int flags = 0, rval; -+ -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ ASSERT(MUTEX_HELD(&cpu_lock)); -+ ASSERT(which < DTRACEOPT_MAX); -+ ASSERT(state->dts_activity == DTRACE_ACTIVITY_INACTIVE || -+ (state == dtrace_anon.dta_state && -+ state->dts_activity == DTRACE_ACTIVITY_ACTIVE)); -+ -+ if (opt[which] == DTRACEOPT_UNSET || opt[which] == 0) -+ return 0; -+ -+ if (opt[DTRACEOPT_CPU] != DTRACEOPT_UNSET) -+ cpu = opt[DTRACEOPT_CPU]; -+ -+ if (which == DTRACEOPT_SPECSIZE) -+ flags |= DTRACEBUF_NOSWITCH; -+ -+ if (which == DTRACEOPT_BUFSIZE) { -+ if (opt[DTRACEOPT_BUFPOLICY] == DTRACEOPT_BUFPOLICY_RING) -+ flags |= DTRACEBUF_RING; -+ -+ if (opt[DTRACEOPT_BUFPOLICY] == DTRACEOPT_BUFPOLICY_FILL) -+ flags |= DTRACEBUF_FILL; -+ -+ if (state != dtrace_anon.dta_state || -+ state->dts_activity != DTRACE_ACTIVITY_ACTIVE) -+ flags |= DTRACEBUF_INACTIVE; -+ } -+ -+ for (size = opt[which]; size >= sizeof(uint64_t); size >>= 1) { -+ /* -+ * The size must be 8-byte aligned. If the size is not 8-byte -+ * aligned, drop it down by the difference. -+ */ -+ if (size & (sizeof(uint64_t) - 1)) -+ size -= size & (sizeof(uint64_t) - 1); -+ -+ if (size < state->dts_reserve) { -+ /* -+ * Buffers always must be large enough to accommodate -+ * their prereserved space. We return -E2BIG instead -+ * of ENOMEM in this case to allow for user-level -+ * software to differentiate the cases. -+ */ -+ return -E2BIG; -+ } -+ -+ rval = dtrace_buffer_alloc(buf, size, flags, cpu); -+ if (rval != -ENOMEM) { -+ opt[which] = size; -+ return rval; -+ } -+ -+ if (opt[DTRACEOPT_BUFRESIZE] == DTRACEOPT_BUFRESIZE_MANUAL) -+ return rval; -+ } -+ -+ return -ENOMEM; -+} -+ -+static int dtrace_state_buffers(struct dtrace_state *state) -+{ -+ struct dtrace_speculation *spec = state->dts_speculations; -+ int rval, i; -+ -+ rval = dtrace_state_buffer(state, state->dts_buffer, DTRACEOPT_BUFSIZE); -+ if (rval != 0) -+ return rval; -+ -+ rval = dtrace_state_buffer(state, state->dts_aggbuffer, -+ DTRACEOPT_AGGSIZE); -+ if (rval != 0) -+ return rval; -+ -+ for (i = 0; i < state->dts_nspeculations; i++) { -+ rval = dtrace_state_buffer(state, spec[i].dtsp_buffer, -+ DTRACEOPT_SPECSIZE); -+ if (rval != 0) -+ return rval; -+ } -+ -+ return 0; -+} -+ -+static void dtrace_begin_probe(struct dtrace_state *state) -+{ -+ processorid_t cpuid = smp_processor_id(); -+ -+ ASSERT(state->dts_buffer[cpuid].dtb_flags & DTRACEBUF_INACTIVE); -+ state->dts_buffer[cpuid].dtb_flags &= ~DTRACEBUF_INACTIVE; -+ -+ dtrace_probe(dtrace_probeid_begin, (uint64_t)(uintptr_t)state, 0, 0, 0, -+ 0, 0, 0); -+ -+ /* -+ * We may have had an exit action from a BEGIN probe; only change our -+ * state to ACTIVE if we're still in WARMUP. -+ */ -+ ASSERT(state->dts_activity == DTRACE_ACTIVITY_WARMUP || -+ state->dts_activity == DTRACE_ACTIVITY_DRAINING); -+ -+ if (state->dts_activity == DTRACE_ACTIVITY_WARMUP) -+ state->dts_activity = DTRACE_ACTIVITY_ACTIVE; -+ -+ dtrace_membar_enter(); -+} -+ -+static void dtrace_state_prereserve(struct dtrace_state *state) -+{ -+ struct dtrace_ecb *ecb; -+ struct dtrace_probe *probe; -+ -+ state->dts_reserve = 0; -+ -+ if (state->dts_options[DTRACEOPT_BUFPOLICY] != DTRACEOPT_BUFPOLICY_FILL) -+ return; -+ -+ /* -+ * If our buffer policy is a "fill" buffer policy, we need to set the -+ * prereserved space to be the space required by the END probes. -+ */ -+ probe = dtrace_probe_lookup_id(dtrace_probeid_end); -+ ASSERT(probe != NULL); -+ -+ for (ecb = probe->dtpr_ecb; ecb != NULL; ecb = ecb->dte_next) { -+ if (ecb->dte_state != state) -+ continue; -+ -+ state->dts_reserve += ecb->dte_needed + ecb->dte_alignment; -+ } -+} -+ -+int dtrace_state_go(struct dtrace_state *state, processorid_t *cpu) -+{ -+ dtrace_optval_t *opt = state->dts_options, sz, nspec; -+ struct dtrace_speculation *spec; -+ struct dtrace_buffer *buf; -+ struct cyc_handler hdlr; -+ struct cyc_time when; -+ processorid_t cpuid; -+ int rval = 0, i, bufsize = NR_CPUS * sizeof(struct dtrace_buffer); -+ -+ mutex_lock(&cpu_lock); -+ mutex_lock(&dtrace_lock); -+ -+ if (state->dts_activity != DTRACE_ACTIVITY_INACTIVE) { -+ rval = -EBUSY; -+ goto out; -+ } -+ -+ /* -+ * Before we can perform any checks, we must prime all of the -+ * retained enablings that correspond to this state. -+ */ -+ dtrace_enabling_prime(state); -+ -+ if (state->dts_destructive && !state->dts_cred.dcr_destructive) { -+ rval = -EACCES; -+ goto out; -+ } -+ -+ dtrace_state_prereserve(state); -+ -+ /* -+ * If a cpu has been selected check if its value is valid and -+ * the cpu is online. -+ */ -+ cpuid = opt[DTRACEOPT_CPU]; -+ if (cpuid != DTRACE_CPUALL && -+ (cpuid < 0 || cpuid >= NR_CPUS || !cpu_online(cpuid))) { -+ rval = -ENXIO; -+ goto out; -+ } -+ -+ /* -+ * Now we want to do is try to allocate our speculations. -+ * We do not automatically resize the number of speculations; if -+ * this fails, we will fail the operation. -+ */ -+ nspec = opt[DTRACEOPT_NSPEC]; -+ ASSERT(nspec != DTRACEOPT_UNSET); -+ -+ if (nspec > INT_MAX) { -+ rval = -ENOMEM; -+ goto out; -+ } -+ -+ spec = vzalloc(nspec * sizeof(struct dtrace_speculation)); -+ if (spec == NULL) { -+ rval = -ENOMEM; -+ goto out; -+ } -+ -+ state->dts_speculations = spec; -+ state->dts_nspeculations = (int)nspec; -+ -+ for (i = 0; i < nspec; i++) { -+ buf = vzalloc(bufsize); -+ if (buf == NULL) { -+ rval = -ENOMEM; -+ goto err; -+ } -+ -+ spec[i].dtsp_buffer = buf; -+ } -+ -+ if (opt[DTRACEOPT_GRABANON] != DTRACEOPT_UNSET) { -+ if (dtrace_anon.dta_state == NULL) { -+ rval = -ENOENT; -+ goto out; -+ } -+ -+ if (state->dts_necbs != 0) { -+ rval = -EALREADY; -+ goto out; -+ } -+ -+ state->dts_anon = dtrace_anon_grab(); -+ ASSERT(state->dts_anon != NULL); -+ state = state->dts_anon; -+ -+ /* -+ * We want "grabanon" to be set in the grabbed state, so we'll -+ * copy that option value from the grabbing state into the -+ * grabbed state. -+ */ -+ state->dts_options[DTRACEOPT_GRABANON] = -+ opt[DTRACEOPT_GRABANON]; -+ -+ *cpu = dtrace_anon.dta_beganon; -+ -+ /* -+ * If the anonymous state is active (as it almost certainly -+ * is if the anonymous enabling ultimately matched anything), -+ * we don't allow any further option processing -- but we -+ * don't return failure. -+ */ -+ if (state->dts_activity != DTRACE_ACTIVITY_INACTIVE) -+ goto out; -+ } -+ -+ if (opt[DTRACEOPT_AGGSIZE] != DTRACEOPT_UNSET && -+ opt[DTRACEOPT_AGGSIZE] != 0) { -+ if (state->dts_naggs == 0) { -+ /* -+ * We're not going to create an aggregation buffer -+ * because we don't have any ECBs that contain -+ * aggregations -- set this option to 0. -+ */ -+ opt[DTRACEOPT_AGGSIZE] = 0; -+ } else { -+ /* -+ * If we have an aggregation buffer, we must also have -+ * a buffer to use as scratch. -+ */ -+ if (opt[DTRACEOPT_BUFSIZE] == DTRACEOPT_UNSET || -+ opt[DTRACEOPT_BUFSIZE] < state->dts_needed) -+ opt[DTRACEOPT_BUFSIZE] = state->dts_needed; -+ } -+ } -+ -+ if (opt[DTRACEOPT_SPECSIZE] != DTRACEOPT_UNSET && -+ opt[DTRACEOPT_SPECSIZE] != 0) { -+ /* -+ * We are not going to create speculation buffers if we do not -+ * have any ECBs that actually speculate. -+ */ -+ if (!state->dts_speculates) -+ opt[DTRACEOPT_SPECSIZE] = 0; -+ } -+ -+ /* -+ * The bare minimum size for any buffer that we're actually going to -+ * do anything to is sizeof (uint64_t). -+ */ -+ sz = sizeof(uint64_t); -+ -+ if ((state->dts_needed != 0 && opt[DTRACEOPT_BUFSIZE] < sz) || -+ (state->dts_speculates && opt[DTRACEOPT_SPECSIZE] < sz) || -+ (state->dts_naggs != 0 && opt[DTRACEOPT_AGGSIZE] < sz)) { -+ /* -+ * A buffer size has been explicitly set to 0 (or to a size -+ * that will be adjusted to 0) and we need the space -- we -+ * need to return failure. We return -ENOSPC to differentiate -+ * it from failing to allocate a buffer due to failure to meet -+ * the reserve (for which we return -E2BIG). -+ */ -+ rval = -ENOSPC; -+ goto out; -+ } -+ -+ rval = dtrace_state_buffers(state); -+ if (rval != 0) -+ goto err; -+ -+ sz = opt[DTRACEOPT_DYNVARSIZE]; -+ if (sz == DTRACEOPT_UNSET) -+ sz = dtrace_dstate_defsize; -+ -+ do { -+ rval = dtrace_dstate_init(&state->dts_vstate.dtvs_dynvars, sz); -+ -+ if (rval == 0) -+ break; -+ -+ if (opt[DTRACEOPT_BUFRESIZE] == DTRACEOPT_BUFRESIZE_MANUAL) -+ goto err; -+ } while (sz >>= 1); -+ -+ opt[DTRACEOPT_DYNVARSIZE] = sz; -+ -+ if (rval != 0) -+ goto err; -+ -+ if (opt[DTRACEOPT_STATUSRATE] > dtrace_statusrate_max) -+ opt[DTRACEOPT_STATUSRATE] = dtrace_statusrate_max; -+ -+ if (opt[DTRACEOPT_CLEANRATE] == 0) -+ opt[DTRACEOPT_CLEANRATE] = dtrace_cleanrate_max; -+ -+ if (opt[DTRACEOPT_CLEANRATE] < dtrace_cleanrate_min) -+ opt[DTRACEOPT_CLEANRATE] = dtrace_cleanrate_min; -+ -+ if (opt[DTRACEOPT_CLEANRATE] > dtrace_cleanrate_max) -+ opt[DTRACEOPT_CLEANRATE] = dtrace_cleanrate_max; -+ -+ hdlr.cyh_func = (cyc_func_t)dtrace_state_clean; -+ hdlr.cyh_arg = (uintptr_t)state; -+ hdlr.cyh_level = CY_LOW_LEVEL; -+ -+ when.cyt_when = ktime_set(0, 0); -+ when.cyt_interval = CY_INTERVAL_INF; -+ -+ state->dts_cleaner = cyclic_add(&hdlr, &when); -+ cyclic_reprogram(state->dts_cleaner, ns_to_ktime( -+ opt[DTRACEOPT_CLEANRATE])); -+ -+ hdlr.cyh_func = (cyc_func_t)dtrace_state_deadman; -+ hdlr.cyh_arg = (uintptr_t)state; -+ hdlr.cyh_level = CY_LOW_LEVEL; -+ -+ when.cyt_when = ktime_set(0, 0); -+ when.cyt_interval = dtrace_deadman_interval; -+ -+ state->dts_alive = state->dts_laststatus = dtrace_gethrtime(); -+ state->dts_deadman = cyclic_add(&hdlr, &when); -+ -+ state->dts_activity = DTRACE_ACTIVITY_WARMUP; -+ -+ /* -+ * Issue xcall even when the BEGIN probe fires on current CPU. The -+ * underlying implementation of SMP will turn it into direct function -+ * call. It is not allowed to turn off interrupts so we need to pick -+ * a cpu first and then xcall it. This way a begin probe will always -+ * fire on the expected cpu. -+ */ -+ *cpu = (cpuid == DTRACE_CPUALL) ? smp_processor_id() : cpuid; -+ dtrace_xcall(*cpu, (dtrace_xcall_t)dtrace_begin_probe, state); -+ -+ /* -+ * Regardless of whether or not now we're in ACTIVE or DRAINING, we -+ * want each CPU to transition its principal buffer out of the -+ * INACTIVE state. Doing this assures that no CPU will suddenly begin -+ * processing an ECB halfway down a probe's ECB chain; all CPUs will -+ * atomically transition from processing none of a state's ECBs to -+ * processing all of them. -+ */ -+ dtrace_xcall(DTRACE_CPUALL, (dtrace_xcall_t)dtrace_buffer_activate, -+ state); -+ goto out; -+ -+err: -+ dtrace_buffer_free(state->dts_buffer); -+ dtrace_buffer_free(state->dts_aggbuffer); -+ -+ nspec = state->dts_nspeculations; -+ if (nspec == 0) { -+ ASSERT(state->dts_speculations == NULL); -+ goto out; -+ } -+ -+ spec = state->dts_speculations; -+ ASSERT(spec != NULL); -+ -+ for (i = 0; i < state->dts_nspeculations; i++) { -+ buf = spec[i].dtsp_buffer; -+ if (buf == NULL) -+ break; -+ -+ dtrace_buffer_free(buf); -+ vfree(buf); -+ } -+ -+ vfree(spec); -+ state->dts_nspeculations = 0; -+ state->dts_speculations = NULL; -+ -+out: -+ mutex_unlock(&dtrace_lock); -+ mutex_unlock(&cpu_lock); -+ -+ return rval; -+} -+ -+static void dtrace_end_probe(struct dtrace_state *state) -+{ -+ dtrace_probe(dtrace_probeid_end, (uint64_t)(uintptr_t)state, 0, 0, 0, -+ 0, 0, 0); -+ -+ state->dts_activity = DTRACE_ACTIVITY_STOPPED; -+ -+ dtrace_membar_enter(); -+} -+ -+int dtrace_state_stop(struct dtrace_state *state, processorid_t *cpu) -+{ -+ processorid_t cpuid = state->dts_options[DTRACEOPT_CPU]; -+ -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ -+ if (state->dts_activity != DTRACE_ACTIVITY_ACTIVE && -+ state->dts_activity != DTRACE_ACTIVITY_DRAINING) -+ return -EINVAL; -+ -+ /* -+ * We'll set the activity to DTRACE_ACTIVITY_DRAINING, and issue a sync -+ * to be sure that every CPU has seen it. See below for the details -+ * on why this is done. -+ */ -+ state->dts_activity = DTRACE_ACTIVITY_DRAINING; -+ dtrace_sync(); -+ -+ /* -+ * By this point, it is impossible for any CPU to be still processing -+ * with DTRACE_ACTIVITY_ACTIVE. We can thus set our activity to -+ * DTRACE_ACTIVITY_COOLDOWN and know that we're not racing with any -+ * other CPU in dtrace_buffer_reserve(). This allows dtrace_probe() -+ * and callees to know that the activity is DTRACE_ACTIVITY_COOLDOWN -+ * iff we're in the END probe. -+ */ -+ state->dts_activity = DTRACE_ACTIVITY_COOLDOWN; -+ dtrace_sync(); -+ ASSERT(state->dts_activity == DTRACE_ACTIVITY_COOLDOWN); -+ -+ /* -+ * Finally, we can release the reserve and call the END probe. We -+ * disable interrupts across calling the END probe to allow us to -+ * return the CPU on which we actually called the END probe. This -+ * allows user-land to be sure that this CPU's principal buffer is -+ * processed last. -+ */ -+ state->dts_reserve = 0; -+ -+ /* -+ * Same as for BEGIN probe in dtrace_state_go(). The END probe must -+ * also fire on the enabled cpu. -+ */ -+ *cpu = (cpuid == DTRACE_CPUALL) ? smp_processor_id() : cpuid; -+ dtrace_xcall(*cpu, (dtrace_xcall_t)dtrace_end_probe, state); -+ -+ dtrace_sync(); -+ return 0; -+} -+ -+int dtrace_state_option(struct dtrace_state *state, dtrace_optid_t option, -+ dtrace_optval_t val) -+{ -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ -+ if (state->dts_activity != DTRACE_ACTIVITY_INACTIVE) -+ return -EBUSY; -+ -+ if (option >= DTRACEOPT_MAX) -+ return -EINVAL; -+ -+ if (option != DTRACEOPT_CPU && val < 0) -+ return -EINVAL; -+ -+ switch (option) { -+ case DTRACEOPT_DESTRUCTIVE: -+ if (dtrace_destructive_disallow) -+ return -EACCES; -+ -+ state->dts_cred.dcr_destructive = 1; -+ break; -+ -+ case DTRACEOPT_BUFSIZE: -+ case DTRACEOPT_DYNVARSIZE: -+ case DTRACEOPT_AGGSIZE: -+ case DTRACEOPT_SPECSIZE: -+ case DTRACEOPT_STRSIZE: -+ if (val < 0) -+ return -EINVAL; -+ -+ /* -+ * If this is an otherwise negative value, set it to the -+ * highest multiple of 128m less than LONG_MAX. Technically, -+ * we're adjusting the size without regard to the buffer -+ * resizing policy, but in fact, this has no effect -- if we -+ * set the buffer size to ~LONG_MAX and the buffer policy is -+ * ultimately set to be "manual", the buffer allocation is -+ * guaranteed to fail, if only because the allocation requires -+ * two buffers. (We set the the size to the highest multiple -+ * of 128m because it ensures that the size will remain a -+ * multiple of a megabyte when repeatedly halved -- all the -+ * way down to 15m.) -+ */ -+ if (val >= LONG_MAX) -+ val = LONG_MAX - (1 << 27) + 1; -+ } -+ -+ state->dts_options[option] = val; -+ -+ return 0; -+} -+ -+void dtrace_state_destroy(struct dtrace_state *state) -+{ -+ struct dtrace_ecb *ecb; -+ struct dtrace_vstate *vstate = &state->dts_vstate; -+ int i; -+ struct dtrace_speculation *spec = state->dts_speculations; -+ int nspec = state->dts_nspeculations; -+ uint32_t match; -+ -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ ASSERT(MUTEX_HELD(&cpu_lock)); -+ -+ /* -+ * First, retract any retained enablings for this state. -+ */ -+ dtrace_enabling_retract(state); -+ ASSERT(state->dts_nretained == 0); -+ -+ if (state->dts_activity == DTRACE_ACTIVITY_ACTIVE || -+ state->dts_activity == DTRACE_ACTIVITY_DRAINING) { -+ /* -+ * We have managed to come into dtrace_state_destroy() on a -+ * hot enabling -- almost certainly because of a disorderly -+ * shutdown of a consumer. (That is, a consumer that is -+ * exiting without having called dtrace_stop().) In this case, -+ * we're going to set our activity to be KILLED, and then -+ * issue a sync to be sure that everyone is out of probe -+ * context before we start blowing away ECBs. -+ */ -+ state->dts_activity = DTRACE_ACTIVITY_KILLED; -+ dtrace_sync(); -+ } -+ -+ /* -+ * Release the credential hold we took in dtrace_state_create(). -+ */ -+ if (state->dts_cred.dcr_cred != NULL) -+ put_cred(state->dts_cred.dcr_cred); -+ -+ /* -+ * Now we can safely disable and destroy any enabled probes. Because -+ * any DTRACE_PRIV_KERNEL probes may actually be slowing our progress -+ * (especially if they're all enabled), we take two passes through the -+ * ECBs: in the first, we disable just DTRACE_PRIV_KERNEL probes, and -+ * in the second we disable whatever is left over. -+ */ -+ for (match = DTRACE_PRIV_KERNEL; ; match = 0) { -+ for (i = 0; i < state->dts_necbs; i++) { -+ ecb = state->dts_ecbs[i]; -+ if (ecb == NULL) -+ continue; -+ -+ if (match && ecb->dte_probe != NULL) { -+ struct dtrace_probe *probe = -+ ecb->dte_probe; -+ struct dtrace_provider *prov = -+ probe->dtpr_provider; -+ -+ if (!(prov->dtpv_priv.dtpp_flags & match)) -+ continue; -+ } -+ -+ dtrace_ecb_disable(ecb); -+ dtrace_ecb_destroy(ecb); -+ } -+ -+ if (!match) -+ break; -+ } -+ -+ /* -+ * Before we free the buffers, perform one more sync to assure that -+ * every CPU is out of probe context. -+ */ -+ dtrace_sync(); -+ -+ dtrace_buffer_free(state->dts_buffer); -+ dtrace_buffer_free(state->dts_aggbuffer); -+ -+ for (i = 0; i < nspec; i++) -+ dtrace_buffer_free(spec[i].dtsp_buffer); -+ -+ if (state->dts_cleaner != CYCLIC_NONE) -+ cyclic_remove(state->dts_cleaner); -+ -+ if (state->dts_deadman != CYCLIC_NONE) -+ cyclic_remove(state->dts_deadman); -+ -+ dtrace_dstate_fini(&vstate->dtvs_dynvars); -+ dtrace_vstate_fini(vstate); -+ vfree(state->dts_ecbs); -+ -+ /* -+ * If there were aggregations allocated, they should have been cleaned -+ * up by now, so we can get rid of the idr. -+ */ -+ idr_destroy(&state->dts_agg_idr); -+ -+ vfree(state->dts_buffer); -+ vfree(state->dts_aggbuffer); -+ -+ for (i = 0; i < nspec; i++) -+ vfree(spec[i].dtsp_buffer); -+ -+ vfree(spec); -+ -+ dtrace_format_destroy(state); -+ -+ kfree(state); -+} -diff --git a/dtrace/dtrace_util.c b/dtrace/dtrace_util.c -new file mode 100644 -index 000000000000..76fdf2bd8b41 ---- /dev/null -+++ b/dtrace/dtrace_util.c -@@ -0,0 +1,282 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_util.c -+ * DESCRIPTION: DTrace - utility functions -+ * -+ * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/dtrace_cpu.h> -+#include <linux/module.h> -+#include <linux/vmalloc.h> -+#include <asm/pgtable.h> -+ -+#include "dtrace.h" -+ -+int dtrace_isglob(const char *s) -+{ -+ char c; -+ -+ while ((c = *s++) != '\0') { -+ if (c == '[' || c == '?' || c == '*' || c == '\\') -+ return 1; -+ } -+ -+ return 0; -+} -+EXPORT_SYMBOL(dtrace_isglob); -+ -+int dtrace_gmatch(const char *s, const char *p) -+{ -+ const char *olds = s; -+ char sc; -+ char pc; -+ -+ sc = *s++; -+ pc = *p++; -+ -+ if (!pc) -+ return !sc; -+ -+ switch (pc) { -+ case '[': { -+ int ok = 0; -+ char lc = '\0'; -+ int inv = 0; -+ -+ if (!sc) -+ return 0; -+ -+ if (*p == '!') { -+ inv = 1; -+ p++; -+ } -+ -+ pc = *p++; -+ do { -+ if (pc == '-' && lc && *p != ']') { -+ pc = *p++; -+ if (pc == '\\') -+ pc = *p++; -+ -+ if (inv) { -+ if (sc < lc || sc > pc) -+ ok++; -+ else -+ return 0; -+ } else { -+ if (lc <= sc && sc <= pc) -+ ok++; -+ } -+ } else if (pc == '\\') { -+ pc = *p++; -+ } -+ -+ lc = sc; -+ -+ if (inv) { -+ if (sc != lc) -+ ok++; -+ else -+ return 0; -+ } else { -+ if (sc == lc) -+ ok++; -+ } -+ -+ pc = *p++; -+ } while (pc != ']'); -+ -+ return ok ? dtrace_gmatch(s, p) : 0; -+ } -+ case '\\': -+ pc = *p++; -+ if (!pc) -+ return 0; -+ -+ /* fall-through */ -+ default: -+ if (pc != sc) -+ return 0; -+ -+ /* fall-through */ -+ case '?': -+ return sc ? dtrace_gmatch(s, p) : 0; -+ case '*': -+ while (*p == '*') -+ p++; -+ -+ if (!*p) -+ return 1; -+ -+ s = olds; -+ while (*s) { -+ if (dtrace_gmatch(s, p)) -+ return 1; -+ -+ s++; -+ } -+ -+ return 0; -+ } -+} -+EXPORT_SYMBOL(dtrace_gmatch); -+ -+int dtrace_badattr(const struct dtrace_attribute *a) -+{ -+ return a->dtat_name > DTRACE_STABILITY_MAX || -+ a->dtat_data > DTRACE_STABILITY_MAX || -+ a->dtat_class > DTRACE_CLASS_MAX; -+} -+ -+/* -+ * Allocate a chunk of virtual memory in kernel space, and zero it out. This -+ * allocation might fail (which will report a backtrace in the kernel log, yet -+ * it is harmless). -+ */ -+void *dtrace_vzalloc_try(unsigned long size) -+{ -+ return __vmalloc(size, -+ GFP_NOWAIT | __GFP_FS | __GFP_IO | __GFP_NOMEMALLOC | -+ __GFP_NORETRY | __GFP_NOWARN | __GFP_ZERO); -+} -+EXPORT_SYMBOL(dtrace_vzalloc_try); -+ -+/* -+ * Return a duplicate copy of a string. If the specified string is NULL, this -+ * function returs a zero-length string. -+ */ -+char *dtrace_strdup(const char *str) -+{ -+ return kstrdup(str ? str : "", GFP_KERNEL); -+} -+ -+/* -+ * Compare two strings using safe loads. -+ */ -+int dtrace_strncmp(char *s1, char *s2, size_t limit) -+{ -+ uint8_t c1, c2; -+ volatile uint16_t *flags; -+ -+ if (s1 == s2 || limit == 0) -+ return 0; -+ -+ flags = (volatile uint16_t *)&this_cpu_core->cpuc_dtrace_flags; -+ -+ do { -+ if (s1 == NULL) -+ c1 = '\0'; -+ else -+ c1 = dtrace_load8((uintptr_t)s1++); -+ -+ if (s2 == NULL) -+ c2 = '\0'; -+ else -+ c2 = dtrace_load8((uintptr_t)s2++); -+ -+ if (c1 != c2) -+ return (c1 - c2); -+ } while (--limit && c1 != '\0' && !(*flags & CPU_DTRACE_FAULT)); -+ -+ return 0; -+} -+ -+/* -+ * Compute strlen(s) for a string using safe memory accesses. The additional -+ * len parameter is used to specify a maximum length to ensure completion. -+ */ -+size_t dtrace_strlen(const char *s, size_t lim) -+{ -+ uint_t len; -+ -+ for (len = 0; len != lim; len++) { -+ if (dtrace_load8((uintptr_t)s++) == '\0') -+ break; -+ } -+ -+ return len; -+} -+ -+#define DTRACE_ISALPHA(c) (((c) >= 'a' && (c) <= 'z') || \ -+ ((c) >= 'A' && (c) <= 'Z')) -+int dtrace_badname(const char *s) -+{ -+ char c; -+ -+ if (s == NULL) -+ return 0; -+ -+ c = *s++; -+ if (c == '\0') -+ return 0; -+ -+ if (!DTRACE_ISALPHA(c) && c != '-' && c != '_' && c != '.') -+ return 1; -+ -+ while ((c = *s++) != '\0') { -+ if (!DTRACE_ISALPHA(c) && (c < '0' || c > '9') && -+ c != '-' && c != '_' && c != '.' && c != '`') -+ return 1; -+ } -+ -+ return 0; -+} -+ -+void dtrace_cred2priv(const struct cred *cr, uint32_t *privp, kuid_t *uidp) -+{ -+#ifdef FIXME -+/* -+ * This should probably be rewritten based on capabilities in the struct cred. -+ */ -+ uint32_t priv; -+ -+ if (cr == NULL) -+ priv = DTRACE_PRIV_ALL; -+ else { -+ const struct cred *lcr = get_cred(cr); -+ -+ if (PRIV_POLICY_ONLY(lcr, PRIV_ALL, FALSE)) -+ priv = DTRACE_PRIV_ALL; -+ else { -+ *uidp = lcr->uid; -+ priv = 0; -+ -+ if (PRIV_POLICY_ONLY(lcr, PRIV_DTRACE_KERNEL, FALSE)) -+ priv |= DTRACE_PRIV_KERNEL | DTRACE_PRIV_USER; -+ else if (PRIV_POLICY_ONLY(lcr, PRIV_DTRACE_USER, -+ FALSE)) -+ priv |= DTRACE_PRIV_USER; -+ -+ if (PRIV_POLICY_ONLY(lcr, PRIV_DTRACE_PROC, FALSE)) -+ priv |= DTRACE_PRIV_PROC; -+ if (PRIV_POLICY_ONLY(lcr, PRIV_PROC_OWNER, FALSE)) -+ priv |= DTRACE_PRIV_OWNER; -+ } -+ -+ put_cred(cr); -+ } -+ -+ *privp = priv; -+#else -+ *privp = DTRACE_PRIV_ALL; -+ -+ if (cr != NULL) { -+ const struct cred *lcr = get_cred(cr); -+ -+ *uidp = lcr->uid; -+ put_cred(cr); -+ } -+#endif -+} -+ --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/dtrace-patches/0006-dtrace-systrace-provider-core-components.patch b/sys-kernel/cairn-sources/files/5.10.13/dtrace-patches/0006-dtrace-systrace-provider-core-components.patch deleted file mode 100644 index 16c4176cb842..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/dtrace-patches/0006-dtrace-systrace-provider-core-components.patch +++ /dev/null @@ -1,326 +0,0 @@ -From a71a23031f2c3ae2e9b4a560bf5ed11e6d237003 Mon Sep 17 00:00:00 2001 -From: Kris Van Hees <kris.van.hees@oracle.com> -Date: Mon, 19 Nov 2018 16:55:11 +0000 -Subject: [PATCH 06/19] dtrace: systrace provider core components - -This implements the core (linked-in) components of the DTrace systrace -provider, which intercepts system call invocations. As previously, -the arch-dependent pieces needed for x86 are also provided. - -Signed-off-by: Nick Alcock <nick.alcock@oracle.com> -Signed-off-by: Kris Van Hees <kris.van.hees@oracle.com> -Signed-off-by: Tomas Jedlicka <tomas.jedlicka@oracle.com> -Signed-off-by: Eugene Loh <eugene.loh@oracle.com> -Signed-off-by: David Mc Lean <david.mclean@oracle.com> -Signed-off-by: Vincent Lim <vincent.lim@oracle.com> ---- - arch/x86/entry/syscall_32.c | 4 + - arch/x86/entry/syscall_64.c | 4 + - arch/x86/include/asm/dtrace_syscall.h | 3 + - arch/x86/include/asm/dtrace_syscall_types.h | 11 +++ - arch/x86/include/asm/syscall.h | 8 ++ - arch/x86/kernel/dtrace_syscall.c | 97 +++++++++++++++++++++ - arch/x86/kernel/dtrace_syscall_stubs.S | 0 - include/linux/dtrace_syscall.h | 60 +++++++++++++ - kernel/dtrace/Kconfig | 9 ++ - kernel/dtrace/Makefile | 1 + - 10 files changed, 197 insertions(+) - create mode 100644 arch/x86/include/asm/dtrace_syscall.h - create mode 100644 arch/x86/include/asm/dtrace_syscall_types.h - create mode 100644 arch/x86/kernel/dtrace_syscall.c - create mode 100644 arch/x86/kernel/dtrace_syscall_stubs.S - create mode 100644 include/linux/dtrace_syscall.h - -diff --git a/arch/x86/entry/syscall_32.c b/arch/x86/entry/syscall_32.c -index 86eb0d89d46f..66381ebd6a9f 100644 ---- a/arch/x86/entry/syscall_32.c -+++ b/arch/x86/entry/syscall_32.c -@@ -15,7 +15,11 @@ - - #define __SYSCALL_I386(nr, sym) [nr] = __ia32_##sym, - -+#if IS_ENABLED(CONFIG_DT_SYSTRACE) -+__visible sys_call_ptr_t ia32_sys_call_table[__NR_ia32_syscall_max+1] = { -+#else - __visible const sys_call_ptr_t ia32_sys_call_table[__NR_ia32_syscall_max+1] = { -+#endif /* CONFIG_DT_SYSTRACE || CONFIG_DT_SYSTRACE_MODULE */ - /* - * Smells like a compiler bug -- it doesn't work - * when the & below is removed. -diff --git a/arch/x86/entry/syscall_64.c b/arch/x86/entry/syscall_64.c -index 1594ec72bcbb..42587831ef04 100644 ---- a/arch/x86/entry/syscall_64.c -+++ b/arch/x86/entry/syscall_64.c -@@ -17,7 +17,11 @@ - - #define __SYSCALL_64(nr, sym) [nr] = __x64_##sym, - -+#if IS_ENABLED(CONFIG_DT_SYSTRACE) -+asmlinkage sys_call_ptr_t sys_call_table[__NR_syscall_max+1] = { -+#else - asmlinkage const sys_call_ptr_t sys_call_table[__NR_syscall_max+1] = { -+#endif /* CONFIG_DT_SYSTRACE || CONFIG_DT_SYSTRACE_MODULE */ - /* - * Smells like a compiler bug -- it doesn't work - * when the & below is removed. -diff --git a/arch/x86/include/asm/dtrace_syscall.h b/arch/x86/include/asm/dtrace_syscall.h -new file mode 100644 -index 000000000000..402826562478 ---- /dev/null -+++ b/arch/x86/include/asm/dtrace_syscall.h -@@ -0,0 +1,3 @@ -+/* -+ * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. -+ */ -diff --git a/arch/x86/include/asm/dtrace_syscall_types.h b/arch/x86/include/asm/dtrace_syscall_types.h -new file mode 100644 -index 000000000000..2b3ee563ad14 ---- /dev/null -+++ b/arch/x86/include/asm/dtrace_syscall_types.h -@@ -0,0 +1,11 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+#include <linux/types.h> -+#include <linux/dtrace_types.h> -+ -+typedef asmlinkage long (*dt_sys_call_t)(const struct pt_regs *regs); -+ -+#define DTRACE_SYSCALL_WRAP_PREFIX "__x64_" -diff --git a/arch/x86/include/asm/syscall.h b/arch/x86/include/asm/syscall.h -index 7cbf733d11af..3d1bce850b74 100644 ---- a/arch/x86/include/asm/syscall.h -+++ b/arch/x86/include/asm/syscall.h -@@ -17,15 +17,23 @@ - #include <asm/unistd.h> - - typedef long (*sys_call_ptr_t)(const struct pt_regs *); -+#if IS_ENABLED(CONFIG_DT_SYSTRACE) -+extern sys_call_ptr_t sys_call_table[]; -+#else - extern const sys_call_ptr_t sys_call_table[]; -+#endif - - #if defined(CONFIG_X86_32) - #define ia32_sys_call_table sys_call_table - #endif - - #if defined(CONFIG_IA32_EMULATION) -+#if IS_ENABLED(CONFIG_DT_SYSTRACE) -+extern sys_call_ptr_t ia32_sys_call_table[]; -+#else - extern const sys_call_ptr_t ia32_sys_call_table[]; - #endif -+#endif - - #ifdef CONFIG_X86_X32_ABI - extern const sys_call_ptr_t x32_sys_call_table[]; -diff --git a/arch/x86/kernel/dtrace_syscall.c b/arch/x86/kernel/dtrace_syscall.c -new file mode 100644 -index 000000000000..3328710e7050 ---- /dev/null -+++ b/arch/x86/kernel/dtrace_syscall.c -@@ -0,0 +1,97 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_syscall.c -+ * DESCRIPTION: Dynamic Tracing: system call tracing support (arch-specific) -+ * -+ * Copyright (C) 2010-2018 Oracle Corporation -+ */ -+ -+#include <linux/dtrace_cpu.h> -+#include <linux/dtrace_os.h> -+#include <linux/dtrace_syscall.h> -+#include <linux/fs.h> -+#include <linux/module.h> -+#include <linux/namei.h> -+#include <linux/sched.h> -+#include <asm/insn.h> -+#include <asm/stacktrace.h> -+#include <asm/syscalls.h> -+ -+/* -+ * SYSTEM CALL TRACING SUPPORT -+ */ -+void (*systrace_probe)(dtrace_id_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, -+ uintptr_t, uintptr_t, uintptr_t); -+ -+void systrace_stub(dtrace_id_t id, uintptr_t arg0, uintptr_t arg1, -+ uintptr_t arg2, uintptr_t arg3, uintptr_t arg4, -+ uintptr_t arg5, uintptr_t arg6) -+{ -+} -+ -+asmlinkage long systrace_syscall(const struct pt_regs *regs); -+ -+asmlinkage long dtrace_stub_ptregs(uintptr_t, uintptr_t, uintptr_t, uintptr_t, -+ uintptr_t, uintptr_t, uintptr_t); -+ -+static struct systrace_info systrace_info = -+{ -+ &systrace_probe, -+ systrace_stub, -+ systrace_syscall, -+ {}, -+ { -+#define __SYSCALL_64(nr, sym) [nr] { __stringify(sym), }, -+#define __SYSCALL_COMMON(nr, sym) __SYSCALL_64(nr, sym) -+#define __SYSCALL_X32(nt, sym) -+#include <asm/syscalls_64.h> -+ } -+}; -+ -+asmlinkage long systrace_syscall(const struct pt_regs *regs) -+{ -+ long rc = 0; -+ unsigned long sysnum; -+ dtrace_id_t id; -+ struct dtrace_syscalls *sc; -+ -+ sysnum = syscall_get_nr(current, (struct pt_regs *) regs); -+ sc = &systrace_info.sysent[sysnum]; -+ -+ /* -+ * Note: 64-bit syscall-specific. -+ */ -+ id = sc->stsy_entry; -+ if (id != DTRACE_IDNONE) -+ (*systrace_probe)(id, regs->di, regs->si, regs->dx, -+ regs->r10, regs->r8, regs->r9, 0); -+ -+ /* -+ * FIXME: Add stop functionality for DTrace. -+ */ -+ -+ if (sc->stsy_underlying != NULL) -+ rc = (*sc->stsy_underlying)(regs); -+ -+ id = sc->stsy_return; -+ if (id != DTRACE_IDNONE) -+ (*systrace_probe)(id, (uintptr_t)rc, (uintptr_t)rc, -+ (uintptr_t)((uint64_t)rc >> 32), 0, 0, 0, 0); -+ -+ return rc; -+} -+ -+struct systrace_info *dtrace_syscalls_init(void) -+{ -+ int i; -+ -+ for (i = 0; i < NR_syscalls; i++) { -+ systrace_info.sysent[i].stsy_tblent = -+ (dt_sys_call_t *)&sys_call_table[i]; -+ systrace_info.sysent[i].stsy_underlying = -+ (dt_sys_call_t)sys_call_table[i]; -+ } -+ -+ return &systrace_info; -+} -+EXPORT_SYMBOL(dtrace_syscalls_init); -diff --git a/arch/x86/kernel/dtrace_syscall_stubs.S b/arch/x86/kernel/dtrace_syscall_stubs.S -new file mode 100644 -index 000000000000..e69de29bb2d1 -diff --git a/include/linux/dtrace_syscall.h b/include/linux/dtrace_syscall.h -new file mode 100644 -index 000000000000..7f9e351f3783 ---- /dev/null -+++ b/include/linux/dtrace_syscall.h -@@ -0,0 +1,60 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+#ifndef _LINUX_DTRACE_SYSCALL_H_ -+#define _LINUX_DTRACE_SYSCALL_H_ -+ -+#include <linux/types.h> -+#include <linux/dtrace_os.h> -+#include <asm/syscall.h> -+ -+#define DTRACE_SYSCALL_STUB(t, n) SCE_##t, -+enum dtrace_sce_id { -+ SCE_NONE = 0, -+#include <asm/dtrace_syscall.h> -+ SCE_nr_stubs -+}; -+#undef DTRACE_SYSCALL_STUB -+ -+#define DTRACE_SYSCALL_STUB(t, n) \ -+ asmlinkage long dtrace_stub_##n(uintptr_t, uintptr_t, uintptr_t, \ -+ uintptr_t, uintptr_t, uintptr_t, \ -+ uintptr_t); -+#include <asm/dtrace_syscall.h> -+#undef DTRACE_SYSCALL_STUB -+ -+#ifndef CONFIG_ARCH_HAS_SYSCALL_WRAPPER -+typedef asmlinkage long (*dt_sys_call_t)(uintptr_t, uintptr_t, uintptr_t, -+ uintptr_t, uintptr_t, uintptr_t, -+ uintptr_t); -+ -+#define DTRACE_SYSCALL_WRAP_PREFIX "" -+#else -+#include <asm/dtrace_syscall_types.h> -+#endif -+ -+struct dtrace_syscalls { -+ const char *name; -+ dtrace_id_t stsy_entry; -+ dtrace_id_t stsy_return; -+ dt_sys_call_t stsy_underlying; -+ dt_sys_call_t *stsy_tblent; -+}; -+ -+typedef void (*dtrace_systrace_probe_t)(dtrace_id_t, uintptr_t, uintptr_t, -+ uintptr_t, uintptr_t, uintptr_t, -+ uintptr_t, uintptr_t); -+ -+struct systrace_info { -+ dtrace_systrace_probe_t *probep; -+ dtrace_systrace_probe_t stub; -+ dt_sys_call_t syscall; -+ dt_sys_call_t stubs[SCE_nr_stubs]; -+ struct dtrace_syscalls sysent[NR_syscalls]; -+}; -+ -+extern struct systrace_info *dtrace_syscalls_init(void); -+ -+#endif /* _LINUX_DTRACE_SYSCALL_H_ */ -diff --git a/kernel/dtrace/Kconfig b/kernel/dtrace/Kconfig -index 854e4411343f..d04ca0ab7ac9 100644 ---- a/kernel/dtrace/Kconfig -+++ b/kernel/dtrace/Kconfig -@@ -23,6 +23,15 @@ config DT_CORE - - if DT_CORE - -+config DT_SYSTRACE -+ tristate "System Call Tracing" -+ default m -+ select FTRACE -+ select FTRACE_SYSCALLS -+ help -+ Provides DTrace probes at the entry and exit of all system calls, -+ in the syscall provider. -+ - config DT_DT_TEST - tristate "DTrace Test Probe" - default m -diff --git a/kernel/dtrace/Makefile b/kernel/dtrace/Makefile -index 872785327c3d..68fc3861e5d1 100644 ---- a/kernel/dtrace/Makefile -+++ b/kernel/dtrace/Makefile -@@ -3,6 +3,7 @@ - # - - DT_CORE_ARCH_OBJS = $(addprefix ../../arch/$(SRCARCH)/kernel/, \ -+ dtrace_syscall.o dtrace_syscall_stubs.o \ - dtrace_util.o) - - ifdef CONFIG_DT_CORE --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/dtrace-patches/0007-dtrace-systrace-provider.patch b/sys-kernel/cairn-sources/files/5.10.13/dtrace-patches/0007-dtrace-systrace-provider.patch deleted file mode 100644 index a9e8b5659cd4..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/dtrace-patches/0007-dtrace-systrace-provider.patch +++ /dev/null @@ -1,374 +0,0 @@ -From 5d684eeadb4a16c417cfc365180a4b6a9364866f Mon Sep 17 00:00:00 2001 -From: Kris Van Hees <kris.van.hees@oracle.com> -Date: Mon, 19 Nov 2018 17:58:09 +0000 -Subject: [PATCH 07/19] dtrace: systrace provider - -This implements the DTrace systrace provider, which intercepts system -call invocations. - -Signed-off-by: Nick Alcock <nick.alcock@oracle.com> -Signed-off-by: Kris Van Hees <kris.van.hees@oracle.com> -Signed-off-by: Tomas Jedlicka <tomas.jedlicka@oracle.com> -Signed-off-by: Eugene Loh <eugene.loh@oracle.com> -Signed-off-by: David Mc Lean <david.mclean@oracle.com> -Signed-off-by: Vincent Lim <vincent.lim@oracle.com> ---- - dtrace/Makefile | 2 + - dtrace/systrace.h | 33 +++++++ - dtrace/systrace_dev.c | 224 ++++++++++++++++++++++++++++++++++++++++++ - dtrace/systrace_mod.c | 52 ++++++++++ - 4 files changed, 311 insertions(+) - create mode 100644 dtrace/systrace.h - create mode 100644 dtrace/systrace_dev.c - create mode 100644 dtrace/systrace_mod.c - -diff --git a/dtrace/Makefile b/dtrace/Makefile -index 36a4b97b922c..b91bc69d3802 100644 ---- a/dtrace/Makefile -+++ b/dtrace/Makefile -@@ -3,6 +3,7 @@ - # - - obj-$(CONFIG_DT_CORE) += dtrace.o -+obj-$(CONFIG_DT_SYSTRACE) += systrace.o - obj-$(CONFIG_DT_DT_TEST) += dt_test.o - - dtrace-y := dtrace_mod.o dtrace_dev.o \ -@@ -14,6 +15,7 @@ dtrace-y := dtrace_mod.o dtrace_dev.o \ - dtrace_probe.o dtrace_probe_ctx.o \ - dtrace_ptofapi.o dtrace_predicate.o \ - dtrace_spec.o dtrace_state.o dtrace_util.o -+systrace-y := systrace_mod.o systrace_dev.o - dt_test-y := dt_test_mod.o dt_test_dev.o - - -include arch/$(SRCARCH)/dtrace/Makefile.arch -diff --git a/dtrace/systrace.h b/dtrace/systrace.h -new file mode 100644 -index 000000000000..832bc613b966 ---- /dev/null -+++ b/dtrace/systrace.h -@@ -0,0 +1,33 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Dynamic Tracing for Linux - syscall tracing provider -+ * -+ * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#ifndef _SYSTRACE_H_ -+#define _SYSTRACE_H_ -+ -+#include "dtrace.h" -+ -+extern void systrace_provide(void *, const struct dtrace_probedesc *); -+extern int systrace_enable(void *arg, dtrace_id_t, void *); -+extern void systrace_disable(void *arg, dtrace_id_t, void *); -+extern void systrace_destroy(void *, dtrace_id_t, void *); -+ -+extern dtrace_provider_id_t syscall_id; -+ -+extern int syscall_dev_init(void); -+extern void syscall_dev_exit(void); -+ -+#endif /* _SYSTRACE_H_ */ -diff --git a/dtrace/systrace_dev.c b/dtrace/systrace_dev.c -new file mode 100644 -index 000000000000..2ff3ba4329a5 ---- /dev/null -+++ b/dtrace/systrace_dev.c -@@ -0,0 +1,224 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: systrace_dev.c -+ * DESCRIPTION: DTrace - systrace provider device driver -+ * -+ * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/dtrace_syscall.h> -+#include <linux/fs.h> -+#include <linux/miscdevice.h> -+#include <asm/unistd.h> -+ -+#include "dtrace.h" -+#include "dtrace_dev.h" -+#include "systrace.h" -+ -+#define SYSTRACE_ARTIFICIAL_FRAMES 1 -+ -+#define SYSTRACE_SHIFT 16 -+#define SYSTRACE_ENTRY(id) ((1 << SYSTRACE_SHIFT) | (id)) -+#define SYSTRACE_RETURN(id) (id) -+#define SYSTRACE_SYSNUM(x) ((int)(x) & ((1 << SYSTRACE_SHIFT) - 1)) -+#define SYSTRACE_ISENTRY(x) ((int)(x) >> SYSTRACE_SHIFT) -+ -+#if ((1 << SYSTRACE_SHIFT) <= NR_syscalls) -+# error 1 << SYSTRACE_SHIFT must exceed number of system calls -+#endif -+ -+static struct systrace_info *systrace_info; -+ -+void systrace_provide(void *arg, const struct dtrace_probedesc *desc) -+{ -+ int failed_count = 0; -+ int i; -+ -+ ASSERT(systrace_info != NULL); -+ -+ if (desc != NULL) -+ return; -+ -+ for (i = 0; i < NR_syscalls; i++) { -+ const char *nm = systrace_info->sysent[i].name; -+ dtrace_id_t id; -+ int sz; -+ size_t wrap_len; -+ -+ if (nm == NULL) -+ continue; -+ -+ if (systrace_info->sysent[i].stsy_underlying == NULL) -+ continue; -+ -+ wrap_len = strlen(DTRACE_SYSCALL_WRAP_PREFIX); -+ sz = strlen(nm); -+ if (sz > wrap_len && -+ memcmp(nm, DTRACE_SYSCALL_WRAP_PREFIX, wrap_len) == 0) { -+ nm += wrap_len; -+ sz -= wrap_len; -+ } -+ if (sz > 4 && memcmp(nm, "sys_", 4) == 0) -+ nm += 4; -+ else if (sz > 5 && memcmp(nm, "stub_", 5) == 0) -+ nm += 5; -+ -+ id = dtrace_probe_lookup(syscall_id, dtrace_kmod->name, nm, -+ "entry"); -+ if (id == DTRACE_IDNONE) { -+ id = dtrace_probe_create(syscall_id, dtrace_kmod->name, -+ nm, "entry", -+ SYSTRACE_ARTIFICIAL_FRAMES, -+ (void *)((uintptr_t)SYSTRACE_ENTRY(i))); -+ if (id == DTRACE_IDNONE) -+ failed_count++; -+ -+ systrace_info->sysent[i].stsy_entry = DTRACE_IDNONE; -+ } -+ -+ id = dtrace_probe_lookup(syscall_id, dtrace_kmod->name, nm, -+ "return"); -+ if (id == DTRACE_IDNONE) { -+ id = dtrace_probe_create(syscall_id, dtrace_kmod->name, -+ nm, "return", -+ SYSTRACE_ARTIFICIAL_FRAMES, -+ (void *)((uintptr_t)SYSTRACE_RETURN(i))); -+ if (id == DTRACE_IDNONE) -+ failed_count++; -+ -+ systrace_info->sysent[i].stsy_return = DTRACE_IDNONE; -+ } -+ } -+ -+ if (failed_count > 0) -+ pr_warn("systrace: Failed to provide %d probes (out of memory)\n", failed_count); -+} -+ -+static dt_sys_call_t get_intercept(int sysnum) -+{ -+ switch (sysnum) { -+ default: -+ return systrace_info->syscall; -+#define DTRACE_SYSCALL_STUB(t, n) \ -+ case __NR_##n: \ -+ return systrace_info->stubs[SCE_##t]; -+#include <asm/dtrace_syscall.h> -+#undef DTRACE_SYSCALL_STUB -+ } -+} -+ -+int systrace_enable(void *arg, dtrace_id_t id, void *parg) -+{ -+ int sysnum = SYSTRACE_SYSNUM((uintptr_t)parg); -+ struct dtrace_syscalls *sc = &systrace_info->sysent[sysnum]; -+ int enabled = sc->stsy_entry != DTRACE_IDNONE || -+ sc->stsy_return != DTRACE_IDNONE; -+ dt_sys_call_t intercept = get_intercept(sysnum); -+ -+ if (!enabled) { -+ if (cmpxchg(sc->stsy_tblent, sc->stsy_underlying, -+ intercept) != sc->stsy_underlying) -+ return 1; -+ } else -+ ASSERT(*sc->stsy_tblent == intercept); -+ -+ if (SYSTRACE_ISENTRY((uintptr_t)parg)) -+ sc->stsy_entry = id; -+ else -+ sc->stsy_return = id; -+ -+ return 0; -+} -+ -+void systrace_disable(void *arg, dtrace_id_t id, void *parg) -+{ -+ int sysnum = SYSTRACE_SYSNUM((uintptr_t)parg); -+ struct dtrace_syscalls *sc = &systrace_info->sysent[sysnum]; -+ int enabled = -+ (sc->stsy_entry != DTRACE_IDNONE ? 1 : 0) + -+ (sc->stsy_return != DTRACE_IDNONE ? 1 : 0); -+ dt_sys_call_t intercept = get_intercept(sysnum); -+ -+ /* -+ * Every syscall can have 2 probes associated with it. We need to keep -+ * the interceptor in place until the last probe is getting disabled. -+ */ -+ if (enabled == 1) -+ (void)cmpxchg(sc->stsy_tblent, intercept, sc->stsy_underlying); -+ -+ if (SYSTRACE_ISENTRY((uintptr_t)parg)) -+ sc->stsy_entry = DTRACE_IDNONE; -+ else -+ sc->stsy_return = DTRACE_IDNONE; -+} -+ -+void systrace_destroy(void *arg, dtrace_id_t id, void *parg) -+{ -+ int sysnum = SYSTRACE_SYSNUM((uintptr_t)parg); -+ -+ /* -+ * Nothing to be done here - just ensure our probe has been disabled. -+ */ -+ if (SYSTRACE_ISENTRY((uintptr_t)parg)) -+ ASSERT(systrace_info->sysent[sysnum].stsy_entry == -+ DTRACE_IDNONE); -+ else -+ ASSERT(systrace_info->sysent[sysnum].stsy_return == -+ DTRACE_IDNONE); -+} -+ -+static int systrace_open(struct inode *inode, struct file *file) -+{ -+ return -EAGAIN; -+} -+ -+static int systrace_close(struct inode *inode, struct file *file) -+{ -+ return 0; -+} -+ -+static const struct file_operations systrace_fops = { -+ .owner = THIS_MODULE, -+ .open = systrace_open, -+ .release = systrace_close, -+}; -+ -+static struct miscdevice systrace_dev = { -+ .minor = DT_DEV_SYSTRACE_MINOR, -+ .name = "systrace", -+ .nodename = "dtrace/provider/systrace", -+ .fops = &systrace_fops, -+}; -+ -+int syscall_dev_init(void) -+{ -+ int ret = 0; -+ -+ systrace_info = dtrace_syscalls_init(); -+ -+ ret = misc_register(&systrace_dev); -+ if (ret) -+ pr_err("%s: Can't register misc device %d\n", -+ systrace_dev.name, systrace_dev.minor); -+ -+ *(systrace_info->probep) = (dtrace_systrace_probe_t)dtrace_probe; -+ -+ return ret; -+} -+ -+void syscall_dev_exit(void) -+{ -+ *(systrace_info->probep) = systrace_info->stub; -+ -+ misc_deregister(&systrace_dev); -+} -diff --git a/dtrace/systrace_mod.c b/dtrace/systrace_mod.c -new file mode 100644 -index 000000000000..d286f7d9d47a ---- /dev/null -+++ b/dtrace/systrace_mod.c -@@ -0,0 +1,52 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: systrace_mod.c -+ * DESCRIPTION: DTrace - systrace provider kernel module -+ * -+ * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/module.h> -+ -+#include "dtrace.h" -+#include "dtrace_dev.h" -+#include "systrace.h" -+ -+MODULE_AUTHOR("Kris Van Hees (kris.van.hees@oracle.com)"); -+MODULE_DESCRIPTION("System Call Tracing"); -+MODULE_VERSION("v0.1"); -+MODULE_LICENSE("GPL"); -+ -+static const struct dtrace_pattr syscall_attr = { -+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA }, -+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA }, -+}; -+ -+static struct dtrace_pops syscall_pops = { -+ .dtps_provide = systrace_provide, -+ .dtps_provide_module = NULL, -+ .dtps_destroy_module = NULL, -+ .dtps_enable = systrace_enable, -+ .dtps_disable = systrace_disable, -+ .dtps_suspend = NULL, -+ .dtps_resume = NULL, -+ .dtps_getargdesc = NULL, -+ .dtps_getargval = NULL, -+ .dtps_usermode = NULL, -+ .dtps_destroy = systrace_destroy -+}; -+ -+DT_PROVIDER_MODULE(syscall, DTRACE_PRIV_USER) --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/dtrace-patches/0008-dtrace-sdt-provider-core-components.patch b/sys-kernel/cairn-sources/files/5.10.13/dtrace-patches/0008-dtrace-sdt-provider-core-components.patch deleted file mode 100644 index dc5efdd39ea6..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/dtrace-patches/0008-dtrace-sdt-provider-core-components.patch +++ /dev/null @@ -1,3112 +0,0 @@ -From 0bf2a2a85df13740247a26e7b217f39eda237b0c Mon Sep 17 00:00:00 2001 -From: Kris Van Hees <kris.van.hees@oracle.com> -Date: Mon, 19 Nov 2018 22:03:10 +0000 -Subject: [PATCH 08/19] dtrace: sdt provider core components - -This implements the core (linked-in) machinery needed for SDT -tracepoints: - - - generate empty stub function calls __dtrace_probe_* for each probe - point and perf-event probe point, and record their section-relative - offset in tables in special symbols in the output; calls to - is-enabling probes (conditionals of the form - if (DTRACE_FOO_ENABLED(probe-name))) are translated as well - - similarly record the names and types of arguments to probes in - special sections - - parse both of these at load time, and substitute in nops over the top - of the stub functions, remembering their locations: is-enabled probes - get 0-returns patched over the top - - on probe enabling, patch invalid-operation traps over the top of - those stub functions; handle these by calling the probe, then return - as if the trap had never happened - -The provider module itself is added in the next commit. - -Signed-off-by: Nick Alcock <nick.alcock@oracle.com> -Signed-off-by: Kris Van Hees <kris.van.hees@oracle.com> -Signed-off-by: Tomas Jedlicka <tomas.jedlicka@oracle.com> -Signed-off-by: Eugene Loh <eugene.loh@oracle.com> -Signed-off-by: David Mc Lean <david.mclean@oracle.com> -Signed-off-by: Vincent Lim <vincent.lim@oracle.com> ---- - .gitignore | 6 + - Makefile | 1 + - arch/x86/dtrace/include/dtrace/sdt_arch.h | 28 ++ - arch/x86/include/asm/dtrace_arch.h | 8 +- - arch/x86/include/asm/dtrace_sdt_arch.h | 11 + - arch/x86/include/asm/dtrace_util.h | 13 + - arch/x86/include/asm/spinlock.h | 1 + - arch/x86/include/asm/text-patching.h | 1 + - arch/x86/kernel/alternative.c | 2 +- - arch/x86/kernel/dtrace_sdt.c | 76 +++ - arch/x86/kernel/dtrace_util.c | 214 +++++++- - arch/x86/kernel/vmlinux.lds.S | 3 +- - include/asm-generic/vmlinux.lds.h | 16 + - include/linux/dtrace_os.h | 3 + - include/linux/dtrace_sdt.h | 32 ++ - include/linux/module.h | 5 + - include/linux/sdt.h | 191 +++++++ - include/linux/sdt_internal.h | 276 ++++++++++ - include/linux/tracepoint.h | 8 +- - kernel/dtrace/Kconfig | 16 + - kernel/dtrace/Makefile | 3 +- - kernel/dtrace/dtrace_os.c | 83 +++ - kernel/dtrace/dtrace_sdt_core.c | 364 ++++++++++++++ - kernel/module.c | 14 + - scripts/.gitignore | 1 + - scripts/Makefile | 6 + - scripts/Makefile.modfinal | 52 +- - scripts/dtrace_sdt.sh | 588 ++++++++++++++++++++++ - scripts/kmodsdt.c | 410 +++++++++++++++ - scripts/link-vmlinux.sh | 69 ++- - scripts/mod/modpost.c | 19 +- - 31 files changed, 2500 insertions(+), 20 deletions(-) - create mode 100644 arch/x86/dtrace/include/dtrace/sdt_arch.h - create mode 100644 arch/x86/include/asm/dtrace_sdt_arch.h - create mode 100644 arch/x86/kernel/dtrace_sdt.c - create mode 100644 include/linux/dtrace_sdt.h - create mode 100644 include/linux/sdt.h - create mode 100644 include/linux/sdt_internal.h - create mode 100644 kernel/dtrace/dtrace_sdt_core.c - create mode 100755 scripts/dtrace_sdt.sh - create mode 100644 scripts/kmodsdt.c - -diff --git a/.gitignore b/.gitignore -index 1c10cd7ce033..13954b4624a9 100644 ---- a/.gitignore -+++ b/.gitignore -@@ -158,3 +158,9 @@ x509.genkey - - # Documentation toolchain - sphinx_*/ -+# -+# Generated DTrace SDT files -+# -+*.sdtinfo.c -+*.sdtinfo.h -+*.sdtstub.S -diff --git a/Makefile b/Makefile -index 4b25be692ac1..e3f113b64681 100644 ---- a/Makefile -+++ b/Makefile -@@ -1883,6 +1883,7 @@ clean: $(clean-dirs) - -o -name '*.dtb' -o -name '*.dtb.S' -o -name '*.dt.yaml' \ - -o -name '*.dwo' -o -name '*.lst' \ - -o -name '*.su' -o -name '*.mod' \ -+ -o -name '*.sdtinfo.c' -o -name '*.sdtinfo.h' -o -name '*.sdtstub.S' \ - -o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \ - -o -name '*.lex.c' -o -name '*.tab.[ch]' \ - -o -name '*.asn1.[ch]' \ -diff --git a/arch/x86/dtrace/include/dtrace/sdt_arch.h b/arch/x86/dtrace/include/dtrace/sdt_arch.h -new file mode 100644 -index 000000000000..d8616b44079b ---- /dev/null -+++ b/arch/x86/dtrace/include/dtrace/sdt_arch.h -@@ -0,0 +1,28 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Dynamic Tracing for Linux - SDT Implementation defines -+ * -+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _X86_64_SDT_ARCH_H -+#define _X86_64_SDT_ARCH_H -+ -+#define SDT_AFRAMES 4 -+ -+#endif /* _X86_64_SDT_ARCH_H */ -diff --git a/arch/x86/include/asm/dtrace_arch.h b/arch/x86/include/asm/dtrace_arch.h -index 74e27f08a873..88beb8e4db0b 100644 ---- a/arch/x86/include/asm/dtrace_arch.h -+++ b/arch/x86/include/asm/dtrace_arch.h -@@ -12,16 +12,22 @@ - - typedef uint8_t asm_instr_t; - -+#define ASM_CALL_SIZE 5 -+ - typedef int (*prov_exit_f)(void); - - /* - * Structure to hold DTrace specific information about modules (including the - * core kernel module). Note that each module (and the main kernel) already -- * has one field that relates to probing: -+ * has three fields that relate to probing: -+ * - sdt_probes: description of SDT probes in the module -+ * - sdt_probec: number of SDT probes in the module - * - pdata: pointer to a dtrace_module struct (for DTrace) - */ - struct dtrace_module { - int enabled_cnt; -+ size_t sdt_probe_cnt; -+ size_t fbt_probe_cnt; - prov_exit_f prov_exit; /* Called with module_mutex held */ - }; - -diff --git a/arch/x86/include/asm/dtrace_sdt_arch.h b/arch/x86/include/asm/dtrace_sdt_arch.h -new file mode 100644 -index 000000000000..59f57cb489ab ---- /dev/null -+++ b/arch/x86/include/asm/dtrace_sdt_arch.h -@@ -0,0 +1,11 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+ -+/* Copyright (C) 2016 Oracle, Inc. */ -+ -+#ifndef _X86_DTRACE_SDT_ARCH_H -+#define _X86_DTRACE_SDT_ARCH_H -+ -+#define __DTRACE_SDT_ISENABLED_PROTO void -+#define __DTRACE_SDT_ISENABLED_ARGS -+ -+#endif /* _X86_DTRACE_SDT_ARCH_H */ -diff --git a/arch/x86/include/asm/dtrace_util.h b/arch/x86/include/asm/dtrace_util.h -index 4d9843bbc95b..ce28bf42a59d 100644 ---- a/arch/x86/include/asm/dtrace_util.h -+++ b/arch/x86/include/asm/dtrace_util.h -@@ -6,11 +6,24 @@ - #ifndef _X86_DTRACE_UTIL_H - #define _X86_DTRACE_UTIL_H - -+#define DTRACE_INVOP_NOPS 0x0f /* 5-byte NOP sequence */ -+#define DTRACE_INVOP_MOV_RSP_RBP 0x48 /* mov %rsp, %rbp = 48 89 e5 */ -+#define DTRACE_INVOP_PUSH_BP 0x55 /* push %rbp = 55 */ -+#define DTRACE_INVOP_NOP 0x90 /* nop = 90 */ -+#define DTRACE_INVOP_LEAVE 0xc9 /* leave = c9 */ -+#define DTRACE_INVOP_RET 0xc3 /* ret = c3 */ -+ - #ifndef __ASSEMBLY__ - - #include <asm/dtrace_arch.h> - #include <asm/ptrace.h> - -+extern int dtrace_invop_add(uint8_t (*func)(struct pt_regs *)); -+extern void dtrace_invop_remove(uint8_t (*func)(struct pt_regs *)); -+ -+extern void dtrace_invop_enable(asm_instr_t *, asm_instr_t); -+extern void dtrace_invop_disable(asm_instr_t *, asm_instr_t); -+ - #endif - - #endif /* _X86_DTRACE_UTIL_H */ -diff --git a/arch/x86/include/asm/spinlock.h b/arch/x86/include/asm/spinlock.h -index 5b6bc7016c22..79e017f90c60 100644 ---- a/arch/x86/include/asm/spinlock.h -+++ b/arch/x86/include/asm/spinlock.h -@@ -9,6 +9,7 @@ - #include <linux/compiler.h> - #include <asm/paravirt.h> - #include <asm/bitops.h> -+#include <linux/sdt.h> - - /* - * Your basic SMP spinlocks, allowing only a single CPU anywhere -diff --git a/arch/x86/include/asm/text-patching.h b/arch/x86/include/asm/text-patching.h -index b7421780e4e9..127a59c41e6d 100644 ---- a/arch/x86/include/asm/text-patching.h -+++ b/arch/x86/include/asm/text-patching.h -@@ -25,6 +25,7 @@ static inline void apply_paravirt(struct paravirt_patch_site *start, - */ - #define POKE_MAX_OPCODE_SIZE 5 - -+extern void add_nops(void *insns, unsigned int len); - extern void text_poke_early(void *addr, const void *opcode, size_t len); - - /* -diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c -index 2400ad62f330..389c3870ce48 100644 ---- a/arch/x86/kernel/alternative.c -+++ b/arch/x86/kernel/alternative.c -@@ -256,7 +256,7 @@ void __init arch_init_ideal_nops(void) - } - - /* Use this to add nops to a buffer, then text_poke the whole buffer. */ --static void __init_or_module add_nops(void *insns, unsigned int len) -+void __init_or_module add_nops(void *insns, unsigned int len) - { - while (len > 0) { - unsigned int noplen = len; -diff --git a/arch/x86/kernel/dtrace_sdt.c b/arch/x86/kernel/dtrace_sdt.c -new file mode 100644 -index 000000000000..31bb962573fb ---- /dev/null -+++ b/arch/x86/kernel/dtrace_sdt.c -@@ -0,0 +1,76 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_sdt.c -+ * DESCRIPTION: Dynamic Tracing: SDT registration code (arch-specific) -+ * -+ * Copyright (c) 2010, 2020, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/memory.h> -+#include <linux/module.h> -+#include <linux/dtrace_os.h> -+#include <linux/sdt.h> -+#include <linux/slab.h> -+#include <linux/sync_core.h> -+#include <linux/vmalloc.h> -+#include <asm/nmi.h> -+#include <asm/nops.h> -+#include <asm/dtrace_arch.h> -+#include <asm/text-patching.h> -+ -+static uint8_t nops[ASM_CALL_SIZE]; -+static uint8_t movs[ASM_CALL_SIZE]; -+ -+#define DT_OP_REX_RAX 0x48 -+#define DT_OP_XOR_EAX_0 0x33 -+#define DT_OP_XOR_EAX_1 0xc0 -+ -+/* This code is based on apply_alternatives and text_poke_early. It needs to -+ * run before SMP is initialized in order to avoid SMP problems with patching -+ * code that might be accessed on another CPU. -+ */ -+void __init_or_module dtrace_sdt_nop_multi(asm_instr_t **addrs, -+ int *is_enabled, int cnt) -+{ -+ int i; -+ asm_instr_t *addr; -+ unsigned long flags; -+ -+ stop_nmi(); -+ local_irq_save(flags); -+ -+ for (i = 0; i < cnt; i++) { -+ addr = addrs[i]; -+ if (likely(!is_enabled[i])) -+ memcpy(addr, nops, sizeof(nops)); -+ else -+ memcpy(addr, movs, sizeof(movs)); -+ } -+ -+ sync_core(); -+ local_irq_restore(flags); -+ restart_nmi(); -+} -+ -+void __init dtrace_sdt_init_arch(void) -+{ -+ /* -+ * A little unusual, but potentially necessary. While we could use a -+ * single NOP sequence of length ASM_CALL_SIZE, we need to consider the -+ * fact that when a SDT probe point is enabled, a single invalid opcode -+ * is written on the first byte of this NOP sequence. By using a -+ * sequence of a 1-byte NOP, followed by a (ASM_CALL_SIZE - 1) byte NOP -+ * sequence, we play it pretty safe. -+ */ -+ add_nops(nops, 1); -+ add_nops(nops + 1, ASM_CALL_SIZE - 1); -+ -+ /* -+ * Is-enabled probe points contain an "xor %rax, %rax" when disabled. -+ */ -+ movs[0] = DT_OP_REX_RAX; -+ movs[1] = DT_OP_XOR_EAX_0; -+ movs[2] = DT_OP_XOR_EAX_1; -+ add_nops(movs + 3, ASM_CALL_SIZE - 3); -+} -diff --git a/arch/x86/kernel/dtrace_util.c b/arch/x86/kernel/dtrace_util.c -index d3d552c062f7..f138fd62f555 100644 ---- a/arch/x86/kernel/dtrace_util.c -+++ b/arch/x86/kernel/dtrace_util.c -@@ -61,6 +61,13 @@ void dtrace_handle_badaddr(struct pt_regs *regs) - dtrace_skip_instruction(regs); - } - -+struct dtrace_invop_hdlr { -+ uint8_t (*dtih_func)(struct pt_regs *); -+ struct dtrace_invop_hdlr *dtih_next; -+}; -+ -+static struct dtrace_invop_hdlr *dtrace_invop_hdlrs; -+ - /* - * Trap notification handler. - */ -@@ -68,6 +75,7 @@ int dtrace_die_notifier(struct notifier_block *nb, unsigned long val, - void *args) - { - struct die_args *dargs = args; -+ int orig_trapnr = 0; - - switch (val) { - case DIE_PAGE_FAULT: { -@@ -79,12 +87,141 @@ int dtrace_die_notifier(struct notifier_block *nb, unsigned long val, - return NOTIFY_OK | NOTIFY_STOP_MASK; - } - case DIE_GPF: { -- if (!DTRACE_CPUFLAG_ISSET(CPU_DTRACE_NOFAULT)) -+ /* -+ * This gets messy... For one, some versions of Xen deliver -+ * the invalid opcode generated by the LOCK prefix (0xf0) as a -+ * GP fault rather than a UD fault. So, we need to figure out -+ * whether the GP we're processing here is one of those -+ * misreported faults. -+ * -+ * But, it is possible that the instruction that caused the -+ * fault (0xf0) gets overwritten by a different CPU with the -+ * original valid opcode before we get to look at it here, -+ * which makes it kind of hard to recognize. -+ * -+ * So... we're going to assume that a GP fault that gets -+ * triggered for the LOCK prefix opcode (0xf0) *or* for an -+ * opcode that can get overwritten with the LOCK prefix for -+ * probing is actually a UD fault. -+ * -+ * If we are wrong, the handlers will simply see a fault that -+ * isn't theirs, and return without consuming it. And in that -+ * case, the kernel will report a UD fault that may have been -+ * a real GP fault... Sorry. -+ */ -+ asm_instr_t opc = *(asm_instr_t *)dargs->regs->ip; -+ -+ if (opc != 0xf0 && opc != 0x55 && opc != 0xc3) { -+ if (!DTRACE_CPUFLAG_ISSET(CPU_DTRACE_NOFAULT)) -+ return NOTIFY_DONE; -+ -+ dtrace_handle_badaddr(dargs->regs); -+ -+ return NOTIFY_OK | NOTIFY_STOP_MASK; -+ } -+ -+ /* -+ * ... and instead treat them as the SDT probe point traps that -+ * they are. -+ */ -+ orig_trapnr = dargs->trapnr; -+ dargs->trapnr = 6; -+ } -+ /* fallthrough */ -+ case DIE_TRAP: { -+ struct dtrace_invop_hdlr *hdlr; -+ int rval = 0; -+ -+ if (dargs->trapnr != 6) - return NOTIFY_DONE; - -- dtrace_handle_badaddr(dargs->regs); -+ for (hdlr = dtrace_invop_hdlrs; hdlr != NULL; -+ hdlr = hdlr->dtih_next) { -+ rval = hdlr->dtih_func(dargs->regs); -+ if (rval != 0) -+ break; -+ } - -- return NOTIFY_OK | NOTIFY_STOP_MASK; -+ switch (rval) { -+ case DTRACE_INVOP_NOPS: -+ /* -+ * SDT probe points are encoded as either: -+ * - a 1-byte NOP followed by a multi-byte NOP -+ * - a multi-byte code sequence (to set AX to 0), -+ * followed by a multi-byte NOP -+ * In both cases, the total length of the probe point -+ * instruction is ASM_CALL_SITE bytes, so we can safely -+ * skip that number of bytes here. -+ */ -+ dargs->regs->ip += ASM_CALL_SIZE; -+ return NOTIFY_OK | NOTIFY_STOP_MASK; -+ case DTRACE_INVOP_MOV_RSP_RBP: -+ case DTRACE_INVOP_NOP: -+ case DTRACE_INVOP_PUSH_BP: -+ case DTRACE_INVOP_RET: -+ return notifier_from_errno(-rval); -+ default: -+ /* -+ * This must not have been a trap triggered from a -+ * probe point. Let someone else deal with it... -+ * -+ * If we got here because of a GPF that we thought -+ * was a UD (due to a bug in some versions of Xen), -+ * undo our change to dargs->trapnr. -+ */ -+ if (unlikely(orig_trapnr)) -+ dargs->trapnr = orig_trapnr; -+ -+ return NOTIFY_DONE; -+ } -+ } -+ case DIE_INT3: { -+ struct dtrace_invop_hdlr *hdlr; -+ int rval = 0; -+ -+ /* -+ * Let's assume that this is a DTrace probe firing, so we need -+ * to adjust the IP (to be consistent with #UD processing) so -+ * that it reflects the address of the #BP rather than the -+ * following intruction. -+ * -+ * If it turns out that this was not DTrace related, we'll have -+ * to reverse this adjustment. -+ */ -+ dargs->regs->ip--; -+ for (hdlr = dtrace_invop_hdlrs; hdlr != NULL; -+ hdlr = hdlr->dtih_next) { -+ rval = hdlr->dtih_func(dargs->regs); -+ if (rval != 0) -+ break; -+ } -+ -+ switch (rval) { -+ case DTRACE_INVOP_NOPS: -+ /* -+ * SDT probe points are encoded as either: -+ * - a 1-byte NOP followed by a multi-byte NOP -+ * - a multi-byte code sequence (to set AX to 0), -+ * followed by a multi-byte NOP -+ * In both cases, the total length of the probe point -+ * instruction is ASM_CALL_SITE bytes, so we can safely -+ * skip that number of bytes here. -+ */ -+ dargs->regs->ip += ASM_CALL_SIZE; -+ return NOTIFY_OK | NOTIFY_STOP_MASK; -+ case DTRACE_INVOP_MOV_RSP_RBP: -+ case DTRACE_INVOP_NOP: -+ case DTRACE_INVOP_PUSH_BP: -+ case DTRACE_INVOP_RET: -+ return notifier_from_errno(-rval); -+ default: -+ /* -+ * This must not have been a trap triggered from a -+ * probe point. Re-adjust the instruction pointer -+ * and let someone else deal with it... -+ */ -+ dargs->regs->ip++; -+ } - } - /* fallthrough */ - default: -@@ -92,6 +229,77 @@ int dtrace_die_notifier(struct notifier_block *nb, unsigned long val, - } - } - -+/* -+ * Add an INVOP trap handler. -+ */ -+int dtrace_invop_add(uint8_t (*func)(struct pt_regs *)) -+{ -+ struct dtrace_invop_hdlr *hdlr; -+ -+ hdlr = kmalloc(sizeof(struct dtrace_invop_hdlr), GFP_KERNEL); -+ if (hdlr == NULL) { -+ pr_warn("Failed to add invop handler: out of memory\n"); -+ return -ENOMEM; -+ } -+ -+ hdlr->dtih_func = func; -+ hdlr->dtih_next = dtrace_invop_hdlrs; -+ dtrace_invop_hdlrs = hdlr; -+ -+ return 0; -+} -+EXPORT_SYMBOL(dtrace_invop_add); -+ -+/* -+ * Remove an INVOP trap handler. -+ */ -+void dtrace_invop_remove(uint8_t (*func)(struct pt_regs *)) -+{ -+ struct dtrace_invop_hdlr *hdlr = dtrace_invop_hdlrs, *prev = NULL; -+ -+ for (;;) { -+ if (hdlr == NULL) -+ return; -+ -+ if (hdlr->dtih_func == func) -+ break; -+ -+ prev = hdlr; -+ hdlr = hdlr->dtih_next; -+ } -+ -+ if (prev == NULL) -+ dtrace_invop_hdlrs = hdlr->dtih_next; -+ else -+ prev->dtih_next = hdlr->dtih_next; -+ -+ kfree(hdlr); -+} -+EXPORT_SYMBOL(dtrace_invop_remove); -+ -+/* -+ * Enable an INVOP-based probe, i.e. ensure that an INVOP trap is triggered at -+ * the specified address. -+ */ -+void dtrace_invop_enable(asm_instr_t *addr, asm_instr_t opcode) -+{ -+ mutex_lock(&text_mutex); -+ text_poke(addr, ((unsigned char []){opcode}), 1); -+ mutex_unlock(&text_mutex); -+} -+EXPORT_SYMBOL(dtrace_invop_enable); -+ -+/* -+ * Disable an INVOP-based probe. -+ */ -+void dtrace_invop_disable(asm_instr_t *addr, asm_instr_t opcode) -+{ -+ mutex_lock(&text_mutex); -+ text_poke(addr, ((unsigned char []){opcode}), 1); -+ mutex_unlock(&text_mutex); -+} -+EXPORT_SYMBOL(dtrace_invop_disable); -+ - static inline int dtrace_bad_address(void *addr) - { - unsigned long dummy; -diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S -index bf9e0adb5b7e..970b6cd011f6 100644 ---- a/arch/x86/kernel/vmlinux.lds.S -+++ b/arch/x86/kernel/vmlinux.lds.S -@@ -473,7 +473,8 @@ INIT_PER_CPU(irq_stack_backing_store); - /* - * Build-time check on the image size: - */ --. = ASSERT((_end - _text <= KERNEL_IMAGE_SIZE), -+. = ASSERT(((_end < _text) ? (_end < KERNEL_IMAGE_SIZE) -+ : (_end - _text <= KERNEL_IMAGE_SIZE)), - "kernel image bigger than KERNEL_IMAGE_SIZE"); - - #ifdef CONFIG_SMP -diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h -index b2b3d81b1535..7d1517f97db2 100644 ---- a/include/asm-generic/vmlinux.lds.h -+++ b/include/asm-generic/vmlinux.lds.h -@@ -214,6 +214,20 @@ - #define ERROR_INJECT_WHITELIST() - #endif - -+#ifdef CONFIG_DTRACE -+#define DTRACE_SDT_NAMES() . = ALIGN(8); \ -+ __start_dtrace_sdt_names = .; \ -+ KEEP(*(_dtrace_sdt_names)) \ -+ __stop_dtrace_sdt_names = .; -+#define DTRACE_SDT_ARGS() . = ALIGN(8); \ -+ __start_dtrace_sdt_args = .; \ -+ KEEP(*(_dtrace_sdt_args)) \ -+ __stop_dtrace_sdt_args = .; -+#else -+#define DTRACE_SDT_NAMES() -+#define DTRACE_SDT_ARGS() -+#endif -+ - #ifdef CONFIG_EVENT_TRACING - #define FTRACE_EVENTS() . = ALIGN(8); \ - __start_ftrace_events = .; \ -@@ -721,6 +735,8 @@ - FTRACE_EVENTS() \ - TRACE_SYSCALLS() \ - KPROBE_BLACKLIST() \ -+ DTRACE_SDT_NAMES() \ -+ DTRACE_SDT_ARGS() \ - ERROR_INJECT_WHITELIST() \ - MEM_DISCARD(init.rodata) \ - CLK_OF_TABLES() \ -diff --git a/include/linux/dtrace_os.h b/include/linux/dtrace_os.h -index 5bcd77e08a14..f2921ce039a7 100644 ---- a/include/linux/dtrace_os.h -+++ b/include/linux/dtrace_os.h -@@ -25,6 +25,9 @@ extern void __init dtrace_os_init(void); - extern void __init dtrace_psinfo_os_init(void); - extern void __init dtrace_task_os_init(void); - -+extern void *dtrace_alloc_text(struct module *, unsigned long); -+extern void dtrace_free_text(void *); -+ - extern void dtrace_mod_pdata_alloc(struct module *); - extern void dtrace_mod_pdata_free(struct module *); - extern int dtrace_destroy_prov(struct module *); -diff --git a/include/linux/dtrace_sdt.h b/include/linux/dtrace_sdt.h -new file mode 100644 -index 000000000000..3a4d608bc3fa ---- /dev/null -+++ b/include/linux/dtrace_sdt.h -@@ -0,0 +1,32 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+#ifndef _DTRACE_SDT_H_ -+#define _DTRACE_SDT_H_ -+ -+#ifdef CONFIG_DTRACE -+#include <linux/module.h> -+#include <asm/dtrace_arch.h> -+ -+extern void __init dtrace_sdt_init(void); -+extern void __init dtrace_sdt_register(struct module *); -+extern void dtrace_sdt_register_module(struct module *, -+ void *sdt_names_addr, size_t, -+ void *sdt_args_addr, size_t); -+extern void dtrace_sdt_exit(void); -+ -+/* -+ * Functions to be defined in arch/<arch>/kernel/dtrace_sdt.c -+ */ -+extern void __init_or_module dtrace_sdt_nop_multi(asm_instr_t **, int *, int); -+ -+#ifdef CONFIG_X86_64 -+extern void __init dtrace_sdt_init_arch(void); -+#else -+#define dtrace_sdt_init_arch() -+#endif /* CONFIG_X86_64 */ -+ -+#endif /* CONFIG_DTRACE */ -+#endif /* _DTRACE_SDT_H_ */ -diff --git a/include/linux/module.h b/include/linux/module.h -index 44915ed85337..7abbaeb5d659 100644 ---- a/include/linux/module.h -+++ b/include/linux/module.h -@@ -30,6 +30,8 @@ - #include <linux/percpu.h> - #include <asm/module.h> - -+#include <linux/sdt.h> -+ - /* Not Yet Implemented */ - #define MODULE_SUPPORTED_DEVICE(name) - -@@ -513,8 +515,11 @@ struct module { - #endif - - #ifdef CONFIG_DTRACE -+ struct sdt_probedesc *sdt_probes; -+ unsigned int sdt_probec; - void *pdata; - #endif -+ - #ifdef CONFIG_MODULE_UNLOAD - /* What modules depend on me? */ - struct list_head source_list; -diff --git a/include/linux/sdt.h b/include/linux/sdt.h -new file mode 100644 -index 000000000000..8efb63cff1ac ---- /dev/null -+++ b/include/linux/sdt.h -@@ -0,0 +1,191 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+#ifndef _LINUX_SDT_H_ -+#define _LINUX_SDT_H_ -+ -+#include <linux/sdt_internal.h> -+ -+#if IS_ENABLED(CONFIG_DT_SDT) -+ -+#include <asm/dtrace_sdt_arch.h> -+#include <linux/stringify.h> -+ -+#define DTRACE_PROBE(name, ...) { \ -+ extern int __dtrace_probe_##name(__DTRACE_TYPE_APPLY_DEFAULT(__DTRACE_UINTPTR_EACH, void, ## __VA_ARGS__)); \ -+ (void)__dtrace_probe_##name(__DTRACE_ARG_APPLY(__DTRACE_UINTCAST_EACH, ## __VA_ARGS__)); \ -+ asm volatile(".pushsection _dtrace_sdt_names, \"a\", @progbits\n" \ -+ ".ascii \"" __stringify(name) "\"\n" \ -+ ".byte 0\n" \ -+ ".popsection\n" \ -+ ".pushsection _dtrace_sdt_args, \"a\", @progbits\n" \ -+ __DTRACE_TYPE_APPLY_NOCOMMA(__DTRACE_TYPE_EACH, ## __VA_ARGS__) \ -+ ".byte 0\n" \ -+ ".popsection\n"); \ -+} -+ -+#define DTRACE_PROBE_ENABLED(name) unlikely(({ \ -+ extern int __dtrace_isenabled_##name(__DTRACE_SDT_ISENABLED_PROTO); \ -+ __dtrace_isenabled_##name(__DTRACE_SDT_ISENABLED_ARGS); \ -+})) -+ -+#ifdef CONFIG_DT_SDT_PERF -+ -+#define __DTRACE_UINTPTR_CAST_EACH(x) ({ \ -+ union { \ -+ typeof((x)) __val; \ -+ unsigned char __c; \ -+ unsigned short __s; \ -+ unsigned int __i; \ -+ unsigned long __l; \ -+ unsigned long long __ll; } __u = { .__val = (x) }; \ -+ __builtin_choose_expr(sizeof(__u.__val) == sizeof(__u.__c), __u.__c, \ -+ __builtin_choose_expr(sizeof(__u.__val) == sizeof(__u.__s), __u.__s, \ -+ __builtin_choose_expr(sizeof(__u.__val) == sizeof(__u.__i), __u.__i, \ -+ __builtin_choose_expr(sizeof(__u.__val) == sizeof(__u.__l), __u.__l, \ -+ __builtin_choose_expr(sizeof(__u.__val) == sizeof(__u.__ll), __u.__ll, \ -+ (uintptr_t)&(__u.__val)))))); }) -+ -+#define DTRACE_PROBE_TRACEPOINT(name, ...) { \ -+ extern void __dtrace_probe___perf_##name(__DTRACE_APPLY(__DTRACE_UINTPTR_EACH, ## __VA_ARGS__)); \ -+ __dtrace_probe___perf_##name(__DTRACE_APPLY(__DTRACE_UINTPTR_CAST_EACH, ## __VA_ARGS__)); \ -+} -+ -+#define DTRACE_PROTO_TRACEPOINT(name, ...) { \ -+ asm volatile(".pushsection _dtrace_sdt_names, \"a\", @progbits\n"\ -+ ".ascii \"" __stringify(__perf_##name) "\"\n" \ -+ ".byte 0\n" \ -+ ".popsection\n" \ -+ ".pushsection _dtrace_sdt_args, \"a\", @progbits\n" \ -+ ".ascii \"" __stringify(__VA_ARGS__) "\"\n" \ -+ ".byte 0\n" \ -+ ".popsection\n"); \ -+} -+#else -+ -+#define DTRACE_PROBE_TRACEPOINT(name, ...) -+#define DTRACE_PROTO_TRACEPOINT(name, ...) -+ -+#endif -+ -+#else /* ! IS_ENABLED(CONFIG_DT_SDT) */ -+ -+/* -+ * This apparently redundant call serves to validate the DTRACE_PROBE has the -+ * right number of args even when dtrace is turned off. -+ */ -+#define DTRACE_PROBE(name, ...) \ -+ __DTRACE_DOUBLE_APPLY_NOCOMMA(__DTRACE_NONE, __DTRACE_NONE, ## __VA_ARGS__) \ -+ do { } while (0) -+#define DTRACE_PROBE_ENABLED(name) 0 -+#define DTRACE_PROBE_TRACEPOINT(name, ...) -+#define DTRACE_PROTO_TRACEPOINT(name, ...) -+ -+#endif /* IS_ENABLED(CONFIG_DT_SDT) */ -+ -+#ifdef CONFIG_DTRACE -+ -+struct sdt_probedesc { -+ char *sdpd_name; /* probe name */ -+ char *sdpd_func; /* probe function */ -+#ifndef __GENKSYMS__ -+ const char *sdpd_args; /* arg string */ -+#endif -+ unsigned long sdpd_offset; /* offset of call in text */ -+ struct sdt_probedesc *sdpd_next; /* next static probe */ -+}; -+ -+#endif /* CONFIG_DTRACE */ -+ -+#define DTRACE_SCHED(name, ...) \ -+ DTRACE_PROBE(__sched_##name, ## __VA_ARGS__); -+ -+#define DTRACE_PROC(name, ...) \ -+ DTRACE_PROBE(__proc_##name, ## __VA_ARGS__); -+ -+#define DTRACE_IO(name, ...) \ -+ DTRACE_PROBE(__io_##name, ## __VA_ARGS__); -+ -+#define DTRACE_IO_ENABLED(name) \ -+ DTRACE_PROBE_ENABLED(__io_##name) -+ -+#define DTRACE_ISCSI(name, ...) \ -+ DTRACE_PROBE(__iscsi_##name, ## __VA_ARGS__); -+ -+#define DTRACE_NFSV3(name, ...) \ -+ DTRACE_PROBE(__nfsv3_##name, ## __VA_ARGS__); -+ -+#define DTRACE_NFSV4(name, ...) \ -+ DTRACE_PROBE(__nfsv4_##name, ## __VA_ARGS__); -+ -+#define DTRACE_SMB(name, ...) \ -+ DTRACE_PROBE(__smb_##name, ## __VA_ARGS__); -+ -+/* -+ * These definitions are used at probe points to specify the traffic direction; -+ * this helps simplify argument translation. -+ */ -+#define DTRACE_NET_PROBE_OUTBOUND 0x0 -+#define DTRACE_NET_PROBE_INBOUND 0x1 -+ -+#define DTRACE_IP(name, ...) \ -+ DTRACE_PROBE(__ip_##name, ## __VA_ARGS__); -+ -+/* -+ * Default DTRACE_TCP() and DTRACE_UDP() provider definitions specify the -+ * probe point within an is-enabled predicate. This is to avoid the overhead -+ * incurred during argument dereferencing (e.g. calls to ip_hdr(skb)), along -+ * with any conditional evaluation (which would require branching) when the -+ * probe is disabled. -+ * -+ * Because some TCP probe points require additional argument preparation, -+ * we also define the is-enabled predicate directly as -+ * DTRACE_TCP_ENABLED(probename) along with a probe point which does not -+ * the probe in an is-enabled predicate; this allows us to handle cases such -+ * as this: -+ * -+ * if (DTRACE_TCP_ENABLED(state__change)) { -+ * ...argument preparation... -+ * DTRACE_TCP_NOCHECK(state__change, ...); -+ * } -+ */ -+ -+#define DTRACE_TCP(name, ...) \ -+ if (DTRACE_PROBE_ENABLED(__tcp_##name)) \ -+ DTRACE_PROBE(__tcp_##name, ## __VA_ARGS__) -+#define DTRACE_TCP_ENABLED(name) \ -+ DTRACE_PROBE_ENABLED(__tcp_##name) -+#define DTRACE_TCP_NOCHECK(name, ...) \ -+ DTRACE_PROBE(__tcp_##name, ## __VA_ARGS__); -+ -+#define DTRACE_UDP(name, ...) \ -+ if (DTRACE_PROBE_ENABLED(__udp_##name)) \ -+ DTRACE_PROBE(__udp_##name, ## __VA_ARGS__); -+ -+#define DTRACE_SYSEVENT(name, ...) \ -+ DTRACE_PROBE(__sysevent_##name, ## __VA_ARGS__); -+ -+#define DTRACE_XPV(name, ...) \ -+ DTRACE_PROBE(__xpv_##name, ## __VA_ARGS__); -+ -+#define DTRACE_FC(name, ...) \ -+ DTRACE_PROBE(__fc_##name, ## __VA_ARGS__); -+ -+#define DTRACE_SRP(name, ...) \ -+ DTRACE_PROBE(__srp_##name, ## __VA_ARGS__); -+ -+#define DTRACE_LOCKSTAT_ENABLED(name) \ -+ DTRACE_PROBE_ENABLED(__lockstat_##name) -+ -+#define DTRACE_LOCKSTAT(name, ...) \ -+ DTRACE_PROBE(__lockstat_##name, ## __VA_ARGS__) -+ -+#define DTRACE_LOCKSTAT_RW_WRITER 0 -+#define DTRACE_LOCKSTAT_RW_READER 1 -+ -+/* Needed for lockstat probes where we cannot include ktime.h */ -+extern u64 dtrace_gethrtime_ns(void); -+ -+#endif /* _LINUX_SDT_H_ */ -diff --git a/include/linux/sdt_internal.h b/include/linux/sdt_internal.h -new file mode 100644 -index 000000000000..b544f8e619cf ---- /dev/null -+++ b/include/linux/sdt_internal.h -@@ -0,0 +1,276 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Hide away all the terrible macro magic. -+ * -+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+#ifndef _LINUX_SDT_INTERNAL_H_ -+#define _LINUX_SDT_INTERNAL_H_ -+ -+#include <linux/types.h> -+ -+/* -+ * This counts the number of args. -+ */ -+#define __DTRACE_NARGS_SEQ(dummy, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ -+ _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, \ -+ _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, \ -+ _31, _32, _33, _34, _35, _36, N, ...) N -+#define __DTRACE_NARGS(...) \ -+ __DTRACE_NARGS_SEQ(dummy, ##__VA_ARGS__, 36, 35, 34, 33, 32, 31, \ -+ 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, \ -+ 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, \ -+ 8, 7, 6, 5, 4, 3, 2, 1, 0) -+ -+/* -+ * This will let macros expand before concatting them. -+ */ -+#define __DTRACE_PRIMITIVE_CAT(x, y) x ## y -+#define __DTRACE_CAT(x, y) __DTRACE_PRIMITIVE_CAT(x, y) -+ -+#define __DTRACE_COMMA , -+#define __DTRACE_NO_COMMA -+#define __DTRACE_NONE(x) -+ -+/* -+ * This will call two macros on each argument-pair passed in (the first two args -+ * are the names of the macros to call). Its TYPE and NAME variants will throw -+ * away the name and type arguments, respectively. __DTRACE_*_APPLY_NOCOMMA -+ * are like DTRACE_*_APPLY, but also omit the comma between arguments in the -+ * expansion of the macro. DTRACE_TYPE_APPLY_DEFAULT lets you specify a default -+ * if no variadic args are provided. -+ */ -+#define __DTRACE_DOUBLE_APPLY(type_macro, arg_macro, ...) \ -+ __DTRACE_CAT(__DTRACE_DOUBLE_APPLY_, \ -+ __DTRACE_NARGS(__VA_ARGS__))(type_macro, \ -+ arg_macro, __DTRACE_COMMA, \ -+ __DTRACE_COMMA, , ## __VA_ARGS__) -+#define __DTRACE_DOUBLE_APPLY_NOCOMMA(type_macro, arg_macro, ...) \ -+ __DTRACE_CAT(__DTRACE_DOUBLE_APPLY_, \ -+ __DTRACE_NARGS(__VA_ARGS__))(type_macro, \ -+ arg_macro, __DTRACE_NO_COMMA, \ -+ __DTRACE_NO_COMMA, , ## __VA_ARGS__) -+#define __DTRACE_TYPE_APPLY(type_macro, ...) \ -+ __DTRACE_CAT(__DTRACE_DOUBLE_APPLY_, \ -+ __DTRACE_NARGS(__VA_ARGS__))(type_macro, \ -+ __DTRACE_NONE, __DTRACE_NO_COMMA, \ -+ __DTRACE_COMMA, , ## __VA_ARGS__) -+#define __DTRACE_TYPE_APPLY_NOCOMMA(type_macro, ...) \ -+ __DTRACE_CAT(__DTRACE_DOUBLE_APPLY_, \ -+ __DTRACE_NARGS(__VA_ARGS__))(type_macro, \ -+ __DTRACE_NONE, __DTRACE_NO_COMMA, \ -+ __DTRACE_NO_COMMA, , ## __VA_ARGS__) -+#define __DTRACE_TYPE_APPLY_DEFAULT(type_macro, def, ...) \ -+ __DTRACE_CAT(__DTRACE_DOUBLE_APPLY_, \ -+ __DTRACE_NARGS(__VA_ARGS__))(type_macro, \ -+ __DTRACE_NONE, __DTRACE_NO_COMMA, \ -+ __DTRACE_COMMA, def, ## __VA_ARGS__) -+#define __DTRACE_ARG_APPLY(arg_macro, ...) \ -+ __DTRACE_CAT(__DTRACE_DOUBLE_APPLY_, \ -+ __DTRACE_NARGS(__VA_ARGS__))(__DTRACE_NONE, \ -+ arg_macro, __DTRACE_NO_COMMA, \ -+ __DTRACE_COMMA, , ## __VA_ARGS__) -+#define __DTRACE_DOUBLE_APPLY_0(t, a, comma_t, comma_a, def) def -+#define __DTRACE_DOUBLE_APPLY_2(t, a, comma_t, comma_a, def, type1, arg1) \ -+ t(type1) comma_t a(arg1) -+#define __DTRACE_DOUBLE_APPLY_4(t, a, comma_t, comma_a, def, type1, arg1, \ -+ type2, arg2) \ -+ t(type1) comma_t a(arg1) comma_a t(type2) comma_t a(arg2) -+#define __DTRACE_DOUBLE_APPLY_6(t, a, comma_t, comma_a, def, type1, \ -+ arg1, type2, arg2, type3, arg3) \ -+ t(type1) comma_t a(arg1) comma_a t(type2) comma_t a(arg2) comma_a \ -+ t(type3) comma_t a(arg3) -+#define __DTRACE_DOUBLE_APPLY_8(t, a, comma_t, comma_a, def, type1, arg1, \ -+ type2, arg2, type3, arg3, type4, arg4) \ -+ t(type1) comma_t a(arg1) comma_a t(type2) comma_t a(arg2) comma_a \ -+ t(type3) comma_t a(arg3) comma_a t(type4) comma_t a(arg4) -+#define __DTRACE_DOUBLE_APPLY_10(t, a, comma_t, comma_a, def, type1, arg1,\ -+ type2, arg2, type3, arg3, type4, arg4, \ -+ type5, arg5) \ -+ t(type1) comma_t a(arg1) comma_a t(type2) comma_t a(arg2) comma_a \ -+ t(type3) comma_t a(arg3) comma_a t(type4) comma_t a(arg4) comma_a \ -+ t(type5) comma_t a(arg5) -+#define __DTRACE_DOUBLE_APPLY_12(t, a, comma_t, comma_a, def, type1, \ -+ arg1, type2, arg2, type3, arg3, type4, \ -+ arg4, type5, arg5, type6, arg6) \ -+ t(type1) comma_t a(arg1) comma_a t(type2) comma_t a(arg2) comma_a \ -+ t(type3) comma_t a(arg3) comma_a t(type4) comma_t a(arg4) comma_a \ -+ t(type5) comma_t a(arg5) comma_a t(type6) comma_t a(arg6) -+#define __DTRACE_DOUBLE_APPLY_14(t, a, comma_t, comma_a, def, type1, \ -+ arg1, type2, arg2, type3, arg3, type4, \ -+ arg4, type5, arg5, type6, arg6, type7, \ -+ arg7) \ -+ t(type1) comma_t a(arg1) comma_a t(type2) comma_t a(arg2) comma_a \ -+ t(type3) comma_t a(arg3) comma_a t(type4) comma_t a(arg4) comma_a \ -+ t(type5) comma_t a(arg5) comma_a t(type6) comma_t a(arg6) comma_a \ -+ t(type7) comma_t a(arg7) -+#define __DTRACE_DOUBLE_APPLY_16(t, a, comma_t, comma_a, def, type1, \ -+ arg1, type2, arg2, type3, arg3, type4, \ -+ arg4, type5, arg5, type6, arg6, type7, \ -+ arg7, type8, arg8) \ -+ t(type1) comma_t a(arg1) comma_a t(type2) comma_t a(arg2) comma_a \ -+ t(type3) comma_t a(arg3) comma_a t(type4) comma_t a(arg4) comma_a \ -+ t(type5) comma_t a(arg5) comma_a t(type6) comma_t a(arg6) comma_a \ -+ t(type7) comma_t a(arg7) comma_a t(type8) comma_t a(arg8) -+#define __DTRACE_DOUBLE_APPLY_18(t, a, comma_t, comma_a, def, type1, arg1, type2, arg2, type3, arg3, type4, arg4, type5, arg5, type6, arg6, type7, arg7, type8, arg8, type9, arg9) \ -+ t(type1) comma_t a(arg1) comma_a t(type2) comma_t a(arg2) comma_a \ -+ t(type3) comma_t a(arg3) comma_a t(type4) comma_t a(arg4) comma_a \ -+ t(type5) comma_t a(arg5) comma_a t(type6) comma_t a(arg6) comma_a \ -+ t(type7) comma_t a(arg7) comma_a t(type8) comma_t a(arg8) comma_a \ -+ t(type9) comma_t a(arg9) -+#define __DTRACE_DOUBLE_APPLY_20(t, a, comma_t, comma_a, def, type1, arg1, type2, arg2, type3, arg3, type4, arg4, type5, arg5, type6, arg6, type7, arg7, type8, arg8, type9, arg9, typea, arga) \ -+ t(type1) comma_t a(arg1) comma_a t(type2) comma_t a(arg2) comma_a \ -+ t(type3) comma_t a(arg3) comma_a t(type4) comma_t a(arg4) comma_a \ -+ t(type5) comma_t a(arg5) comma_a t(type6) comma_t a(arg6) comma_a \ -+ t(type7) comma_t a(arg7) comma_a t(type8) comma_t a(arg8) comma_a \ -+ t(type9) comma_t a(arg9) comma_a t(typea) comma_t a(arga) -+#define __DTRACE_DOUBLE_APPLY_22(t, a, comma_t, comma_a, def, type1, arg1, type2, arg2, type3, arg3, type4, arg4, type5, arg5, type6, arg6, type7, arg7, type8, arg8, type9, arg9, typea, arga, typeb, argb) \ -+ t(type1) comma_t a(arg1) comma_a t(type2) comma_t a(arg2) comma_a \ -+ t(type3) comma_t a(arg3) comma_a t(type4) comma_t a(arg4) comma_a \ -+ t(type5) comma_t a(arg5) comma_a t(type6) comma_t a(arg6) comma_a \ -+ t(type7) comma_t a(arg7) comma_a t(type8) comma_t a(arg8) comma_a \ -+ t(type9) comma_t a(arg9) comma_a t(typea) comma_t a(arga) comma_a \ -+ t(typeb) comma_t a(argb) -+#define __DTRACE_DOUBLE_APPLY_24(t, a, comma_t, comma_a, def, type1, arg1, type2, arg2, type3, arg3, type4, arg4, type5, arg5, type6, arg6, type7, arg7, type8, arg8, type9, arg9, typea, arga, typeb, argb, typec, argc) \ -+ t(type1) comma_t a(arg1) comma_a t(type2) comma_t a(arg2) comma_a \ -+ t(type3) comma_t a(arg3) comma_a t(type4) comma_t a(arg4) comma_a \ -+ t(type5) comma_t a(arg5) comma_a t(type6) comma_t a(arg6) comma_a \ -+ t(type7) comma_t a(arg7) comma_a t(type8) comma_t a(arg8) comma_a \ -+ t(type9) comma_t a(arg9) comma_a t(typea) comma_t a(arga) comma_a \ -+ t(typeb) comma_t a(argb) comma_a t(typec) comma_t a(argc) -+#define __DTRACE_DOUBLE_APPLY_26(t, a, comma_t, comma_a, def, type1, arg1, type2, arg2, type3, arg3, type4, arg4, type5, arg5, type6, arg6, type7, arg7, type8, arg8, type9, arg9, typea, arga, typeb, argb, typec, argc, typed, argd) \ -+ t(type1) comma_t a(arg1) comma_a t(type2) comma_t a(arg2) comma_a \ -+ t(type3) comma_t a(arg3) comma_a t(type4) comma_t a(arg4) comma_a \ -+ t(type5) comma_t a(arg5) comma_a t(type6) comma_t a(arg6) comma_a \ -+ t(type7) comma_t a(arg7) comma_a t(type8) comma_t a(arg8) comma_a \ -+ t(type9) comma_t a(arg9) comma_a t(typea) comma_t a(arga) comma_a \ -+ t(typeb) comma_t a(argb) comma_a t(typec) comma_t a(argc) comma_a \ -+ t(typed) comma_t a(argd) -+#define __DTRACE_DOUBLE_APPLY_28(t, a, comma_t, comma_a, def, type1, arg1, type2, arg2, type3, arg3, type4, arg4, type5, arg5, type6, arg6, type7, arg7, type8, arg8, type9, arg9, typea, arga, typeb, argb, typec, argc, typed, argd, typee, arge) \ -+ t(type1) comma_t a(arg1) comma_a t(type2) comma_t a(arg2) comma_a \ -+ t(type3) comma_t a(arg3) comma_a t(type4) comma_t a(arg4) comma_a \ -+ t(type5) comma_t a(arg5) comma_a t(type6) comma_t a(arg6) comma_a \ -+ t(type7) comma_t a(arg7) comma_a t(type8) comma_t a(arg8) comma_a \ -+ t(type9) comma_t a(arg9) comma_a t(typea) comma_t a(arga) comma_a \ -+ t(typeb) comma_t a(argb) comma_a t(typec) comma_t a(argc) comma_a \ -+ t(typed) comma_t a(argd) comma_a t(typee) comma_t a(arge) -+#define __DTRACE_DOUBLE_APPLY_30(t, a, comma_t, comma_a, def, type1, arg1, type2, arg2, type3, arg3, type4, arg4, type5, arg5, type6, arg6, type7, arg7, type8, arg8, type9, arg9, typea, arga, typeb, argb, typec, argc, typed, argd, typee, arge, typef, argf) \ -+ t(type1) comma_t a(arg1) comma_a t(type2) comma_t a(arg2) comma_a \ -+ t(type3) comma_t a(arg3) comma_a t(type4) comma_t a(arg4) comma_a \ -+ t(type5) comma_t a(arg5) comma_a t(type6) comma_t a(arg6) comma_a \ -+ t(type7) comma_t a(arg7) comma_a t(type8) comma_t a(arg8) comma_a \ -+ t(type9) comma_t a(arg9) comma_a t(typea) comma_t a(arga) comma_a \ -+ t(typeb) comma_t a(argb) comma_a t(typec) comma_t a(argc) comma_a \ -+ t(typed) comma_t a(argd) comma_a t(typee) comma_t a(arge) comma_a \ -+ t(typef) comma_t a(argf) -+#define __DTRACE_DOUBLE_APPLY_32(t, a, comma_t, comma_a, def, type1, arg1, type2, arg2, type3, arg3, type4, arg4, type5, arg5, type6, arg6, type7, arg7, type8, arg8, type9, arg9, typea, arga, typeb, argb, typec, argc, typed, argd, typee, arge, typef, argf, typeg, argg) \ -+ t(type1) comma_t a(arg1) comma_a t(type2) comma_t a(arg2) comma_a \ -+ t(type3) comma_t a(arg3) comma_a t(type4) comma_t a(arg4) comma_a \ -+ t(type5) comma_t a(arg5) comma_a t(type6) comma_t a(arg6) comma_a \ -+ t(type7) comma_t a(arg7) comma_a t(type8) comma_t a(arg8) comma_a \ -+ t(type9) comma_t a(arg9) comma_a t(typea) comma_t a(arga) comma_a \ -+ t(typeb) comma_t a(argb) comma_a t(typec) comma_t a(argc) comma_a \ -+ t(typed) comma_t a(argd) comma_a t(typee) comma_t a(arge) comma_a \ -+ t(typef) comma_t a(argf) comma_a t(typeg) comma_t a(argg) -+#define __DTRACE_DOUBLE_APPLY_34(t, a, comma_t, comma_a, def, type1, arg1, type2, arg2, type3, arg3, type4, arg4, type5, arg5, type6, arg6, type7, arg7, type8, arg8, type9, arg9, typea, arga, typeb, argb, typec, argc, typed, argd, typee, arge, typef, argf, typeg, argg, typeh, argh) \ -+ t(type1) comma_t a(arg1) comma_a t(type2) comma_t a(arg2) comma_a \ -+ t(type3) comma_t a(arg3) comma_a t(type4) comma_t a(arg4) comma_a \ -+ t(type5) comma_t a(arg5) comma_a t(type6) comma_t a(arg6) comma_a \ -+ t(type7) comma_t a(arg7) comma_a t(type8) comma_t a(arg8) comma_a \ -+ t(type9) comma_t a(arg9) comma_a t(typea) comma_t a(arga) comma_a \ -+ t(typeb) comma_t a(argb) comma_a t(typec) comma_t a(argc) comma_a \ -+ t(typed) comma_t a(argd) comma_a t(typee) comma_t a(arge) comma_a \ -+ t(typef) comma_t a(argf) comma_a t(typeg) comma_t a(argg) comma_a \ -+ t(typeh) comma_t a(argh) -+#define __DTRACE_DOUBLE_APPLY_36(t, a, comma_t, comma_a, def, type1, arg1, type2, arg2, type3, arg3, type4, arg4, type5, arg5, type6, arg6, type7, arg7, type8, arg8, type9, arg9, typea, arga, typeb, argb, typec, argc, typed, argd, typee, arge, typef, argf, typeg, argg, typeh, argh, typei, argi) \ -+ t(type1) comma_t a(arg1) comma_a t(type2) comma_t a(arg2) comma_a \ -+ t(type3) comma_t a(arg3) comma_a t(type4) comma_t a(arg4) comma_a \ -+ t(type5) comma_t a(arg5) comma_a t(type6) comma_t a(arg6) comma_a \ -+ t(type7) comma_t a(arg7) comma_a t(type8) comma_t a(arg8) comma_a \ -+ t(type9) comma_t a(arg9) comma_a t(typea) comma_t a(arga) comma_a \ -+ t(typeb) comma_t a(argb) comma_a t(typec) comma_t a(argc) comma_a \ -+ t(typed) comma_t a(argd) comma_a t(typee) comma_t a(arge) comma_a \ -+ t(typef) comma_t a(argf) comma_a t(typeg) comma_t a(argg) comma_a \ -+ t(typeh) comma_t a(argh) comma_a t(typei) comma_t a(argi) -+ -+#define __DTRACE_DOUBLE_APPLY_ERROR Error: type specified without arg. -+#define __DTRACE_DOUBLE_APPLY_1 __DTRACE_DOUBLE_APPLY_ERROR -+#define __DTRACE_DOUBLE_APPLY_3 __DTRACE_DOUBLE_APPLY_ERROR -+#define __DTRACE_DOUBLE_APPLY_5 __DTRACE_DOUBLE_APPLY_ERROR -+#define __DTRACE_DOUBLE_APPLY_7 __DTRACE_DOUBLE_APPLY_ERROR -+#define __DTRACE_DOUBLE_APPLY_9 __DTRACE_DOUBLE_APPLY_ERROR -+#define __DTRACE_DOUBLE_APPLY_11 __DTRACE_DOUBLE_APPLY_ERROR -+#define __DTRACE_DOUBLE_APPLY_13 __DTRACE_DOUBLE_APPLY_ERROR -+#define __DTRACE_DOUBLE_APPLY_15 __DTRACE_DOUBLE_APPLY_ERROR -+#define __DTRACE_DOUBLE_APPLY_17 __DTRACE_DOUBLE_APPLY_ERROR -+#define __DTRACE_DOUBLE_APPLY_19 __DTRACE_DOUBLE_APPLY_ERROR -+#define __DTRACE_DOUBLE_APPLY_21 __DTRACE_DOUBLE_APPLY_ERROR -+#define __DTRACE_DOUBLE_APPLY_23 __DTRACE_DOUBLE_APPLY_ERROR -+#define __DTRACE_DOUBLE_APPLY_25 __DTRACE_DOUBLE_APPLY_ERROR -+#define __DTRACE_DOUBLE_APPLY_27 __DTRACE_DOUBLE_APPLY_ERROR -+#define __DTRACE_DOUBLE_APPLY_29 __DTRACE_DOUBLE_APPLY_ERROR -+#define __DTRACE_DOUBLE_APPLY_31 __DTRACE_DOUBLE_APPLY_ERROR -+#define __DTRACE_DOUBLE_APPLY_33 __DTRACE_DOUBLE_APPLY_ERROR -+#define __DTRACE_DOUBLE_APPLY_35 __DTRACE_DOUBLE_APPLY_ERROR -+#define __DTRACE_DOUBLE_APPLY_37 __DTRACE_DOUBLE_APPLY_ERROR -+ -+#define __DTRACE_UINTPTR_EACH(x) uintptr_t -+ -+#define __DTRACE_UINTCAST_EACH(x) (uintptr_t)(x) -+#define __DTRACE_TYPE_EACH(x) ".ascii \"" __stringify(x) ",\"\n" -+ -+/* -+ * Convert everything to the appropriate integral type, unless too large to fit -+ * into any of them, in which case its address is taken instead. -+ */ -+ -+/* -+ * This will call a macro on each argument passed in, with optional default for -+ * zero args. -+ */ -+#define __DTRACE_APPLY(macro, ...) __DTRACE_CAT(__DTRACE_APPLY_, __DTRACE_NARGS(__VA_ARGS__))(macro, , ## __VA_ARGS__) -+#define __DTRACE_APPLY_DEFAULT(macro, def, ...) __DTRACE_CAT(__DTRACE_APPLY_, __DTRACE_NARGS(__VA_ARGS__))(macro, def, ## __VA_ARGS__) -+#define __DTRACE_APPLY_0(m, def) def -+#define __DTRACE_APPLY_1(m, def, x1) m(x1) -+#define __DTRACE_APPLY_2(m, def, x1, x2) m(x1), m(x2) -+#define __DTRACE_APPLY_3(m, def, x1, x2, x3) m(x1), m(x2), m(x3) -+#define __DTRACE_APPLY_4(m, def, x1, x2, x3, x4) m(x1), m(x2), m(x3), m(x4) -+#define __DTRACE_APPLY_5(m, def, x1, x2, x3, x4, x5) \ -+ m(x1), m(x2), m(x3), m(x4), m(x5) -+#define __DTRACE_APPLY_6(m, def, x1, x2, x3, x4, x5, x6) \ -+ m(x1), m(x2), m(x3), m(x4), m(x5), m(x6) -+#define __DTRACE_APPLY_7(m, def, x1, x2, x3, x4, x5, x6, x7) \ -+ m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7) -+#define __DTRACE_APPLY_8(m, def, x1, x2, x3, x4, x5, x6, x7, x8) \ -+ m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7), m(x8) -+#define __DTRACE_APPLY_9(m, def, x1, x2, x3, x4, x5, x6, x7, x8, x9) \ -+ m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7), m(x8), m(x9) -+#define __DTRACE_APPLY_10(m, def, x1, x2, x3, x4, x5, x6, x7, x8, x9, xa) \ -+ m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7), m(x8), m(x9), m(xa) -+#define __DTRACE_APPLY_11(m, def, x1, x2, x3, x4, x5, x6, x7, x8, x9, xa, xb) \ -+ m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7), m(x8), m(x9), m(xa), \ -+ m(xb) -+#define __DTRACE_APPLY_12(m, def, x1, x2, x3, x4, x5, x6, x7, x8, x9, xa, xb, xc) \ -+ m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7), m(x8), m(x9), m(xa), \ -+ m(xb), m(xc) -+#define __DTRACE_APPLY_13(m, def, x1, x2, x3, x4, x5, x6, x7, x8, x9, xa, xb, xc, xd) \ -+ m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7), m(x8), m(x9), m(xa), \ -+ m(xb), m(xc), m(xd) -+#define __DTRACE_APPLY_14(m, def, x1, x2, x3, x4, x5, x6, x7, x8, x9, xa, xb, xc, xd, xe) \ -+ m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7), m(x8), m(x9), m(xa), \ -+ m(xb), m(xc), m(xd), m(xe) -+#define __DTRACE_APPLY_15(m, def, x1, x2, x3, x4, x5, x6, x7, x8, x9, xa, xb, xc, xd, xe, xf) \ -+ m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7), m(x8), m(x9), m(xa), \ -+ m(xb), m(xc), m(xd), m(xe), m(xf) -+#define __DTRACE_APPLY_16(m, def, x1, x2, x3, x4, x5, x6, x7, x8, x9, xa, xb, xc, xd, xe, xf, xg) \ -+ m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7), m(x8), m(x9), m(xa), \ -+ m(xb), m(xc), m(xd), m(xe), m(xf), m(xg) -+#define __DTRACE_APPLY_17(m, def, x1, x2, x3, x4, x5, x6, x7, x8, x9, xa, xb, xc, xd, xe, xf, xg, xh) \ -+ m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7), m(x8), m(x9), m(xa), \ -+ m(xb), m(xc), m(xd), m(xe), m(xf), m(xg), m(xh) -+#define __DTRACE_APPLY_18(m, def, x1, x2, x3, x4, x5, x6, x7, x8, x9, xa, xb, xc, xd, xe, xf, xg, xh, xi) \ -+ m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7), m(x8), m(x9), m(xa), \ -+ m(xb), m(xc), m(xd), m(xe), m(xf), m(xg), m(xh), m(xi) -+ -+#endif /* _LINUX_SDT_INTERNAL_H */ -diff --git a/include/linux/tracepoint.h b/include/linux/tracepoint.h -index 0f21617f1a66..e847bbafd123 100644 ---- a/include/linux/tracepoint.h -+++ b/include/linux/tracepoint.h -@@ -20,6 +20,7 @@ - #include <linux/rcupdate.h> - #include <linux/tracepoint-defs.h> - #include <linux/static_call.h> -+#include <linux/sdt.h> - - struct module; - struct tracepoint; -@@ -237,6 +238,8 @@ static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p) - extern struct tracepoint __tracepoint_##name; \ - static inline void trace_##name(proto) \ - { \ -+ DTRACE_PROBE_TRACEPOINT(name, args); \ -+ DTRACE_PROTO_TRACEPOINT(name, proto); \ - if (static_key_false(&__tracepoint_##name.key)) \ - __DO_TRACE(name, \ - TP_PROTO(data_proto), \ -@@ -332,7 +335,10 @@ static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p) - #else /* !TRACEPOINTS_ENABLED */ - #define __DECLARE_TRACE(name, proto, args, cond, data_proto, data_args) \ - static inline void trace_##name(proto) \ -- { } \ -+ { \ -+ DTRACE_PROBE_TRACEPOINT(name, args); \ -+ DTRACE_PROTO_TRACEPOINT(name, proto); \ -+ } \ - static inline void trace_##name##_rcuidle(proto) \ - { } \ - static inline int \ -diff --git a/kernel/dtrace/Kconfig b/kernel/dtrace/Kconfig -index d04ca0ab7ac9..c1ec55d8750e 100644 ---- a/kernel/dtrace/Kconfig -+++ b/kernel/dtrace/Kconfig -@@ -23,6 +23,22 @@ config DT_CORE - - if DT_CORE - -+config DT_SDT -+ tristate "Statically Defined Tracing" -+ default m -+ select KALLSYMS -+ help -+ Statically defined tracepoints in the kernel. -+ -+config DT_SDT_PERF -+ bool "DTrace perf-events Probes" -+ default y -+ depends on DT_SDT -+ select TRACEPOINTS -+ help -+ Provides the perf provider, containing a DTrace probe for each -+ perf-events tracepoint in the system. -+ - config DT_SYSTRACE - tristate "System Call Tracing" - default m -diff --git a/kernel/dtrace/Makefile b/kernel/dtrace/Makefile -index 68fc3861e5d1..06329cbe52cb 100644 ---- a/kernel/dtrace/Makefile -+++ b/kernel/dtrace/Makefile -@@ -4,10 +4,11 @@ - - DT_CORE_ARCH_OBJS = $(addprefix ../../arch/$(SRCARCH)/kernel/, \ - dtrace_syscall.o dtrace_syscall_stubs.o \ -- dtrace_util.o) -+ dtrace_sdt.o dtrace_util.o) - - ifdef CONFIG_DT_CORE - obj-y += cyclic.o dtrace_os.o dtrace_cpu.o \ -+ dtrace_sdt_core.o \ - dtrace_task.o dtrace_psinfo.o \ - $(DT_CORE_ARCH_OBJS) - endif -diff --git a/kernel/dtrace/dtrace_os.c b/kernel/dtrace/dtrace_os.c -index d023f3913323..931cfd0d0fbf 100644 ---- a/kernel/dtrace/dtrace_os.c -+++ b/kernel/dtrace/dtrace_os.c -@@ -19,6 +19,7 @@ - #include <linux/binfmts.h> - #include <linux/dtrace_cpu.h> - #include <linux/dtrace_os.h> -+#include <linux/dtrace_sdt.h> - #include <linux/fs.h> - #include <linux/hardirq.h> - #include <linux/interrupt.h> -@@ -66,6 +67,46 @@ void __init dtrace_os_init(void) - if (dtrace_pdata_cachep == NULL) - pr_debug("Can't allocate kmem cache for pdata\n"); - -+ /* -+ * A little bit of magic... -+ * We create a dummy module to represent the core Linux kernel. The -+ * only data we're interested in is the name, the SDT probe points data -+ * (to be filled in by dtrace_sdt_register()), and the probe data. -+ * DTrace uses an architecture-specific structure (hidden from us here) -+ * to hold some data. -+ */ -+ dtrace_kmod = kmalloc(sizeof(struct module), GFP_KERNEL | __GFP_ZERO); -+ if (dtrace_kmod == NULL) { -+ pr_warn("%s: cannot allocate kernel pseudo-module\n", -+ __func__); -+ return; -+ } -+ -+ strlcpy(dtrace_kmod->name, "vmlinux", MODULE_NAME_LEN); -+ -+ /* -+ * Some sizing info is required for kernel module. We are going to use -+ * modules VA range for trampoline anyway so lets pretend a kernel has -+ * no init section and VA range (0, MODULES_VADDR) is occupied by -+ * kernel itself -+ */ -+#ifdef CONFIG_X86_64 -+ dtrace_kmod->core_layout.base = (void *)__START_KERNEL_map; -+ dtrace_kmod->core_layout.size = KERNEL_IMAGE_SIZE; -+#elif defined(CONFIG_SPARC64) -+ /* Hardcoded see pgtable_64.h */ -+ dtrace_kmod->core_layout.base = (void *)0x4000000; -+ dtrace_kmod->core_layout.size = 0x2000000; -+#endif -+ -+ dtrace_kmod->state = MODULE_STATE_LIVE; -+ atomic_inc(&dtrace_kmod->refcnt); -+ -+ dtrace_mod_pdata_alloc(dtrace_kmod); -+ -+ INIT_LIST_HEAD(&dtrace_kmod->source_list); -+ INIT_LIST_HEAD(&dtrace_kmod->target_list); -+ - /* - * We need to set up a psinfo structure for PID 0 (swapper). - */ -@@ -73,7 +114,49 @@ void __init dtrace_os_init(void) - dtrace_psinfo_os_init(); - dtrace_task_init(&init_task); - dtrace_psinfo_alloc(&init_task); -+ -+ dtrace_sdt_init(); -+ dtrace_sdt_register(dtrace_kmod); -+} -+ -+#define MIN(a, b) (((a) < (b)) ? (a) : (b)) -+#define MAX(a, b) (((a) > (b)) ? (a) : (b)) -+#define TRAMP_RANGE 0x80000000 -+ -+void *dtrace_alloc_text(struct module *mp, unsigned long size) -+{ -+ unsigned long mp_start, mp_end; -+ unsigned long va_start, va_end; -+ void *trampoline; -+ -+ /* module range */ -+ mp_start = (unsigned long) mp->core_layout.base; -+ mp_end = mp_start + mp->core_layout.size; -+ -+ if (mp->init_layout.size) { -+ mp_start = MIN(mp_start, (unsigned long)mp->init_layout.base); -+ mp_end = MAX(mp_end, (unsigned long)mp->init_layout.base + -+ mp->init_layout.size); -+ } -+ -+ /* get trampoline range */ -+ va_end = MIN(mp_start + TRAMP_RANGE, MODULES_END); -+ va_start = (mp_end < TRAMP_RANGE) ? 0 : mp_end - TRAMP_RANGE; -+ va_start = MAX(va_start, MODULES_VADDR); -+ -+ trampoline = __vmalloc_node_range(size, 1, va_start, va_end, -+ GFP_KERNEL, PAGE_KERNEL, 0, NUMA_NO_NODE, -+ __builtin_return_address(0)); -+ -+ return trampoline; -+} -+EXPORT_SYMBOL(dtrace_alloc_text); -+ -+void dtrace_free_text(void *ptr) -+{ -+ return vfree(ptr); - } -+EXPORT_SYMBOL(dtrace_free_text); - - /* - * MODULE SUPPORT FUNCTIONS -diff --git a/kernel/dtrace/dtrace_sdt_core.c b/kernel/dtrace/dtrace_sdt_core.c -new file mode 100644 -index 000000000000..90b86726f195 ---- /dev/null -+++ b/kernel/dtrace/dtrace_sdt_core.c -@@ -0,0 +1,364 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_sdt_core.c -+ * DESCRIPTION: DTrace - SDT probes -+ * -+ * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/memory.h> -+#include <linux/module.h> -+#include <linux/dtrace_os.h> -+#include <linux/dtrace_sdt.h> -+#include <linux/jhash.h> -+#include <linux/sdt.h> -+#include <linux/slab.h> -+#include <linux/string.h> -+#include <linux/vmalloc.h> -+#include <asm-generic/bitsperlong.h> -+#include <asm-generic/sections.h> -+ -+const char *sdt_prefix = "__dtrace_probe_"; -+int dtrace_nosdt; -+ -+/* -+ * Compiled-in SDT probe data. -+ */ -+extern const unsigned long dtrace_sdt_probes[]; -+extern const char dtrace_sdt_strings[]; -+extern const unsigned long dtrace_sdt_nprobes; -+ -+/* -+ * Markers of core-kernel sdt_args and sdt_names sections. -+ */ -+extern const char __start_dtrace_sdt_args[]; -+extern const char __stop_dtrace_sdt_args[]; -+extern const char __start_dtrace_sdt_names[]; -+extern const char __stop_dtrace_sdt_names[]; -+ -+static int sdt_probe_set(struct sdt_probedesc *sdp, const char *name, -+ const char *func, uintptr_t addr, asm_instr_t **paddr, -+ struct sdt_probedesc *prv) -+{ -+ sdp->sdpd_name = kstrdup(name, GFP_KERNEL); -+ if (sdp->sdpd_name == NULL) { -+ kfree(sdp); -+ return 1; -+ } -+ -+ sdp->sdpd_func = kstrdup(func, GFP_KERNEL); -+ if (sdp->sdpd_func == NULL) { -+ kfree(sdp->sdpd_name); -+ kfree(sdp); -+ return 1; -+ } -+ -+ sdp->sdpd_args = NULL; -+ sdp->sdpd_offset = addr; -+ sdp->sdpd_next = NULL; -+ -+ *paddr = (asm_instr_t *)addr; -+ -+ if (prv && strcmp(prv->sdpd_name, sdp->sdpd_name) == 0 -+ && strcmp(prv->sdpd_func, sdp->sdpd_func) == 0) -+ prv->sdpd_next = sdp; -+ -+ return 0; -+} -+ -+/* -+ * Transfer the SDT args section into the sdpd_args field left NULL above. -+ * -+ * The memory pointed to by args_start must have a lifetime at least as long as -+ * that pointed to by sdpd. -+ */ -+void dtrace_sdt_stash_args(const char *module_name, -+ struct sdt_probedesc *sdpd, size_t nprobes, -+ const char *names_start, size_t names_len, -+ const char *args_start, size_t args_len) -+{ -+ struct probe_name_hashent_t { -+ const char *pnhe_name; -+ const char *pnhe_args; -+ } *args_by_name; -+ int i; -+ const char *namep, *argp; -+ size_t hashsize; -+ -+ /* -+ * We need to find the probes (and there may be many) in the sdpd -+ * corresponding to the probe with that name in the argtype section. -+ * -+ * Build a hashtable mapping from probe name -> args string, ignoring -+ * duplicate probe names except to check (in debugging mode) that they -+ * have the same args string as the first. Then cycle over the sdpd -+ * looking up each probe in turn and pointing to the same place. -+ * -+ * We don't know how many entries there are in the table, but we do know -+ * there cannot be more than nprobes (and are probably less). -+ */ -+ -+ hashsize = nprobes * 4; /* arbitrary expansion factor */ -+ args_by_name = vzalloc(hashsize * sizeof(struct probe_name_hashent_t)); -+ if (args_by_name == NULL) { -+ pr_warn("%s: cannot allocate hash for sdt args population\n", -+ __func__); -+ return; -+ } -+ -+ namep = names_start; -+ argp = args_start; -+ while ((namep < names_start + names_len) && -+ (argp < args_start + args_len)) { -+ -+ size_t l = strlen(namep); -+ u32 h = jhash(namep, l, 0) % hashsize; -+ -+ while (args_by_name[h].pnhe_name != NULL && -+ strcmp(args_by_name[h].pnhe_name, namep) != 0) { -+ h++; -+ h %= hashsize; -+ } -+ -+ if (args_by_name[h].pnhe_name == NULL) { -+ args_by_name[h].pnhe_name = namep; -+ args_by_name[h].pnhe_args = argp; -+ } -+#if defined(CONFIG_DT_DEBUG) -+ else if (strcmp(args_by_name[h].pnhe_name, namep) != 0) -+ pr_warn("%s: multiple distinct arg strings for probe " -+ "%s found: %s versus %s", -+ module_name, namep, -+ args_by_name[h].pnhe_args, -+ argp); -+#endif -+ namep += l + 1; -+ argp += strlen(argp) + 1; -+ } -+ -+#if defined(CONFIG_DT_DEBUG) -+ if ((namep < names_start + names_len) || (argp < args_start + args_len)) -+ pr_warn("%s: Not all SDT names or args consumed: %zi " -+ "bytes of names and %zi of args left over. " -+ "Some arg types will be mis-assigned.\n", module_name, -+ namep - (names_start + names_len), -+ argp - (args_start + args_len)); -+#endif -+ -+ for (i = 0; i < nprobes; i++) { -+ size_t l = strlen(sdpd[i].sdpd_name); -+ u32 h = jhash(sdpd[i].sdpd_name, l, 0) % hashsize; -+ -+ /* -+ * Is-enabled probes have no arg string. -+ */ -+ if (sdpd[i].sdpd_name[0] == '?') -+ continue; -+ -+ while (args_by_name[h].pnhe_name != NULL && -+ strcmp(sdpd[i].sdpd_name, -+ args_by_name[h].pnhe_name) != 0) { -+ h++; -+ h %= hashsize; -+ } -+ -+ if (args_by_name[h].pnhe_name == NULL) { -+ /* -+ * No arg string. Peculiar: report in debugging mode. -+ */ -+#if defined(CONFIG_DT_DEBUG) -+ pr_warn("%s: probe %s has no arg string.\n", -+ module_name, sdpd[i].sdpd_name); -+#endif -+ continue; -+ } -+ -+ sdpd[i].sdpd_args = args_by_name[h].pnhe_args; -+ } -+ vfree(args_by_name); -+} -+ -+/* -+ * Register the SDT probes for the core kernel, i.e. SDT probes that reside in -+ * vmlinux. For SDT probes in kernel modules, we use dtrace_mod_notifier(). -+ */ -+void __init dtrace_sdt_register(struct module *mp) -+{ -+ int i, cnt; -+ struct sdt_probedesc *sdps; -+ asm_instr_t **addrs; -+ int *is_enabled; -+ void *args; -+ size_t args_len; -+ -+ if (mp == NULL) { -+ pr_warn("%s: no module provided - nothing registered\n", -+ __func__); -+ return; -+ } -+ -+ /* -+ * Just in case we run into failures further on... -+ */ -+ mp->sdt_probes = NULL; -+ mp->sdt_probec = 0; -+ -+ if (dtrace_sdt_nprobes == 0 || dtrace_nosdt) -+ return; -+ -+ /* -+ * Allocate the array of SDT probe descriptions to be registered in the -+ * vmlinux pseudo-module. -+ */ -+ sdps = (struct sdt_probedesc *)vmalloc(dtrace_sdt_nprobes * -+ sizeof(struct sdt_probedesc)); -+ if (sdps == NULL) { -+ pr_warn("%s: cannot allocate SDT probe array\n", __func__); -+ return; -+ } -+ -+ /* -+ * Create a list of addresses (SDT probe locations) that need to be -+ * patched with a NOP instruction (or instruction sequence), and another -+ * array indicating whether each probe needs patching with an -+ * arch-dependent false return instead. -+ */ -+ addrs = (asm_instr_t **)vmalloc(dtrace_sdt_nprobes * -+ sizeof(asm_instr_t *)); -+ is_enabled = (int *)vmalloc(dtrace_sdt_nprobes * sizeof(int)); -+ if ((addrs == NULL) || (is_enabled == NULL)) { -+ pr_warn("%s: cannot allocate SDT probe address/is-enabled " -+ "lists\n", __func__); -+ vfree(sdps); -+ vfree(addrs); -+ vfree(is_enabled); -+ return; -+ } -+ -+ for (i = cnt = 0; i < dtrace_sdt_nprobes; i++) { -+ uintptr_t addr, poff, foff; -+ const char *fname = &dtrace_sdt_strings[foff]; -+ const char *pname; -+ -+ addr = dtrace_sdt_probes[i * 3]; /* address */ -+ poff = dtrace_sdt_probes[i * 3 + 1]; /* probe name offset */ -+ foff = dtrace_sdt_probes[i * 3 + 2]; /* func name offset */ -+ pname = &dtrace_sdt_strings[poff]; -+ fname = &dtrace_sdt_strings[foff]; -+ -+ is_enabled[cnt] = (pname[0] == '?'); -+ -+ if (sdt_probe_set(&sdps[cnt], pname, fname, addr, &addrs[cnt], -+ cnt > 0 ? &sdps[cnt - 1] : NULL)) -+ pr_warn("%s: failed to add SDT probe %s for %s\n", -+ __func__, pname, fname); -+ else -+ cnt++; -+ } -+ -+ mp->sdt_probes = sdps; -+ mp->sdt_probec = cnt; -+ -+ dtrace_sdt_nop_multi(addrs, is_enabled, cnt); -+ -+ /* -+ * Allocate space for the array of arg types, and copy it in from the -+ * (discardable) kernel section. We will need to keep it. (The -+ * identically-ordered array of probe names is not needed after -+ * initialization.) -+ */ -+ args_len = __stop_dtrace_sdt_args - __start_dtrace_sdt_args; -+ args = vmalloc(args_len); -+ if (args == NULL) { -+ pr_warn("%s: cannot allocate table of SDT arg types\n", -+ __func__); -+ goto end; -+ } -+ -+ memcpy(args, __start_dtrace_sdt_args, args_len); -+ -+ dtrace_sdt_stash_args("vmlinux", sdps, cnt, -+ __start_dtrace_sdt_names, -+ (__stop_dtrace_sdt_names - __start_dtrace_sdt_names), -+ args, args_len); -+ -+end: -+ vfree(addrs); -+ vfree(is_enabled); -+} -+ -+static int __init nosdt(char *str) -+{ -+ dtrace_nosdt = 1; -+ -+ return 0; -+} -+ -+early_param("nosdt", nosdt); -+ -+void dtrace_sdt_register_module(struct module *mp, -+ void *sdt_names_addr, size_t sdt_names_len, -+ void *sdt_args_addr, size_t sdt_args_len) -+{ -+ int i, cnt; -+ struct sdt_probedesc *sdp; -+ asm_instr_t **addrs; -+ int *is_enabled; -+ -+ if (mp->sdt_probec == 0 || mp->sdt_probes == NULL) -+ return; -+ -+ /* -+ * Create a list of addresses (SDT probe locations) that need to be -+ * patched with a NOP instruction (or instruction sequence). -+ */ -+ addrs = (asm_instr_t **)vmalloc(mp->sdt_probec * -+ sizeof(asm_instr_t *)); -+ is_enabled = (int *)vmalloc(mp->sdt_probec * sizeof(int)); -+ if ((addrs == NULL) || (is_enabled == NULL)) { -+ pr_warn("%s: cannot allocate SDT probe address list (%s)\n", -+ __func__, mp->name); -+ vfree(addrs); -+ vfree(is_enabled); -+ return; -+ } -+ -+ for (i = cnt = 0, sdp = mp->sdt_probes; i < mp->sdt_probec; -+ i++, sdp++) { -+ addrs[cnt] = (asm_instr_t *)sdp->sdpd_offset; -+ is_enabled[cnt++] = (sdp->sdpd_name[0] == '?'); -+ } -+ -+ dtrace_sdt_nop_multi(addrs, is_enabled, cnt); -+ -+ dtrace_sdt_stash_args(mp->name, mp->sdt_probes, mp->sdt_probec, -+ sdt_names_addr, sdt_names_len, -+ sdt_args_addr, sdt_args_len); -+ -+ vfree(addrs); -+ vfree(is_enabled); -+} -+ -+void __init dtrace_sdt_init(void) -+{ -+ dtrace_sdt_init_arch(); -+} -+ -+#if IS_ENABLED(CONFIG_DT_DT_PERF) -+void dtrace_sdt_perf(void) -+{ -+ DTRACE_PROBE(measure); -+} -+EXPORT_SYMBOL(dtrace_sdt_perf); -+#endif -diff --git a/kernel/module.c b/kernel/module.c -index f4269dabc638..2f214881ae30 100644 ---- a/kernel/module.c -+++ b/kernel/module.c -@@ -40,6 +40,7 @@ - #include <linux/string.h> - #include <linux/mutex.h> - #include <linux/rculist.h> -+#include <linux/sdt.h> - #include <linux/uaccess.h> - #include <asm/cacheflush.h> - #include <linux/set_memory.h> -@@ -47,6 +48,7 @@ - #include <linux/license.h> - #include <asm/sections.h> - #include <linux/dtrace_os.h> -+#include <linux/dtrace_sdt.h> - #include <linux/tracepoint.h> - #include <linux/ftrace.h> - #include <linux/livepatch.h> -@@ -3777,6 +3779,18 @@ static int complete_formation(struct module *mod, struct load_info *info) - { - int err; - -+#ifdef CONFIG_DTRACE -+ void *sdt_args, *sdt_names; -+ unsigned int sdt_args_len, sdt_names_len; -+ -+ sdt_names = section_objs(info, "_dtrace_sdt_names", 1, -+ &sdt_names_len); -+ sdt_args = section_objs(info, "_dtrace_sdt_args", 1, -+ &sdt_args_len); -+ dtrace_sdt_register_module(mod, sdt_names, sdt_names_len, -+ sdt_args, sdt_args_len); -+#endif -+ - mutex_lock(&module_mutex); - - /* Find duplicate symbols (must be called under lock). */ -diff --git a/scripts/.gitignore b/scripts/.gitignore -index a6c11316c969..8458568004eb 100644 ---- a/scripts/.gitignore -+++ b/scripts/.gitignore -@@ -9,3 +9,4 @@ extract-cert - sign-file - insert-sys-cert - /module.lds -+kmodsdt -diff --git a/scripts/Makefile b/scripts/Makefile -index efa1ff4dff95..509a73b6f269 100644 ---- a/scripts/Makefile -+++ b/scripts/Makefile -@@ -11,6 +11,7 @@ hostprogs-always-$(CONFIG_ASN1) += asn1_compiler - hostprogs-always-$(CONFIG_MODULE_SIG_FORMAT) += sign-file - hostprogs-always-$(CONFIG_SYSTEM_TRUSTED_KEYRING) += extract-cert - hostprogs-always-$(CONFIG_SYSTEM_EXTRA_CERTIFICATE) += insert-sys-cert -+hostprogs-always-$(CONFIG_DTRACE) += kmodsdt - - kallsyms-objs := kallsyms.o - -@@ -36,6 +37,11 @@ HOSTCFLAGS_sorttable.o += -DUNWINDER_ORC_ENABLED - HOSTLDLIBS_sorttable = -lpthread - endif - -+ifeq ($(CONFIG_DTRACE),y) -+HOSTCFLAGS_kmodsdt.o := -I$(srctree)/include/generated -+HOSTLDLIBS_kmodsdt := -lelf -+endif -+ - # The following programs are only built on demand - hostprogs += unifdef - -diff --git a/scripts/Makefile.modfinal b/scripts/Makefile.modfinal -index 920545d75da9..50c464f248ef 100644 ---- a/scripts/Makefile.modfinal -+++ b/scripts/Makefile.modfinal -@@ -2,7 +2,7 @@ - # =========================================================================== - # Module final link and CTF generation - # =========================================================================== --# 1) compile all <module>.mod.c files -+# 1) compute SDT offsets, generate SDT stubs, and compile all .mod.c files - # 2) for external modules, generate CTF for the module (there is an extra, - # externally-invoked target that does this for the entire kernel but does - # not invoke the rst of the module-building process) -@@ -32,11 +32,52 @@ modname = $(notdir $(@:.mod.o=)) - part-of-module = y - - quiet_cmd_cc_o_c = CC [M] $@ -- cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $< -+ cmd_cc_o_c = $(CC) $(c_flags) -I$(dir $@) -c -o $@ $< -+ -+quiet_cmd_as_o_S = AS $@ -+ cmd_as_o_S = $(CC) $(a_flags) -c -o $@ $< -+ -+ifdef CONFIG_DTRACE -+ -+sdtgen = $(srctree)/scripts/dtrace_sdt.sh -+ -+quiet_cmd_sdtinfo = SDTINF $@ -+ cmd_sdtinfo = $(sdtgen) sdtinfo $@ $< kmod $(@:.c=.h) -+ -+quiet_cmd_sdtstub = SDTSTB $@ -+ cmd_sdtstub = $(sdtgen) sdtstub $@ $< -+ -+# We depend on the .mod.c file to ensure that modpost runs before sdtinfo. -+$(modules:.ko=.sdtinfo.c): %.sdtinfo.c: %.o %.mod.c -+ $(call cmd,sdtinfo) -+ -+# We depend on the sdtinfo file because info generation rewrites the .o, -+# while sdtstubs reads it. -+$(modules:.ko=.sdtstub.S) : %.sdtstub.S: %.o %.sdtinfo.c -+ $(call cmd,sdtstub) -+ -+%.sdtinfo.o : %.sdtinfo.c -+ $(call if_changed_dep,cc_o_c) -+ -+%.mod.o: %.mod.c %.sdtinfo.c FORCE -+ $(call if_changed_dep,cc_o_c) -+ -+$(modules:.ko=.sdtstub.o): %.sdtstub.o: %.sdtstub.S -+ $(call if_changed,as_o_S) -+ -+module-sdt-modular-prereq = %.sdtstub.o -+sdtinfo-prereq = $(modules:.ko=.sdtinfo.c) -+ -+else - - %.mod.o: %.mod.c FORCE - $(call if_changed_dep,cc_o_c) - -+module-sdt-modular-prereq = -+sdtinfo-prereq = -+ -+endif -+ - # Generate CTF for the entire kernel, or for the module alone if this is a - # build of an external module. - -@@ -95,7 +136,7 @@ $(1) $(wordlist 1,1024,$(2)) - $(if $(word 1025,$(2)),$(call xargs,$(1),$(wordlist 1025,$(words $(2)),$(2)))) - endef - --$(ctf-filelist-raw): $(ctf-builtins-prereq) $(ctf-modules) -+$(ctf-filelist-raw): $(ctf-builtins-prereq) $(ctf-modules) | $(sdtinfo-prereq) - @rm -f $(ctf-filelist-raw); - @if [ -n "$(ctf-dir-mk)" ]; then \ - mkdir -p "$(ctf-dir-mk)"; \ -@@ -123,7 +164,8 @@ vmlinux.ctfa: $(ctf-filelist) - else - - # The CTF depends on the output CTF file list, and that depends --# on the .o files for the modules -+# on the .o files for the modules, and on the sdtinfo files, if any -+# (for the same reason that the sdtstub does). - $(ctf-stamp): $(ctf-filelist) - $(call if_changed,ctf) - @shopt -s nullglob; \ -@@ -170,7 +212,7 @@ quiet_cmd_ld_ko_o = LD [M] $@ - $(OBJCOPY) $(module-ctf-flags) $@.tmp $@ && rm -f $@.tmp ; \ - $(if $(ARCH_POSTLINK), $(MAKE) -f $(ARCH_POSTLINK) $@, true) - --$(modules): %.ko: %.o %.mod.o scripts/module.lds $(module-ctfs-modular-prereq) FORCE -+$(modules): %.ko: %.o %.mod.o %.sdtinfo.o scripts/module.lds $(module-sdt-modular-prereq) $(module-ctfs-modular-prereq) FORCE - $(call cmd_touch_ctf) - +$(call if_changed,ld_ko_o) - -diff --git a/scripts/dtrace_sdt.sh b/scripts/dtrace_sdt.sh -new file mode 100755 -index 000000000000..2dd7ea1aebd8 ---- /dev/null -+++ b/scripts/dtrace_sdt.sh -@@ -0,0 +1,588 @@ -+#!/bin/sh -+# SPDX-License-Identifier: GPL-2.0 -+ -+LANG=C -+ -+# -+# Syntax: -+# dtrace_sdt.sh sdtstub <S-file> <o-file>+ -+# This is used to generate DTrace SDT probe stubs based on one -+# or more object file(s). The stubs are written to <S-file>. -+# dtrace_sdt.sh sdtinfo <c-file> <o-file> kmod <h-file> -+# This is used to generate DTrace SDT probe definitions for a -+# kmod .o file. The output is written to <c-file> and <h-file>. -+# dtrace_sdt.sh sdtinfo <S-file> <l-file> -+# This is used to generate DTrace SDT probe definitions for a -+# linked kernel image file <l-file>. The output is written to -+# <S-file>. -+# -+ -+opr="$1" -+shift -+if [ -z "$opr" ]; then -+ echo "ERROR: Missing operation" > /dev/stderr -+ exit 1 -+fi -+ -+tfn="$1" -+shift -+if [ -z "$tfn" ]; then -+ echo "ERROR: Missing target filename" > /dev/stderr -+ exit 1 -+fi -+ -+ofn="$1" -+tok="$2" -+ -+if [ -z "$ofn" ]; then -+ echo "ERROR: Missing object file argument" > /dev/stderr -+ exit 1 -+fi -+ -+if [ "$opr" = "sdtstub" ]; then -+ ${NM} -u $* | grep -E '__dtrace_(probe|isenabled)_' | sort | uniq | \ -+ gawk -v arch=${ARCH} \ -+ '{ -+ printf("\t.globl %s\n\t.type %s,@function\n%s:\n", -+ $2, $2, $2); -+ count++; -+ } -+ -+ END { -+ if (count) { -+ if (arch == "x86" || arch == "x86_64") { -+ print "\txor %eax,%eax"; -+ print "\tretq"; -+ } else if (arch == "sparc" || arch == "sparc64") { -+ print "\tretl"; -+ print "\tnop"; -+ } else if (arch == "arm" || arch == "arm64") { -+ print "\tmov w0, #0x0"; -+ print "\tret"; -+ } -+ } -+ }' > $tfn -+ exit $? -+fi -+ -+if [ "$opr" != "sdtinfo" ]; then -+ echo "ERROR: Invalid operation, should be sdtstub or sdtinfo" > /dev/stderr -+ exit 1 -+fi -+ -+if [ "$tok" = "kmod" ]; then -+ hfile="$3" -+ -+ # Pre-process the object file to handle any local functions that contain -+ # SDT probes. -+ scripts/kmodsdt ${ofn} -+ -+ # Output all function symbols in the symbol table of the object file. -+ # Subsequently, output all relocation records for DTrace SDT probes. The -+ # probes are identified by either a __dtrace_probe_ or __dtrace_isenabled_ -+ # prefix. -+ # -+ # We sort the output primarily based on the section, using the value (or -+ # offset) as secondary sort criterion The overall result is that the -+ # output will be structured as a list of functions, and for any functions -+ # that contain DTrace SDT probes, relocation records will follow the -+ # function entry they are associated with. -+ # -+ # Relocations are reported by objdump per section, with a header line -+ # documenting the specific section being reported: -+ # RELOCATION RECORDS FOR [<section>]: -+ # This is followed by a column header line, and a list of relocations. -+ # The relocations are listed with 3 tokens per line: -+ # <offset> <type> <value> -+ # -+ # Three different types can show up in the output (all with 4 tokens): -+ # <section> <offset> F <value> -+ # Function within a section at a specific offset. -+ # (See STAGE 3a below.) -+ # <section> <offset> G <value> -+ # Global alias for a local function within a section at a specific -+ # offset. A function can only have one alias, and there cannot be -+ # an alias without its respective function. -+ # (See STAGE 3a below.) -+ # <section> <offset> R <value> -+ # Relocation within a section at a specific offset. -+ # (See STAGE 3b below.) -+ # -+ ${OBJDUMP} -tr ${ofn} | \ -+ gawk '/^RELOC/ { -+ sect = substr($4, 2, length($4) - 3); -+ if (sect ~ /^\.(exit|init|meminit)\.text/) -+ sect = 0; -+ -+ next; -+ } -+ -+ sect && /__dtrace_probe_/ { -+ $3 = substr($3, 16); -+ sub(/[\-+].*$/, "", $3); -+ print sect " " $1 " R " $3; -+ next; -+ } -+ -+ sect && /__dtrace_isenabled_/ { -+ $3 = substr($3, 20); -+ sub(/[\-+].*$/, "", $3); -+ print sect " " $1 " R ?" $3; -+ next; -+ } -+ -+ /file format/ { -+ next; -+ } -+ -+ / F / { -+ if ($4 ~ /^\.(exit|init|meminit)\.text/) -+ next; -+ -+ if ($6 == ".hidden") -+ print $4 " " $1 " G " $7; -+ else -+ print $4 " " $1 " F " $6; -+ }' | \ -+ sort -k1,2 | \ -+ gawk -v arch=${ARCH} -v hfile=${hfile} \ -+ 'function subl(v0, v1, v0h, v0l, v1h, v1l, d, tmp) { -+ tmp = $0; -+ if (length(v0) > 8) { -+ d = length(v0); -+ v0h = strtonum("0x"substr(v0, 1, d - 8)); -+ v0l = strtonum("0x"substr(v0, d - 8 + 1)); -+ d = length(v1); -+ v1h = strtonum("0x"substr(v1, 1, d - 8)); -+ v1l = strtonum("0x"substr(v1, d - 8 + 1)); -+ -+ if (v0l >= v1l) { -+ if (v0h >= v1h) { -+ d = sprintf("%08x%08x", v0h - v1h, v0l - v1l); -+ } else { -+ printf "#error Invalid addresses: %s - %s\n", v0, v1 \ -+ >"/dev/stderr"; -+ errc++; -+ } -+ } else { -+ if (v0h > v1h) { -+ v0h--; -+ v0l += 4294967296; -+ d = sprintf("%08x%08x", v0h - v1h, v0l - v1l); -+ } else { -+ printf "#error Invalid addresses: %s - %s\n", v0, v1 \ -+ >"/dev/stderr"; -+ errc++; -+ } -+ } -+ } else { -+ v0 = strtonum("0x"v0); -+ v1 = strtonum("0x"v1); -+ d = sprintf("%016x", v0 - v1); -+ } -+ $0 = tmp; -+ -+ return d; -+ } -+ -+ BEGIN { -+ print "#include <linux/sdt.h>"; -+ -+ probec = 0; -+ } -+ -+ # -+ # Process a symbol table definition for a function in the object -+ # file ($ofn). As we pass through the symbol table, we record the -+ # function name, address, and symbol table index or alias. This -+ # information is needed for any potential DTrace probes that may exist -+ # in the function. They will be listed in relocation records -+ # subsequent to this function definition (and are processed in the -+ # next action block). -+ # -+ NF == 4 && $3 == "F" { -+ fname = $4; -+ sub(/\..*$/, "", fname); -+ alias = $4; -+ faddr = $2; -+ sub(/^0+/, "", faddr); -+ -+ next; -+ } -+ -+ NF == 4 && $3 == "G" { -+ alias = $4; -+ -+ next; -+ } -+ -+ # -+ # Process a relocation record associated with the preceding function. -+ # -+ # For kernel modules: -+ # Convert the section offset into an offset in the function where the -+ # DTrace probe is located, i.e. an offset from the start of the -+ # function. This will be resolved in an absolute address at runtime -+ # when the module is loaded. -+ # -+ NF == 4 && $3 == "R" { -+ sub(/^0+/, "", $2); -+ -+ addr = subl($2, faddr); -+ -+ if (arch == "x86" || arch == "x86_64") -+ addr = subl(addr, 1); -+ -+ protom[alias] = 1; -+ probev[probec] = sprintf(" {\042%s\042, \042%s\042 /* %s */, 0 /* sdt_args string */, (uintptr_t)%s+0x%s },", $4, fname, $1, alias, addr); -+ probec++; -+ -+ next; -+ } -+ -+ END { -+ for (alias in protom) -+ printf "extern void %s(void);\n", alias; -+ print "\nstruct sdt_probedesc\t_sdt_probes[] = {"; -+ for (i = 0; i < probec; i++) -+ print probev[i]; -+ print "};\n"; -+ -+ print "#define _sdt_probec\t" probec > hfile; -+ print "extern struct sdt_probedesc _sdt_probes[];" >> hfile; -+ -+ exit(errc == 0 ? 0 : 1); -+ }' > $tfn -+else -+ # For a linked kernel (with relocation data), the scope of the DTrace SDT -+ # probe discovery can be limited to CODE sections that are not included in -+ # the init or exit code sections. -+ # -+ # First the sections records are parsed to order to determine the base -+ # address for each relevant section. -+ # -+ # Subsequently, all function symbols that are located in the sections we -+ # care about are read from the symbol table of the linked kernel object. -+ # Each symbol is reported in the output stream with its section name, -+ # address, a token identifying it as a function (or alias), and its name. -+ # -+ # Finally, each relocation record from relevant sections that relates to -+ # SDT probes are written to the output stream with its section name, -+ # address, a token # identifying it as a relocation, and its name. Probes -+ # are identified in the relocation records as symbols with either a -+ # __dtrace_probe_ or __dtrace_isenabled_ prefix. -+ # -+ # We sort the output based on the section name and address, ensuring that -+ # the output will be a list of functions, and each function record will be -+ # followed immediately by any DTrace SDT probe records that are used in -+ # that function. -+ # -+ # Three different record types can show up in the output (4 tokens each): -+ # <section> <address> F <name> -+ # Named function at a specific address. -+ # <section> <address> G <name> -+ # Global alias for a local function at a specific offset. A -+ # function can only have one alias, and there cannot be an alias -+ # without its respective function. -+ # <section> <address> R <value> -+ # Relocation within a section at a specific address -+ # -+ ${OBJDUMP} -htr ${ofn} | \ -+ gawk 'function addl(v0, v1, v0h, v0l, v1h, v1l, d, tmp) { -+ tmp = $0; -+ if (length(v0) > 8 || length(v1) > 8) { -+ d = length(v0); -+ v0h = strtonum("0x"substr(v0, 1, d - 8)); -+ v0l = strtonum("0x"substr(v0, d - 8 + 1)); -+ d = length(v1); -+ v1h = strtonum("0x"substr(v1, 1, d - 8)); -+ v1l = strtonum("0x"substr(v1, d - 8 + 1)); -+ -+ v0l += v1l; -+ v0h += v1h; -+ d = sprintf("%x", v0l); -+ if (length(d) > 8) { -+ v0h++; -+ v0l -= 4294967296; -+ } -+ d = sprintf("%x", v0h); -+ if (length(d) <= 8) { -+ d = sprintf("%08x%08x", v0h, v0l); -+ } else { -+ printf "#error Invalid addresses: %s + %s\n", v0, v1 \ -+ >"/dev/stderr"; -+ errc++; -+ } -+ } else { -+ v0 = strtonum("0x"v0); -+ v1 = strtonum("0x"v1); -+ d = sprintf("%016x", v0 + v1); -+ } -+ $0 = tmp; -+ -+ return d; -+ } -+ -+ function subl(v0, v1, v0h, v0l, v1h, v1l, d, tmp) { -+ tmp = $0; -+ if (length(v0) > 8) { -+ d = length(v0); -+ v0h = strtonum("0x"substr(v0, 1, d - 8)); -+ v0l = strtonum("0x"substr(v0, d - 8 + 1)); -+ d = length(v1); -+ v1h = strtonum("0x"substr(v1, 1, d - 8)); -+ v1l = strtonum("0x"substr(v1, d - 8 + 1)); -+ -+ if (v0l >= v1l) { -+ if (v0h >= v1h) { -+ d = sprintf("%08x%08x", v0h - v1h, v0l - v1l); -+ } else { -+ printf "#error Invalid addresses: %s - %s\n", v0, v1 \ -+ >"/dev/stderr"; -+ errc++; -+ } -+ } else { -+ if (v0h > v1h) { -+ v0h--; -+ v0l += 4294967296; -+ d = sprintf("%08x%08x", v0h - v1h, v0l - v1l); -+ } else { -+ printf "#error Invalid addresses: %s - %s\n", v0, v1 \ -+ >"/dev/stderr"; -+ errc++; -+ } -+ } -+ } else { -+ v0 = strtonum("0x"v0); -+ v1 = strtonum("0x"v1); -+ d = sprintf("%016x", v0 - v1); -+ } -+ $0 = tmp; -+ -+ return d; -+ } -+ -+ NF == 7 && $2 !~ /^\.(exit|init|meminit)\.text/ { -+ snam = $2; -+ addr = $4; -+ -+ getline; -+ if (/CODE/) -+ base[snam] = addr; -+ -+ next; -+ } -+ -+ NF == 5 && $2 == "g" && $NF == "_stext" { -+ print ". " $1 " B _stext"; -+ next; -+ } -+ -+ /^RELOC/ { -+ snam = substr($4, 2, length($4) - 3); -+ if (snam in base) -+ in_reloc = 1; -+ else -+ in_reloc = 0; -+ next; -+ } -+ -+ in_reloc && /__dtrace_probe_/ { -+ $3 = substr($3, 16); -+ sub(/[\-+].*$/, "", $3); -+ print snam " " addl(base[snam], $1) " R " $3; -+ next; -+ } -+ -+ in_reloc && /__dtrace_isenabled_/ { -+ $3 = substr($3, 20); -+ sub(/[\-+].*$/, "", $3); -+ print snam " " addl(base[snam], $1) " R ?" $3; -+ next; -+ } -+ -+ / F / { -+ if (!($4 in base)) -+ next; -+ -+ if ($6 == ".hidden") -+ print $4 " " $1 " G " $7; -+ else -+ print $4 " " $1 " F " $6; -+ }' | \ -+ sort -k2 | \ -+ gawk -v arch=${ARCH} \ -+ 'function subl(v0, v1, v0h, v0l, v1h, v1l, d, tmp) { -+ tmp = $0; -+ if (length(v0) > 8) { -+ d = length(v0); -+ v0h = strtonum("0x"substr(v0, 1, d - 8)); -+ v0l = strtonum("0x"substr(v0, d - 8 + 1)); -+ d = length(v1); -+ v1h = strtonum("0x"substr(v1, 1, d - 8)); -+ v1l = strtonum("0x"substr(v1, d - 8 + 1)); -+ -+ if (v0l >= v1l) { -+ if (v0h >= v1h) { -+ d = sprintf("%08x%08x", v0h - v1h, v0l - v1l); -+ } else { -+ printf "#error Invalid addresses: %x vs %x", v0, v1 \ -+ >"/dev/stderr"; -+ errc++; -+ } -+ } else { -+ printf "#error Invalid addresses: %x vs %x", v0, v1 \ -+ >"/dev/stderr"; -+ errc++; -+ } -+ } else { -+ v0 = strtonum("0x"v0); -+ v1 = strtonum("0x"v1); -+ d = sprintf("%016x", v0 - v1); -+ } -+ $0 = tmp; -+ -+ return d; -+ } -+ -+ function map_string(str, off) { -+ if (str in strmap) -+ off = strmap[str]; -+ else { -+ off = strsz; -+ strmap[str] = strsz; -+ strv[strc++] = str; -+ strsz += length(str) + 1; -+ } -+ -+ return off; -+ } -+ -+ BEGIN { -+ print "#include <asm/types.h>"; -+ print "#if BITS_PER_LONG == 64"; -+ print "# define PTR .quad"; -+ if (arch == "aarch64") -+ print "# define ALGN .align 3"; -+ else -+ print "# define ALGN .align 8"; -+ print "#else"; -+ print "# define PTR .long"; -+ if (arch == "aarch64") -+ print "# define ALGN .align 2"; -+ else -+ print "# define ALGN .align 4"; -+ print "#endif"; -+ -+ print "\t.section .rodata, \042a\042"; -+ print ""; -+ -+ print ".globl dtrace_sdt_probes"; -+ print "\tALGN"; -+ print "dtrace_sdt_probes:"; -+ -+ probec = 0; -+ stroff = 0; -+ strc = 0; -+ } -+ -+ -+ # -+ # Record the _stext address so probe locations can be expressed -+ # relative to that address. -+ # -+ NF == 4 && $1 == "." && $4 == "_stext" { -+ stext = $2; -+ next; -+ } -+ -+ # -+ # Process a symbol table definition for a function in the .text -+ # section of the kernel image. We record the function name and -+ # the address, and pre-populate the alias name with the function -+ # name. -+ # -+ # We also compare the address of the current symbol to the last -+ # recorded address, and if they are the same, we do not increment -+ # the function count. -+ # -+ NF == 4 && $3 == "F" { -+ faddr = $2; -+ fname = $4; -+ sub(/\..*$/, "", fname); -+ alias = $4; -+ -+ if ($2 != prev) -+ funcc++; -+ prev = $2; -+ -+ next; -+ } -+ -+ # -+ # When we encounter an alias symbol, we record the name. -+ # -+ NF == 4 && $3 == "G" { -+ alias = $4; -+ -+ next; -+ } -+ -+ # -+ # Process a relocation record associated with the preceding function. -+ # -+ # The address was resolved earlier, so we can simply generate the -+ # numeric information for the SDT probe information record. The -+ # text information (probe name and function name) are stored. This -+ # allows us to weed out duplicates, and it is necessary because the -+ # data blob with all the strings will be written to output later. -+ # -+ NF == 4 && $3 == "R" { -+ sub(/^0+/, "", $2); -+ -+ addr = subl($2, stext); -+ -+ # -+ # On x86, relocations point to the 2nd byte of a call instruction -+ # so we need to adjust the address. -+ # -+ if (arch == "x86" || arch == "x86_64") -+ addr = subl(addr, 1); -+ -+ print "/*"; -+ print " * " $1 " " faddr " F " fname; -+ print " * " $0; -+ print " */"; -+ printf "\tPTR\t_stext + 0x%s\n", addr; -+ printf "\tPTR\t%d\n", map_string($4); -+ printf "\tPTR\t%d\n", map_string(fname); -+ -+ probec++; -+ -+ next; -+ } -+ -+ END { -+ print ""; -+ print ".globl dtrace_sdt_strings"; -+ print "\tALGN"; -+ print "dtrace_sdt_strings:"; -+ -+ -+ for (i = 0; i < strc; i++) -+ printf "\t.asciz\t\042%s\042\n", strv[i]; -+ -+ print ""; -+ print ".globl dtrace_sdt_nprobes"; -+ print ".globl dtrace_fbt_nfuncs"; -+ print "\tALGN"; -+ print "dtrace_sdt_nprobes:"; -+ printf "\tPTR\t%d\n", probec; -+ print "dtrace_fbt_nfuncs:"; -+ printf "\tPTR\t%d\n", funcc; -+ -+ exit(errc == 0 ? 0 : 1); -+ }' > $tfn -+fi -+ -+exit $? -diff --git a/scripts/kmodsdt.c b/scripts/kmodsdt.c -new file mode 100644 -index 000000000000..1e35794467d7 ---- /dev/null -+++ b/scripts/kmodsdt.c -@@ -0,0 +1,410 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright 2016 Oracle, Inc. All rights reserved. -+ * Use is subject to license terms. -+ */ -+ -+#include "../include/generated/autoconf.h" -+ -+#define ELF_TARGET_ALL -+#include <elf.h> -+#include <gelf.h> -+ -+#include <sys/types.h> -+ -+#include <unistd.h> -+#include <string.h> -+#include <limits.h> -+#include <stddef.h> -+#include <stdlib.h> -+#include <stdio.h> -+#include <fcntl.h> -+#include <errno.h> -+#include <assert.h> -+ -+typedef struct symtbl { -+ struct symtbl *next; -+ void *strtab; -+ void *symtab; -+} symtbl_t; -+ -+static int -+dt_elf_symtab_lookup(Elf_Data *data_sym, int nsym, uintptr_t addr, uint32_t shn, -+ GElf_Sym *sym) -+{ -+ int i, ret = -1; -+ GElf_Sym s; -+ -+ for (i = 0; i < nsym && gelf_getsym(data_sym, i, sym) != NULL; i++) { -+ if (GELF_ST_TYPE(sym->st_info) == STT_FUNC && -+ shn == sym->st_shndx && -+ sym->st_value <= addr && -+ addr < sym->st_value + sym->st_size) { -+ if (GELF_ST_BIND(sym->st_info) == STB_GLOBAL) -+ return i; -+ -+ ret = i; -+ s = *sym; -+ } -+ } -+ -+ if (ret >= 0) -+ *sym = s; -+ return ret; -+} -+ -+static int -+process_obj(const char *obj) -+{ -+ static const char dt_ppref[] = "__dtrace_probe_"; -+ static const char dt_spref[] = "__dta_"; -+ int fd, i, sidx, mod = 0; -+ Elf *elf = NULL; -+ GElf_Ehdr ehdr; -+ Elf_Scn *scn_rel, *scn_sym, *scn_str; -+ Elf_Data *data_rel, *data_sym, *data_str; -+ GElf_Shdr shdr_rel, shdr_sym, shdr_str; -+ GElf_Sym rsym, fsym, dsym; -+ GElf_Rela rela; -+ char *p, *r, *f, *a; -+ uint32_t eclass, emachine1, emachine2; -+ size_t symsize, nsym, nstr, isym, istr, osym, len; -+ symtbl_t *pair, *bufs = NULL; -+ char **alttab; -+ const char *elferrstr = "no error"; -+ -+ fd = open(obj, O_RDWR); -+ if (fd == -1) { -+ fprintf(stderr, "failed to open %s: %s\n", obj, -+ strerror(errno)); -+ return 1; -+ } -+ -+ if (elf_version(EV_CURRENT) == EV_NONE) { -+ fprintf(stderr, "ELF library version too old\n"); -+ return 1; -+ } -+ -+ elf = elf_begin(fd, ELF_C_RDWR, NULL); -+ if (elf == NULL) { -+ fprintf(stderr, "failed to process %s: %s\n", obj, -+ elf_errmsg(elf_errno())); -+ return 1; -+ } -+ -+ switch (elf_kind(elf)) { -+ case ELF_K_ELF: -+ break; -+ case ELF_K_AR: -+ fprintf(stderr, "archives are not permitted; %s\n", obj); -+ return 1; -+ default: -+ fprintf(stderr, "invalid file type: %s\n", obj); -+ return 1; -+ } -+ -+ if (gelf_getehdr(elf, &ehdr) == NULL) { -+ fprintf(stderr, "corrupt file: %s\n", obj); -+ return 1; -+ } -+ -+#ifdef CONFIG_64BIT -+ eclass = ELFCLASS64; -+# if defined(__sparc) -+ emachine1 = emachine2 = EM_SPARCV9; -+# elif defined(__i386) || defined(__amd64) -+ emachine1 = emachine2 = EM_X86_64; -+# elif defined(__aarch64__) -+ emachine1 = emachine2 = EM_AARCH64; -+# endif -+ symsize = sizeof(Elf64_Sym); -+#else -+ eclass = ELFCLASS32; -+# if defined(__sparc) -+ emachine1 = EM_SPARC; -+ emachine2 = EM_SPARC32PLUS; -+# elif defined(__i386) || defined(__amd64) -+ emachine1 = emachine2 = EM_386; -+# elif defined(__arm__) -+ emachine1 = emachine2 = EM_ARM; -+# endif -+ symsize = sizeof(Elf32_Sym); -+#endif -+ -+ if (ehdr.e_ident[EI_CLASS] != eclass) { -+ fprintf(stderr, "incorrect ELF class for %s: %d " -+ "(expected %d)\n", obj, ehdr.e_ident[EI_CLASS], -+ eclass); -+ return 1; -+ } -+ if (ehdr.e_machine != emachine1 && ehdr.e_machine != emachine2) { -+ fprintf(stderr, "incorrect ELF machine type for %s: %d " -+ "(expected %d or %d)\n", -+ obj, ehdr.e_machine, emachine1, emachine2); -+ return 1; -+ } -+ -+ scn_rel = NULL; -+ while ((scn_rel = elf_nextscn(elf, scn_rel)) != NULL) { -+ if (gelf_getshdr(scn_rel, &shdr_rel) == NULL) { -+ elferrstr = "failed to get section header"; -+ goto elf_err; -+ } -+ -+ /* -+ * Skip any non-relocation sections. -+ */ -+ if (shdr_rel.sh_type != SHT_RELA && shdr_rel.sh_type != SHT_REL) -+ continue; -+ -+ data_rel = elf_getdata(scn_rel, NULL); -+ if (data_rel == NULL) { -+ elferrstr = "failed to get relocation data"; -+ goto elf_err; -+ } -+ -+ /* -+ * Grab the section, section header and section data for the -+ * symbol table that this relocation section references. -+ */ -+ scn_sym = elf_getscn(elf, shdr_rel.sh_link); -+ if (scn_sym == NULL || -+ gelf_getshdr(scn_sym, &shdr_sym) == NULL || -+ (data_sym = elf_getdata(scn_sym, NULL)) == NULL) { -+ elferrstr = "failed to get symbol table"; -+ goto elf_err; -+ } -+ -+ /* -+ * Ditto for that symbol table's string table. -+ */ -+ scn_str = elf_getscn(elf, shdr_sym.sh_link); -+ if (scn_str == NULL || -+ gelf_getshdr(scn_str, &shdr_str) == NULL || -+ (data_str = elf_getdata(scn_str, NULL)) == NULL) { -+ elferrstr = "failed to get string table"; -+ goto elf_err; -+ } -+ -+ /* -+ * We're looking for relocations to symbols matching this form: -+ * -+ * __dtrace_probe_<probe> -+ * -+ * If the function containing the probe is locally scoped -+ * (static), we create an alias. The alias, a new symbol, -+ * will be global (so that it can be referenced from sdtinfo -+ * entries) and hidden (so that it is converted to a local -+ * symbol at link time). Such aliases have this form: -+ * -+ * __dta_<function>_<symindex> -+ * -+ * The <symindex> is appended to ensure that aliases are unique -+ * because they are referenced in global scope. Two local -+ * functions with identical names need to be distrinct at the -+ * level of the aliases. -+ * -+ * We take a first pass through all the relocations to -+ * populate our string table and count the number of extra -+ * symbols we'll require. Note that the <function> is -+ * sanitized to ensure that it is a valid C identifier, i.e. -+ * any periods in the name are converted to underscores. -+ */ -+ isym = osym = data_sym->d_size / symsize; -+ istr = data_str->d_size; -+ -+ /* -+ * Allocate the alias table to be the exact same size as the -+ * symtab. If an alias is required for a specific symbol, its -+ * corresponding entry in this alias table will contain the -+ * alias name. Otherwise, the entry will be NULL. -+ */ -+ alttab = (char **)calloc(isym, sizeof(char *)); -+ -+ nsym = 0; -+ nstr = 0; -+ -+ for (i = 0; i < shdr_rel.sh_size / shdr_rel.sh_entsize; i++) { -+ if (shdr_rel.sh_type == SHT_RELA) { -+ if (gelf_getrela(data_rel, i, &rela) == NULL) -+ continue; -+ } else { -+ GElf_Rel rel; -+ -+ if (gelf_getrel(data_rel, i, &rel) == NULL) -+ continue; -+ rela.r_offset = rel.r_offset; -+ rela.r_info = rel.r_info; -+ rela.r_addend = 0; -+ } -+ -+ if (gelf_getsym(data_sym, GELF_R_SYM(rela.r_info), -+ &rsym) == NULL) { -+ elferrstr = "relocation symbol not found"; -+ goto elf_err; -+ } -+ -+ assert(rsym.st_name < data_str->d_size); -+ -+ r = (char *)data_str->d_buf + rsym.st_name; -+ if (strncmp(r, dt_ppref, sizeof(dt_ppref) - 1) != 0) -+ continue; -+ -+ sidx = dt_elf_symtab_lookup(data_sym, isym, -+ rela.r_offset, -+ shdr_rel.sh_info, &fsym); -+ if (sidx < 0) { -+ fprintf(stderr, "relocation %x not in " -+ "function\n", i); -+ goto err; -+ } -+ -+ assert(fsym.st_name < data_str->d_size); -+ assert(GELF_ST_TYPE(fsym.st_info) == STT_FUNC); -+ -+ if (GELF_ST_BIND(fsym.st_info) != STB_LOCAL) -+ continue; -+ -+ f = (char *)data_str->d_buf + fsym.st_name; -+ -+ if (alttab[sidx] != NULL) -+ continue; -+ -+ len = snprintf(NULL, 0, "%s%s_%d", dt_spref, f, sidx) -+ + 1; -+ a = malloc(len); -+ assert(a != NULL); -+ nstr += snprintf(a, len, "%s%s_%d", dt_spref, f, sidx) -+ + 1; -+ for (p = a; *p != '\0'; p++) { -+ if (*p == '.') -+ *p = '_'; -+ } -+ alttab[sidx] = a; -+ nsym++; -+ } -+ -+ if (!nsym) { -+ free(alttab); -+ continue; -+ } -+ -+ pair = malloc(sizeof(symtbl_t)); -+ if (pair == NULL) { -+ fprintf(stderr, "failed to alloc new symtbl\n"); -+ goto err; -+ } -+ pair->strtab = malloc(data_str->d_size + nstr); -+ if (pair->strtab == NULL) { -+ fprintf(stderr, "failed to alloc new symtbl->strtab\n"); -+ free(pair); -+ goto err; -+ } -+ pair->symtab = malloc(data_sym->d_size + nsym * symsize); -+ if (pair->symtab == NULL) { -+ fprintf(stderr, "failed to alloc new symtbl->symtab\n"); -+ free(pair->strtab); -+ free(pair); -+ goto err; -+ } -+ -+ pair->next = bufs; -+ bufs = pair; -+ -+ memcpy(pair->strtab, data_str->d_buf, data_str->d_size); -+ data_str->d_buf = pair->strtab; -+ data_str->d_size += nstr; -+ elf_flagdata(data_str, ELF_C_SET, ELF_F_DIRTY); -+ shdr_str.sh_size += nstr; -+ gelf_update_shdr(scn_str, &shdr_str); -+ -+ memcpy(pair->symtab, data_sym->d_buf, data_sym->d_size); -+ data_sym->d_buf = pair->symtab; -+ data_sym->d_size += nsym * symsize; -+ elf_flagdata(data_sym, ELF_C_SET, ELF_F_DIRTY); -+ shdr_sym.sh_size += nsym * symsize; -+ gelf_update_shdr(scn_sym, &shdr_sym); -+ -+ nsym += isym; -+ -+ /* -+ * Now that the tables have been allocated, add the aliases as -+ * described above. Since we already know the symtab index of -+ * the symbol that the alias refers to, we can simply run down -+ * the alttab and add alias for any non-NULL entries. -+ */ -+ for (i = 1; i < osym; i++) { -+ if (alttab[i] == NULL) -+ continue; -+ -+ if (gelf_getsym(data_sym, i, &fsym) == NULL) { -+ fprintf(stderr, "failed to get symbol %d: %s\n", -+ i, elf_errmsg(elf_errno())); -+ goto err; -+ } -+ -+ assert(GELF_ST_TYPE(fsym.st_info) == STT_FUNC); -+ assert(GELF_ST_BIND(fsym.st_info) == STB_LOCAL); -+ /* -+ * Add the alias as a new symbol to the symtab. -+ */ -+ dsym = fsym; -+ dsym.st_name = istr; -+ dsym.st_info = GELF_ST_INFO(STB_GLOBAL, STT_FUNC); -+ dsym.st_other = ELF64_ST_VISIBILITY(STV_HIDDEN); -+ -+ len = strlen(alttab[i]) + 1; -+ assert(istr + len <= data_str->d_size); -+ a = (char *)data_str->d_buf + istr; -+ memcpy(a, alttab[i], len); -+ -+ gelf_update_sym(data_sym, isym, &dsym); -+ istr += len; -+ isym++; -+ -+ assert(isym <= nsym); -+ -+ mod = 1; -+ -+ free(alttab[i]); -+ } -+ -+ free(alttab); -+ } -+ -+ if (mod && elf_update(elf, ELF_C_WRITE) == -1) { -+ elferrstr = "Failed to update ELF object"; -+ goto elf_err; -+ } -+ -+ elf_end(elf); -+ close(fd); -+ -+ while ((pair = bufs) != NULL) { -+ bufs = pair->next; -+ free(pair->strtab); -+ free(pair->symtab); -+ free(pair); -+ } -+ -+ return 0; -+ -+elf_err: -+ fprintf(stderr, "%s: %s\n", elferrstr, elf_errmsg(elf_errno())); -+err: -+ fprintf(stderr, "an error was encountered while processing %s\n", obj); -+ return 1; -+} -+ -+int -+main(int argc, char *argv[]) -+{ -+ int i; -+ -+ for (i = 1; i < argc; i++) { -+ if (process_obj(argv[i])) -+ exit(1); -+ } -+ -+ exit(0); -+} -diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh -index bc533252fa3c..0b2f3bb60936 100755 ---- a/scripts/link-vmlinux.sh -+++ b/scripts/link-vmlinux.sh -@@ -43,6 +43,34 @@ info() - fi - } - -+# Generate the SDT probe point stubs object file -+# ${1} output file -+sdtstub() -+{ -+ info SDTSTB ${1} -+ ${srctree}/scripts/dtrace_sdt.sh sdtstub .tmp_sdtstub.S \ -+ ${KBUILD_VMLINUX_OBJS} -+ -+ local aflags="${KBUILD_AFLAGS} ${KBUILD_AFLAGS_KERNEL} \ -+ ${NOSTDINC_FLAGS} ${LINUXINCLUDE} ${KBUILD_CPPFLAGS}" -+ -+ ${CC} ${aflags} -c -o ${1} .tmp_sdtstub.S -+} -+ -+# Generate the SDT probe info for kernel image ${1} -+# ${2} output file -+sdtinfo() -+{ -+ info SDTINF ${2} -+ -+ ${srctree}/scripts/dtrace_sdt.sh sdtinfo .tmp_sdtinfo.S ${1} -+ -+ local aflags="${KBUILD_AFLAGS} ${KBUILD_AFLAGS_KERNEL} \ -+ ${NOSTDINC_FLAGS} ${LINUXINCLUDE} ${KBUILD_CPPFLAGS}" -+ -+ ${CC} ${aflags} -c -o ${2} .tmp_sdtinfo.S -+} -+ - # Link of vmlinux.o used for section mismatch analysis - # ${1} output file - modpost_link() -@@ -84,17 +112,20 @@ objtool_link() - - # Link of vmlinux - # ${1} - output file --# ${2}, ${3}, ... - optional extra .o files -+# ${2} - optional extra ld flag(s) -+# ${3}, ${4}, ... - optional extra .o files - vmlinux_link() - { - local lds="${objtree}/${KBUILD_LDS}" - local output=${1} -+ local flags="${2}" - local objects - local strip_debug - - info LD ${output} - -- # skip output file argument -+ # skip output file and flags arguments -+ shift - shift - - # The kallsyms linking does not need debug symbols included. -@@ -114,7 +145,7 @@ vmlinux_link() - - ${LD} ${KBUILD_LDFLAGS} ${LDFLAGS_vmlinux} \ - ${strip_debug#-Wl,} \ -- -o ${output} \ -+ ${flags} -o ${output} \ - -T ${lds} ${objects} - else - objects="-Wl,--whole-archive \ -@@ -128,7 +159,7 @@ vmlinux_link() - - ${CC} ${CFLAGS_vmlinux} \ - ${strip_debug} \ -- -o ${output} \ -+ ${flags} -o ${output} \ - -Wl,-T,${lds} \ - ${objects} \ - -lutil -lrt -lpthread -@@ -219,7 +250,7 @@ kallsyms_step() - kallsymso=${kallsyms_vmlinux}.o - kallsyms_S=${kallsyms_vmlinux}.S - -- vmlinux_link ${kallsyms_vmlinux} "${kallsymso_prev}" ${btf_vmlinux_bin_o} -+ vmlinux_link ${kallsyms_vmlinux} "${2:-}" "${kallsymso_prev}" ${btf_vmlinux_bin_o} ${sdtstubo} ${sdtinfoo} - kallsyms ${kallsyms_vmlinux} ${kallsyms_S} - - info AS ${kallsyms_S} -@@ -245,6 +276,8 @@ cleanup() - { - rm -f .btf.* - rm -f .tmp_System.map -+ rm -f .tmp_sdtstub.* -+ rm -f .tmp_sdtinfo.* - rm -f .tmp_vmlinux* - rm -f System.map - rm -f vmlinux -@@ -293,6 +326,14 @@ fi; - # final build of init/ - ${MAKE} -f "${srctree}/scripts/Makefile.build" obj=init need-builtin=1 - -+sdtstubo="" -+sdtinfoo="" -+if [ -n "${CONFIG_DTRACE}" ]; then -+ sdtstubo=.tmp_sdtstub.o -+ sdtinfoo=.tmp_sdtinfo.o -+ sdtstub ${sdtstubo} -+fi -+ - #link vmlinux.o - info LD vmlinux.o - modpost_link vmlinux.o -@@ -346,7 +387,23 @@ if [ -n "${CONFIG_KALLSYMS}" ]; then - # a) Verify that the System.map from vmlinux matches the map from - # ${kallsymso}. - -+ # step 1 -+ if [ -n "${CONFIG_DTRACE}" ]; then -+ sdtinfo vmlinux.o ${sdtinfoo} -+ fi -+ - kallsyms_step 1 -+ -+ if [ -n "${CONFIG_DTRACE}" ]; then -+ if [ -n "${CONFIG_ARM64}" ]; then -+ kallsyms_step 1 -+ else -+ kallsyms_step 1 -r -+ fi -+ sdtinfo ${kallsyms_vmlinux} ${sdtinfoo} vmlinux.o -+ fi -+ -+ # step 2 - kallsyms_step 2 - - # step 3 -@@ -358,7 +415,7 @@ if [ -n "${CONFIG_KALLSYMS}" ]; then - fi - fi - --vmlinux_link vmlinux "${kallsymso}" ${btf_vmlinux_bin_o} -+vmlinux_link vmlinux "" "${kallsymso}" ${btf_vmlinux_bin_o} ${sdtstubo} ${sdtinfoo} - - # fill in BTF IDs - if [ -n "${CONFIG_DEBUG_INFO_BTF}" -a -n "${CONFIG_BPF}" ]; then -diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c -index f882ce0d9327..ceeb69afc209 100644 ---- a/scripts/mod/modpost.c -+++ b/scripts/mod/modpost.c -@@ -2183,7 +2183,9 @@ static int check_exports(struct module *mod) - const char *basename; - exp = find_symbol(s->name); - if (!exp || exp->module == mod) { -- if (have_vmlinux && !s->weak) { -+ if (have_vmlinux && !s->weak && -+ !strstarts(s->name, "__dtrace_probe_") && -+ !strstarts(s->name, "__dtrace_isenabled_")) { - modpost_log(warn_unresolved ? LOG_WARN : LOG_ERROR, - "\"%s\" [%s.ko] undefined!\n", - s->name, mod->name); -@@ -2238,6 +2240,13 @@ static int check_modname_len(struct module *mod) - **/ - static void add_header(struct buffer *b, struct module *mod) - { -+ const char *modname; -+ -+ modname = strrchr(mod->name, '/'); -+ if (modname != NULL) -+ modname++; -+ else -+ modname = mod->name; - buf_printf(b, "#include <linux/module.h>\n"); - /* - * Include build-salt.h after module.h in order to -@@ -2248,6 +2257,10 @@ static void add_header(struct buffer *b, struct module *mod) - buf_printf(b, "#include <linux/vermagic.h>\n"); - buf_printf(b, "#include <linux/compiler.h>\n"); - buf_printf(b, "\n"); -+ buf_printf(b, "#ifdef CONFIG_DTRACE\n"); -+ buf_printf(b, "# include \"%s.sdtinfo.h\"\n", modname); -+ buf_printf(b, "#endif\n"); -+ buf_printf(b, "\n"); - buf_printf(b, "BUILD_SALT;\n"); - buf_printf(b, "\n"); - buf_printf(b, "MODULE_INFO(vermagic, VERMAGIC_STRING);\n"); -@@ -2263,6 +2276,10 @@ static void add_header(struct buffer *b, struct module *mod) - "\t.exit = cleanup_module,\n" - "#endif\n"); - buf_printf(b, "\t.arch = MODULE_ARCH_INIT,\n"); -+ buf_printf(b, "#ifdef CONFIG_DTRACE\n"); -+ buf_printf(b, "\t.sdt_probes = _sdt_probes,\n"); -+ buf_printf(b, "\t.sdt_probec = _sdt_probec,\n"); -+ buf_printf(b, "#endif\n"); - buf_printf(b, "};\n"); - } - --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/dtrace-patches/0009-dtrace-sdt-provider-for-x86.patch b/sys-kernel/cairn-sources/files/5.10.13/dtrace-patches/0009-dtrace-sdt-provider-for-x86.patch deleted file mode 100644 index 12385fef2f4d..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/dtrace-patches/0009-dtrace-sdt-provider-for-x86.patch +++ /dev/null @@ -1,1076 +0,0 @@ -From 33bb9a2aab1f792110ebeebcc2a5a0b5e02cec6c Mon Sep 17 00:00:00 2001 -From: Kris Van Hees <kris.van.hees@oracle.com> -Date: Mon, 19 Nov 2018 18:00:18 +0000 -Subject: [PATCH 09/19] dtrace: sdt provider for x86 - -This implements the SDT provider itself. It is relatively -straightforward except for the code needed to parse the argument strings -ultimately derived from SDT DTRACE_PROBE invocations and perf-event -prototype definitions. - -Signed-off-by: Kris Van Hees <kris.van.hees@oracle.com> -Signed-off-by: Nick Alcock <nick.alcock@oracle.com> -Signed-off-by: Tomas Jedlicka <tomas.jedlicka@oracle.com> -Signed-off-by: Eugene Loh <eugene.loh@oracle.com> -Signed-off-by: David Mc Lean <david.mclean@oracle.com> -Signed-off-by: Vincent Lim <vincent.lim@oracle.com> ---- - arch/x86/dtrace/Makefile.arch | 2 + - arch/x86/dtrace/sdt_x86_64.c | 126 ++++++++ - dtrace/Makefile | 2 + - dtrace/dt_test_dev.c | 33 ++ - dtrace/dt_test_mod.c | 5 + - dtrace/sdt_dev.c | 562 ++++++++++++++++++++++++++++++++++ - dtrace/sdt_impl.h | 87 ++++++ - dtrace/sdt_mod.c | 154 ++++++++++ - 8 files changed, 971 insertions(+) - create mode 100644 arch/x86/dtrace/sdt_x86_64.c - create mode 100644 dtrace/sdt_dev.c - create mode 100644 dtrace/sdt_impl.h - create mode 100644 dtrace/sdt_mod.c - -diff --git a/arch/x86/dtrace/Makefile.arch b/arch/x86/dtrace/Makefile.arch -index ffb9ef4d1722..8492eaee426d 100644 ---- a/arch/x86/dtrace/Makefile.arch -+++ b/arch/x86/dtrace/Makefile.arch -@@ -7,5 +7,7 @@ DTARCHDIR = ../arch/x86/dtrace - ccflags-y += -I$(srctree)/arch/x86/dtrace/include -Idtrace - - dtrace-obj += dtrace_asm_x86_64.o dtrace_isa_x86_64.o -+sdt-obj += sdt_x86_64.o - - dtrace-y += $(addprefix $(DTARCHDIR)/, $(dtrace-obj)) -+sdt-y += $(addprefix $(DTARCHDIR)/, $(sdt-obj)) -diff --git a/arch/x86/dtrace/sdt_x86_64.c b/arch/x86/dtrace/sdt_x86_64.c -new file mode 100644 -index 000000000000..e686634ff410 ---- /dev/null -+++ b/arch/x86/dtrace/sdt_x86_64.c -@@ -0,0 +1,126 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: sdt_dev.c -+ * DESCRIPTION: DTrace - SDT provider implementation for x86 -+ * -+ * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/sdt.h> -+#include <linux/slab.h> -+#include <linux/vmalloc.h> -+#include <asm/dtrace_util.h> -+ -+#include "dtrace.h" -+#include "dtrace_dev.h" -+#include "sdt_impl.h" -+ -+#define SDT_PATCHVAL 0xf0 -+ -+static uint8_t sdt_invop(struct pt_regs *regs) -+{ -+ struct sdt_probe *sdt = sdt_probetab[SDT_ADDR2NDX(regs->ip)]; -+ -+ for (; sdt != NULL; sdt = sdt->sdp_hashnext) { -+ if ((uintptr_t)sdt->sdp_patchpoint == regs->ip) { -+ if (sdt->sdp_ptype == SDTPT_IS_ENABLED) -+ regs->ax = 1; -+ else { -+ struct pt_regs *old_regs = -+ this_cpu_core->cpu_dtrace_regs; -+ -+ this_cpu_core->cpu_dtrace_regs = regs; -+ -+ dtrace_probe(sdt->sdp_id, regs->di, regs->si, -+ regs->dx, regs->cx, regs->r8, -+ regs->r9, 0); -+ -+ this_cpu_core->cpu_dtrace_regs = old_regs; -+ } -+ -+ return DTRACE_INVOP_NOPS; -+ } -+ } -+ -+ return 0; -+} -+ -+void sdt_provide_probe_arch(struct sdt_probe *sdp, struct module *mp, int idx) -+{ -+ sdp->sdp_patchval = SDT_PATCHVAL; -+ sdp->sdp_savedval = *sdp->sdp_patchpoint; -+} -+ -+int sdt_provide_module_arch(void *arg, struct module *mp) -+{ -+ return 1; -+} -+ -+void sdt_destroy_module(void *arg, struct module *mp) -+{ -+} -+ -+void sdt_enable_arch(struct sdt_probe *sdp, dtrace_id_t id, void *arg) -+{ -+ dtrace_invop_enable(sdp->sdp_patchpoint, sdp->sdp_patchval); -+} -+ -+void sdt_disable_arch(struct sdt_probe *sdp, dtrace_id_t id, void *arg) -+{ -+ dtrace_invop_disable(sdp->sdp_patchpoint, sdp->sdp_savedval); -+} -+ -+uint64_t sdt_getarg(void *arg, dtrace_id_t id, void *parg, int argno, -+ int aframes) -+{ -+ struct pt_regs *regs = this_cpu_core->cpu_dtrace_regs; -+ uint64_t *st; -+ uint64_t val; -+ -+ if (regs == NULL) -+ return 0; -+ -+ switch (argno) { -+ case 0: -+ return regs->di; -+ case 1: -+ return regs->si; -+ case 2: -+ return regs->dx; -+ case 3: -+ return regs->cx; -+ case 4: -+ return regs->r8; -+ case 5: -+ return regs->r9; -+ } -+ -+ ASSERT(argno > 5); -+ -+ st = (uint64_t *)regs->sp; -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); -+ val = st[argno - 6]; -+ DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); -+ -+ return val; -+} -+ -+int sdt_dev_init_arch(void) -+{ -+ return dtrace_invop_add(sdt_invop); -+} -+ -+void sdt_dev_exit_arch(void) -+{ -+ dtrace_invop_remove(sdt_invop); -+} -diff --git a/dtrace/Makefile b/dtrace/Makefile -index b91bc69d3802..126d4985967a 100644 ---- a/dtrace/Makefile -+++ b/dtrace/Makefile -@@ -3,6 +3,7 @@ - # - - obj-$(CONFIG_DT_CORE) += dtrace.o -+obj-$(CONFIG_DT_SDT) += sdt.o - obj-$(CONFIG_DT_SYSTRACE) += systrace.o - obj-$(CONFIG_DT_DT_TEST) += dt_test.o - -@@ -15,6 +16,7 @@ dtrace-y := dtrace_mod.o dtrace_dev.o \ - dtrace_probe.o dtrace_probe_ctx.o \ - dtrace_ptofapi.o dtrace_predicate.o \ - dtrace_spec.o dtrace_state.o dtrace_util.o -+sdt-y := sdt_mod.o sdt_dev.o - systrace-y := systrace_mod.o systrace_dev.o - dt_test-y := dt_test_mod.o dt_test_dev.o - -diff --git a/dtrace/dt_test_dev.c b/dtrace/dt_test_dev.c -index 8e1f5bab8a12..b720d8091787 100644 ---- a/dtrace/dt_test_dev.c -+++ b/dtrace/dt_test_dev.c -@@ -131,6 +131,39 @@ static long dt_test_ioctl(struct file *file, - return 0; - } - -+ if (DTRACE_PROBE_ENABLED(sdt__test)) -+ DTRACE_PROBE(sdt__test__is__enabled); -+ -+ DTRACE_PROBE(sdt__test); -+ -+ /* -+ * Test translation-to-nothing. -+ */ -+ DTRACE_PROBE(sdt__test__ioctl__file, int, cmd, int :, 666, -+ char * : (), 0, struct file *, file, int, arg); -+ -+ /* -+ * Probes with every valid count of args. -+ */ -+ DTRACE_PROBE(sdt__test__arg1, int, 1); -+ DTRACE_PROBE(sdt__test__arg2, int, 1, int, 2); -+ DTRACE_PROBE(sdt__test__arg3, int, 1, int, 2, int, 3); -+ DTRACE_PROBE(sdt__test__arg4, int, 1, int, 2, int, 3, int, 4); -+ DTRACE_PROBE(sdt__test__arg5, int, 1, int, 2, int, 3, int, 4, int, 5); -+ DTRACE_PROBE(sdt__test__arg6, int, 1, int, 2, int, 3, int, 4, int, 5, int, 6); -+ DTRACE_PROBE(sdt__test__arg7, int, 1, int, 2, int, 3, int, 4, int, 5, int, 6, int, 7); -+ DTRACE_PROBE(sdt__test__arg8, int, 1, int, 2, int, 3, int, 4, int, 5, int, 6, int, 7, int, 8); -+ DTRACE_PROBE(sdt__test__arg9, int, 1, int, 2, int, 3, int, 4, int, 5, int, 6, int, 7, int, 8, int, 9); -+ DTRACE_PROBE(sdt__test__arga, int, 1, int, 2, int, 3, int, 4, int, 5, int, 6, int, 7, int, 8, int, 9, int, 10); -+ DTRACE_PROBE(sdt__test__argb, int, 1, int, 2, int, 3, int, 4, int, 5, int, 6, int, 7, int, 8, int, 9, int, 10, int, 11); -+ DTRACE_PROBE(sdt__test__argc, int, 1, int, 2, int, 3, int, 4, int, 5, int, 6, int, 7, int, 8, int, 9, int, 10, int, 11, int, 12); -+ DTRACE_PROBE(sdt__test__argd, int, 1, int, 2, int, 3, int, 4, int, 5, int, 6, int, 7, int, 8, int, 9, int, 10, int, 11, int, 12, int, 13); -+ DTRACE_PROBE(sdt__test__arge, int, 1, int, 2, int, 3, int, 4, int, 5, int, 6, int, 7, int, 8, int, 9, int, 10, int, 11, int, 12, int, 13, int, 14); -+ DTRACE_PROBE(sdt__test__argf, int, 1, int, 2, int, 3, int, 4, int, 5, int, 6, int, 7, int, 8, int, 9, int, 10, int, 11, int, 12, int, 13, int, 14, int, 15); -+ DTRACE_PROBE(sdt__test__argg, int, 1, int, 2, int, 3, int, 4, int, 5, int, 6, int, 7, int, 8, int, 9, int, 10, int, 11, int, 12, int, 13, int, 14, int, 15, int, 16); -+ DTRACE_PROBE(sdt__test__argh, int, 1, int, 2, int, 3, int, 4, int, 5, int, 6, int, 7, int, 8, int, 9, int, 10, int, 11, int, 12, int, 13, int, 14, int, 15, int, 16, int, 17); -+ DTRACE_PROBE(sdt__test__argi, int, 1, int, 2, int, 3, int, 4, int, 5, int, 6, int, 7, int, 8, int, 9, int, 10, int, 11, int, 12, int, 13, int, 14, int, 15, int, 16, int, 17, int, 18); -+ - return -EAGAIN; - } - -diff --git a/dtrace/dt_test_mod.c b/dtrace/dt_test_mod.c -index d8af71665a37..a86c8bc02ae9 100644 ---- a/dtrace/dt_test_mod.c -+++ b/dtrace/dt_test_mod.c -@@ -50,3 +50,8 @@ static struct dtrace_pops dt_test_pops = { - }; - - DT_PROVIDER_MODULE(dt_test, DTRACE_PRIV_USER) -+ -+void foo(void) -+{ -+ DTRACE_PROBE(sdt__test2); -+} -diff --git a/dtrace/sdt_dev.c b/dtrace/sdt_dev.c -new file mode 100644 -index 000000000000..78457dad8773 ---- /dev/null -+++ b/dtrace/sdt_dev.c -@@ -0,0 +1,562 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: sdt_dev.c -+ * DESCRIPTION: DTrace - SDT provider device driver -+ * -+ * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/ctype.h> -+#include <linux/fs.h> -+#include <linux/miscdevice.h> -+#include <linux/sdt.h> -+#include <linux/slab.h> -+#include <linux/uaccess.h> -+#include <linux/vmalloc.h> -+ -+#include "dtrace.h" -+#include "dtrace_dev.h" -+#include "sdt_impl.h" -+ -+#define SDT_PROBETAB_SIZE 0x1000 /* 4k entries -- 16K total */ -+ -+struct sdt_probe **sdt_probetab; -+int sdt_probetab_size; -+int sdt_probetab_mask; -+ -+/* -+ * Return, in newly-allocated space, a version of the passed-in type 'vartype' -+ * which has been cleaned up suitably for CTF: leading and trailing spaces (if -+ * any) removed, and optionally a trailing argument removed as well. -+ * -+ * Type strings look like either -+ * -+ * type (for SDT, as in function prototypes), or -+ * -+ * type argname (for perf: as in function declarations). -+ * -+ * Translator components ": (foo, foo)", if any, have been removed by this -+ * stage. -+ */ -+static char *cleanup_type(const char *vartype, int arg_strip) -+{ -+ const char *cleaned; -+ const char *p; -+ -+ cleaned = vartype + strspn(vartype, " \t"); -+ for (p = cleaned + strlen(cleaned) - 1; p > cleaned && isspace(*p); -+ p--); -+ if (arg_strip) { -+ for (; p > cleaned && (isalnum(*p) || *p == '_'); p--); -+ for (; p > cleaned && isspace(*p); p--); -+ } -+ p++; -+ -+ return kstrndup(cleaned, p - cleaned, GFP_KERNEL); -+} -+ -+/* -+ * Set up the args lists, extracting them from their sdpd entry and parsing them -+ * into an sdt_argdesc array for each probe. -+ */ -+static struct sdt_argdesc * -+sdt_setup_args(struct sdt_probedesc *sdpd, -+ size_t *sdp_nargdesc) -+{ -+ struct sdt_argdesc *args; -+ char *argstr; -+ char *p; -+ int arg_strip = 0; -+ char *next_arg = NULL; -+ size_t arg = 0, sarg = 0, i; -+ -+ *sdp_nargdesc = 0; -+ -+ if ((sdpd->sdpd_args == NULL) || (sdpd->sdpd_args[0] == '\0')) -+ return NULL; -+ -+ /* -+ * Take a copy of the string so we can mutate it without causing trouble -+ * on module reload. -+ */ -+ argstr = kstrdup(sdpd->sdpd_args, GFP_KERNEL); -+ if (argstr == NULL) -+ goto oom; -+ -+ /* -+ * Handle the common case of a trailing comma before we allocate space, -+ * and elide it. -+ */ -+ p = argstr + strlen(argstr) - 1; -+ if (p[0] == ',' && p[1] == '\0') -+ *p = '\0'; -+ -+ /* -+ * This works for counting the number of args even though translator -+ * strings can contain commas, because each comma denotes a new probe -+ * argument. It may overcount in the case of elided arguments -+ * ("foo : ,"): we compensate for that further down, and ignore the tiny -+ * memory leak that results. -+ */ -+ for (p = argstr; p != NULL; p = strchr(p + 1, ',')) -+ (*sdp_nargdesc)++; -+ -+ args = kzalloc(*sdp_nargdesc * sizeof(struct sdt_argdesc), -+ GFP_KERNEL); -+ if (args == NULL) -+ goto oom_argstr; -+ -+ /* -+ * We need to transform each arg (stripping off a terminal argument -+ * name) if this is a perf probe. -+ */ -+ if (strncmp(sdpd->sdpd_name, "__perf_", strlen("__perf_")) == 0) -+ arg_strip = 1; -+ -+ next_arg = argstr; -+ do { -+ char *tok; -+ char *xlator = NULL, *p; -+ char *native; -+ int parens = 0; -+ int empty_xlation; -+ -+ /* -+ * Find the end of this arg, and figure out if it has any -+ * translators. Clean up the type of the arg (or native type, -+ * if this is a translated type). -+ */ -+ tok = next_arg; -+ next_arg = NULL; -+ p = strpbrk(tok, "():,"); -+ while (p && !next_arg) { -+ switch (*p) { -+ case '(': -+ parens++; -+ break; -+ case ')': -+ if (parens > 0) -+ parens--; -+ break; -+ case ':': -+ *p = '\0'; -+ xlator = p + 1; -+ break; -+ case ',': -+ if (parens == 0) { -+ *p = '\0'; -+ next_arg = p + 1; -+ } -+ break; -+ } -+ p = strpbrk(p + 1, "():,"); -+ } -+ -+ native = cleanup_type(tok, arg_strip); -+ if (native == NULL) { -+ args[arg].sda_native = args[arg].sda_xlate = NULL; -+ goto full_oom; -+ } -+ -+ /* -+ * Special case: perf's DECLARE_TRACE_NOARGS passes a single arg -+ * 'void'. Spot and skip it. -+ */ -+ if (!xlator && arg_strip && strcmp(native, "void") == 0) { -+ kfree(native); -+ (*sdp_nargdesc)--; -+ sarg++; -+ continue; -+ } -+ -+ /* -+ * No translator: straight mapping. -+ */ -+ if (xlator == NULL) { -+ ASSERT(arg < *sdp_nargdesc); -+ args[arg].sda_mapping = sarg; -+ args[arg].sda_native = native; -+ args[arg].sda_xlate = NULL; -+ arg++; -+ sarg++; -+ continue; -+ } -+ -+ /* -+ * If this is a perf probe, warn: translations cannot exist for -+ * these, and have no defined format yet in any case. We can -+ * struggle on by assuming they look like SDT translations. -+ */ -+ if (arg_strip) -+ pr_warn("Perf probe %s has at least one SDT translation, " -+ "which should be impossible.", sdpd->sdpd_name); -+ -+ /* -+ * Zero or more translations. (If there are zero, i.e. a pair -+ * of empty parentheses or a colon with nothing after it, we -+ * have to decrement the nargdesc.) -+ */ -+ -+ empty_xlation = 1; -+ while ((p = strsep(&xlator, "(,)")) != NULL) { -+ /* -+ * Skip the empty space before the ( or after the ). -+ */ -+ if (strspn(p, " \t") == strlen(p)) -+ continue; -+ -+ ASSERT(arg < *sdp_nargdesc); -+ -+ empty_xlation = 0; -+ args[arg].sda_mapping = sarg; -+ args[arg].sda_native = kstrdup(native, GFP_KERNEL); -+ args[arg].sda_xlate = cleanup_type(p, 0); -+ if ((args[arg].sda_native == NULL) || -+ (args[arg].sda_xlate == NULL)) { -+ pr_warn("Unable to create argdesc list for " -+ "probe %s: out of memory\n", -+ sdpd->sdpd_name); -+ kfree(native); -+ goto full_oom; -+ } -+ arg++; -+ } -+ if (empty_xlation) -+ (*sdp_nargdesc)--; -+ -+ kfree(native); -+ sarg++; -+ } while (next_arg != NULL); -+ -+ kfree(argstr); -+ return args; -+ -+full_oom: -+ for (i = 0; i < arg; i++) { -+ kfree(args[i].sda_native); -+ kfree(args[i].sda_xlate); -+ } -+ kfree(args); -+oom_argstr: -+ kfree(argstr); -+oom: -+ *sdp_nargdesc = 0; -+ pr_warn("Unable to create argdesc list for probe %s: " -+ "out of memory\n", sdpd->sdpd_name); -+ return NULL; -+} -+ -+void sdt_provide_module(void *arg, struct module *mp) -+{ -+ char *modname = mp->name; -+ struct dtrace_mprovider *prov; -+ struct sdt_probedesc *sdpd; -+ struct sdt_probe *sdp, *prv; -+ int idx, len; -+ int probes_skipped = 0; -+ -+ /* If module setup has failed then do not provide anything. */ -+ if (PDATA(mp) == NULL) -+ return; -+ -+ /* -+ * Nothing to do if the module SDT probes were already created. -+ */ -+ if (PDATA(mp)->sdt_probe_cnt != 0) -+ return; -+ -+ /* -+ * Nothing to do if there are no SDT probes. -+ */ -+ if (mp->sdt_probec == 0) -+ return; -+ -+ /* -+ * Nothing if arch specific module setup fails. -+ */ -+ if (!sdt_provide_module_arch(NULL, mp)) -+ return; -+ -+ /* -+ * Do not provide any probes unless all SDT providers have been created -+ * for this meta-provider. -+ */ -+ for (prov = sdt_providers; prov->dtmp_name != NULL; prov++) { -+ if (prov->dtmp_id == DTRACE_PROVNONE) -+ return; -+ } -+ -+ for (idx = 0, sdpd = mp->sdt_probes; idx < mp->sdt_probec; -+ idx++, sdpd++) { -+ char *name = sdpd->sdpd_name, *nname; -+ int i, j; -+ struct dtrace_mprovider *prov; -+ dtrace_id_t id; -+ enum fasttrap_probe_type ptype; -+ -+ if (name[0] == '?') { -+ ptype = SDTPT_IS_ENABLED; -+ name++; -+ } else -+ ptype = SDTPT_OFFSETS; -+ -+ for (prov = sdt_providers; prov->dtmp_pref != NULL; prov++) { -+ char *prefix = prov->dtmp_pref; -+ int len = strlen(prefix); -+ -+ if (strncmp(name, prefix, len) == 0) { -+ name += len; -+ break; -+ } -+ } -+ -+ nname = kmalloc(len = strlen(name) + 1, GFP_KERNEL); -+ if (nname == NULL) { -+ probes_skipped++; -+ continue; -+ } -+ -+ for (i = j = 0; name[j] != '\0'; i++) { -+ if (name[j] == '_' && name[j + 1] == '_') { -+ nname[i] = '-'; -+ j += 2; -+ } else -+ nname[i] = name[j++]; -+ } -+ -+ nname[i] = '\0'; -+ -+ sdp = kzalloc(sizeof(struct sdt_probe), GFP_KERNEL); -+ if (sdp == NULL) { -+ probes_skipped++; -+ continue; -+ } -+ -+ sdp->sdp_loadcnt = 1; /* FIXME */ -+ sdp->sdp_module = mp; -+ sdp->sdp_name = nname; -+ sdp->sdp_namelen = len; -+ sdp->sdp_provider = prov; -+ sdp->sdp_ptype = ptype; -+ -+ sdp->sdp_argdesc = sdt_setup_args(sdpd, &sdp->sdp_nargdesc); -+ -+ id = dtrace_probe_lookup(prov->dtmp_id, modname, -+ sdpd->sdpd_func, nname); -+ if (id != DTRACE_IDNONE) { -+ prv = dtrace_probe_arg(prov->dtmp_id, id); -+ ASSERT(prv != NULL); -+ -+ sdp->sdp_next = prv->sdp_next; -+ sdp->sdp_id = id; -+ prv->sdp_next = sdp; -+ } else { -+ sdp->sdp_id = dtrace_probe_create(prov->dtmp_id, -+ modname, -+ sdpd->sdpd_func, -+ nname, SDT_AFRAMES, -+ sdp); -+ -+ /* -+ * If we failed to create the probe just skip it. -+ */ -+ if (sdp->sdp_id == DTRACE_IDNONE) { -+ kfree(sdp); -+ probes_skipped++; -+ continue; -+ } -+ -+ PDATA(mp)->sdt_probe_cnt++; -+ } -+ -+ sdp->sdp_patchpoint = (asm_instr_t *)sdpd->sdpd_offset; -+ -+ sdt_provide_probe_arch(sdp, mp, idx); -+ -+ sdp->sdp_hashnext = sdt_probetab[ -+ SDT_ADDR2NDX(sdp->sdp_patchpoint)]; -+ sdt_probetab[SDT_ADDR2NDX(sdp->sdp_patchpoint)] = sdp; -+ } -+ -+ if (probes_skipped != 0) -+ pr_warn("sdt: Failed to provide %d probes in %s (out of memory)\n", -+ probes_skipped, mp->name); -+} -+ -+int sdt_enable(void *arg, dtrace_id_t id, void *parg) -+{ -+ struct sdt_probe *sdp = parg; -+ struct sdt_probe *curr; -+ -+ /* -+ * Ensure that we have a reference to the module. -+ */ -+ if (!try_module_get(sdp->sdp_module)) -+ return -EAGAIN; -+ -+ /* -+ * If at least one other enabled probe exists for this module, drop the -+ * reference we took above, because we only need one to prevent the -+ * module from being unloaded. -+ */ -+ PDATA(sdp->sdp_module)->enabled_cnt++; -+ if (PDATA(sdp->sdp_module)->enabled_cnt > 1) -+ module_put(sdp->sdp_module); -+ -+ for (curr = sdp; curr != NULL; curr = curr->sdp_next) -+ sdt_enable_arch(curr, id, arg); -+ -+ return 0; -+} -+ -+void sdt_disable(void *arg, dtrace_id_t id, void *parg) -+{ -+ struct sdt_probe *sdp = parg; -+ struct sdt_probe *curr; -+ -+ for (curr = sdp; curr != NULL; curr = curr->sdp_next) -+ sdt_disable_arch(curr, id, arg); -+ -+ /* -+ * If we are disabling a probe, we know it was enabled, and therefore -+ * we know that we have a reference on the module to prevent it from -+ * being unloaded. If we disable the last probe on the module, we can -+ * drop the reference. -+ */ -+ PDATA(sdp->sdp_module)->enabled_cnt--; -+ if (PDATA(sdp->sdp_module)->enabled_cnt == 0) -+ module_put(sdp->sdp_module); -+} -+ -+void sdt_getargdesc(void *arg, dtrace_id_t id, void *parg, -+ struct dtrace_argdesc *desc) -+{ -+ struct sdt_probe *sdp = parg; -+ -+ desc->dtargd_native[0] = '\0'; -+ desc->dtargd_xlate[0] = '\0'; -+ -+ while ((sdp->sdp_ptype == SDTPT_IS_ENABLED) && -+ (sdp->sdp_next != NULL)) -+ sdp = sdp->sdp_next; -+ -+ if (sdp->sdp_nargdesc <= desc->dtargd_ndx) { -+ desc->dtargd_ndx = DTRACE_ARGNONE; -+ return; -+ } -+ -+ if (sdp->sdp_argdesc[desc->dtargd_ndx].sda_native != NULL) -+ strlcpy(desc->dtargd_native, -+ sdp->sdp_argdesc[desc->dtargd_ndx].sda_native, -+ sizeof(desc->dtargd_native)); -+ -+ if (sdp->sdp_argdesc[desc->dtargd_ndx].sda_xlate != NULL) -+ strlcpy(desc->dtargd_xlate, -+ sdp->sdp_argdesc[desc->dtargd_ndx].sda_xlate, -+ sizeof(desc->dtargd_xlate)); -+ -+ desc->dtargd_mapping = sdp->sdp_argdesc[desc->dtargd_ndx].sda_mapping; -+} -+ -+void sdt_destroy(void *arg, dtrace_id_t id, void *parg) -+{ -+ struct sdt_probe *sdp = parg; -+ -+ PDATA(sdp->sdp_module)->sdt_probe_cnt--; -+ -+ while (sdp != NULL) { -+ struct sdt_probe *old = sdp, *last, *hash; -+ int ndx; -+ size_t i; -+ -+ ndx = SDT_ADDR2NDX(sdp->sdp_patchpoint); -+ last = NULL; -+ hash = sdt_probetab[ndx]; -+ -+ while (hash != sdp) { -+ ASSERT(hash != NULL); -+ last = hash; -+ hash = hash->sdp_hashnext; -+ } -+ -+ if (last != NULL) -+ last->sdp_hashnext = sdp->sdp_hashnext; -+ else -+ sdt_probetab[ndx] = sdp->sdp_hashnext; -+ -+ for (i = 0; i < sdp->sdp_nargdesc; i++) { -+ kfree(sdp->sdp_argdesc[i].sda_native); -+ kfree(sdp->sdp_argdesc[i].sda_xlate); -+ } -+ kfree(sdp->sdp_argdesc); -+ kfree(sdp->sdp_name); -+ sdp = sdp->sdp_next; -+ kfree(old); -+ } -+} -+ -+static int sdt_open(struct inode *inode, struct file *file) -+{ -+ return -EAGAIN; -+} -+ -+static int sdt_close(struct inode *inode, struct file *file) -+{ -+ return 0; -+} -+ -+static const struct file_operations sdt_fops = { -+ .owner = THIS_MODULE, -+ .open = sdt_open, -+ .release = sdt_close, -+}; -+ -+static struct miscdevice sdt_dev = { -+ .minor = DT_DEV_SDT_MINOR, -+ .name = "sdt", -+ .nodename = "dtrace/provider/sdt", -+ .fops = &sdt_fops, -+}; -+ -+int sdt_dev_init(void) -+{ -+ int ret = 0; -+ -+ ret = misc_register(&sdt_dev); -+ if (ret) { -+ pr_err("%s: Can't register misc device %d\n", -+ sdt_dev.name, sdt_dev.minor); -+ return ret; -+ } -+ -+ if (sdt_probetab_size == 0) -+ sdt_probetab_size = SDT_PROBETAB_SIZE; -+ -+ sdt_probetab_mask = sdt_probetab_size - 1; -+ sdt_probetab = vzalloc(sdt_probetab_size * sizeof(struct sdt_probe *)); -+ if (sdt_probetab == NULL) -+ return -ENOMEM; -+ -+ sdt_dev_init_arch(); -+ -+ return ret; -+} -+ -+void sdt_dev_exit(void) -+{ -+ sdt_dev_exit_arch(); -+ -+ vfree(sdt_probetab); -+ -+ misc_deregister(&sdt_dev); -+} -diff --git a/dtrace/sdt_impl.h b/dtrace/sdt_impl.h -new file mode 100644 -index 000000000000..e5b7f4f80270 ---- /dev/null -+++ b/dtrace/sdt_impl.h -@@ -0,0 +1,87 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Dynamic Tracing for Linux - Statically Defined Tracing provider -+ * -+ * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#ifndef _SDT_IMPL_H_ -+#define _SDT_IMPL_H_ -+ -+#include <linux/sdt.h> -+#include <asm/dtrace_arch.h> -+#include <dtrace/sdt_arch.h> -+ -+extern struct module *dtrace_kmod; -+ -+struct sdt_argdesc; -+ -+enum fasttrap_probe_type { -+ SDTPT_NONE = 0, -+ SDTPT_OFFSETS, -+ SDTPT_IS_ENABLED -+}; -+ -+struct sdt_probe { -+ struct dtrace_mprovider *sdp_provider; /* provider */ -+ char *sdp_name; /* name of probe */ -+ int sdp_namelen; /* length of allocated name */ -+ dtrace_id_t sdp_id; /* probe ID */ -+ struct module *sdp_module; /* modctl for module */ -+ int sdp_loadcnt; /* load count for module */ -+ int sdp_primary; /* non-zero if primary mod */ -+ enum fasttrap_probe_type sdp_ptype; /* probe type */ -+ asm_instr_t *sdp_patchpoint;/* patch point */ -+ asm_instr_t sdp_patchval; /* instruction to patch */ -+ asm_instr_t sdp_savedval; /* saved instruction value */ -+ struct sdt_argdesc *sdp_argdesc; /* arguments for this probe */ -+ size_t sdp_nargdesc; /* number of arguments */ -+ struct sdt_probe *sdp_next; /* next probe */ -+ struct sdt_probe *sdp_hashnext; /* next on hash */ -+}; -+ -+struct sdt_argdesc { -+ int sda_mapping; -+ char *sda_native; -+ char *sda_xlate; -+}; -+ -+extern struct dtrace_mprovider sdt_providers[]; -+extern struct sdt_probe **sdt_probetab; -+extern int sdt_probetab_size; -+extern int sdt_probetab_mask; -+ -+#define SDT_ADDR2NDX(addr) ((((uintptr_t)(addr)) >> 4) & \ -+ sdt_probetab_mask) -+ -+extern void sdt_provide_probe_arch(struct sdt_probe *, struct module *, int); -+extern int sdt_provide_module_arch(void *, struct module *); -+extern void sdt_enable_arch(struct sdt_probe *, dtrace_id_t, void *); -+extern void sdt_disable_arch(struct sdt_probe *, dtrace_id_t, void *); -+ -+extern void sdt_provide_module(void *, struct module *); -+extern void sdt_destroy_module(void *, struct module *); -+extern int sdt_enable(void *, dtrace_id_t, void *); -+extern void sdt_disable(void *, dtrace_id_t, void *); -+extern void sdt_getargdesc(void *, dtrace_id_t, void *, -+ struct dtrace_argdesc *); -+extern uint64_t sdt_getarg(void *, dtrace_id_t, void *, int, int); -+extern void sdt_destroy(void *, dtrace_id_t, void *); -+ -+extern int sdt_dev_init(void); -+extern void sdt_dev_exit(void); -+ -+extern int sdt_dev_init_arch(void); -+extern void sdt_dev_exit_arch(void); -+ -+#endif /* _SDT_IMPL_H_ */ -diff --git a/dtrace/sdt_mod.c b/dtrace/sdt_mod.c -new file mode 100644 -index 000000000000..1de9e72396aa ---- /dev/null -+++ b/dtrace/sdt_mod.c -@@ -0,0 +1,154 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: sdt_mod.c -+ * DESCRIPTION: DTrace - SDT provider kernel module -+ * -+ * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/module.h> -+ -+#include "dtrace.h" -+#include "dtrace_dev.h" -+#include "sdt_impl.h" -+ -+MODULE_AUTHOR("Kris Van Hees (kris.van.hees@oracle.com)"); -+MODULE_DESCRIPTION("Profile Interrupt Tracing"); -+MODULE_VERSION("v0.1"); -+MODULE_LICENSE("GPL"); -+ -+static struct dtrace_pattr vtrace_attr = { -+{ DTRACE_STABILITY_UNSTABLE, DTRACE_STABILITY_UNSTABLE, DTRACE_CLASS_ISA }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_UNSTABLE, DTRACE_STABILITY_UNSTABLE, DTRACE_CLASS_ISA }, -+}; -+ -+static struct dtrace_pattr info_attr = { -+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA }, -+}; -+ -+static struct dtrace_pattr fc_attr = { -+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA }, -+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA }, -+}; -+ -+static struct dtrace_pattr fpu_attr = { -+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_CPU }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA }, -+}; -+ -+static struct dtrace_pattr fsinfo_attr = { -+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA }, -+}; -+ -+static struct dtrace_pattr stab_attr = { -+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA }, -+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA }, -+}; -+ -+static struct dtrace_pattr sdt_attr = { -+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA }, -+}; -+ -+static struct dtrace_pattr xpv_attr = { -+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_PLATFORM }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_PLATFORM }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_PLATFORM }, -+}; -+ -+static struct dtrace_pattr iscsi_attr = { -+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA }, -+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA }, -+}; -+ -+static struct dtrace_pattr perf_attr = { -+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA }, -+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA }, -+}; -+ -+static struct dtrace_pops sdt_pops = { -+ .dtps_provide = NULL, -+ .dtps_provide_module = sdt_provide_module, -+ .dtps_destroy_module = sdt_destroy_module, -+ .dtps_enable = sdt_enable, -+ .dtps_disable = sdt_disable, -+ .dtps_suspend = NULL, -+ .dtps_resume = NULL, -+ .dtps_getargdesc = sdt_getargdesc, -+#ifdef CONFIG_SPARC64 -+ .dtps_getargval = NULL, -+#else -+ .dtps_getargval = sdt_getarg, -+#endif -+ .dtps_usermode = NULL, -+ .dtps_destroy = sdt_destroy, -+}; -+ -+struct dtrace_mprovider sdt_providers[] = { -+ { "vtrace", "__vtrace_", &vtrace_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, -+ { "sysinfo", "__cpu_sysinfo_", &info_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, -+ { "vminfo", "__cpu_vminfo_", &info_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, -+ { "fpuinfo", "__fpuinfo_", &fpu_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, -+ { "sched", "__sched_", &stab_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, -+ { "proc", "__proc_", &stab_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, -+ { "io", "__io_", &stab_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, -+ { "ip", "__ip_", &stab_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, -+ { "lockstat", "__lockstat_", &stab_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, -+ { "tcp", "__tcp_", &stab_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, -+ { "udp", "__udp_", &stab_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, -+ { "mib", "__mib_", &stab_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, -+ { "fsinfo", "__fsinfo_", &fsinfo_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, -+ { "iscsi", "__iscsi_", &iscsi_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, -+ { "nfsv3", "__nfsv3_", &stab_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, -+ { "nfsv4", "__nfsv4_", &stab_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, -+ { "xpv", "__xpv_", &xpv_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, -+ { "fc", "__fc_", &fc_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, -+ { "srp", "__srp_", &fc_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, -+ { "sysevent", "__sysevent_", &stab_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, -+ { "perf", "__perf_", &perf_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, -+ { "sdt", NULL, &sdt_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, -+ { NULL } -+}; -+ -+DT_MULTI_PROVIDER_MODULE(sdt, sdt_providers) --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/dtrace-patches/0010-dtrace-profile-provider-and-test-probe-core-componen.patch b/sys-kernel/cairn-sources/files/5.10.13/dtrace-patches/0010-dtrace-profile-provider-and-test-probe-core-componen.patch deleted file mode 100644 index 0ce39bf8db94..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/dtrace-patches/0010-dtrace-profile-provider-and-test-probe-core-componen.patch +++ /dev/null @@ -1,50 +0,0 @@ -From 59b5eca72202d66370501cd651aef50b19ceb918 Mon Sep 17 00:00:00 2001 -From: Kris Van Hees <kris.van.hees@oracle.com> -Date: Mon, 19 Nov 2018 17:18:23 +0000 -Subject: [PATCH 10/19] dtrace: profile provider and test probe core components - -Only Kconfig changes are needed here: everything else is purely modular. - -Signed-off-by: Nick Alcock <nick.alcock@oracle.com> -Signed-off-by: Kris Van Hees <kris.van.hees@oracle.com> -Signed-off-by: Tomas Jedlicka <tomas.jedlicka@oracle.com> -Signed-off-by: Eugene Loh <eugene.loh@oracle.com> -Signed-off-by: David Mc Lean <david.mclean@oracle.com> -Signed-off-by: Vincent Lim <vincent.lim@oracle.com> ---- - kernel/dtrace/Kconfig | 12 ++++++++++++ - 1 file changed, 12 insertions(+) - -diff --git a/kernel/dtrace/Kconfig b/kernel/dtrace/Kconfig -index c1ec55d8750e..7b88206fe835 100644 ---- a/kernel/dtrace/Kconfig -+++ b/kernel/dtrace/Kconfig -@@ -23,6 +23,12 @@ config DT_CORE - - if DT_CORE - -+config DT_PROFILE -+ tristate "Profile Interrupt Tracing" -+ default m -+ help -+ The profile and tick providers, firing probes at specific intervals. -+ - config DT_SDT - tristate "Statically Defined Tracing" - default m -@@ -54,6 +60,12 @@ config DT_DT_TEST - help - A test provider used by the testsuite. - -+config DT_DT_PERF -+ tristate "DTrace Performance Test Probe" -+ default m -+ help -+ A test provider used for performance testing. -+ - config DT_DEBUG - bool "DTrace debugging" - default m --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/dtrace-patches/0011-dtrace-profile-and-tick-providers-built-on-cyclics.patch b/sys-kernel/cairn-sources/files/5.10.13/dtrace-patches/0011-dtrace-profile-and-tick-providers-built-on-cyclics.patch deleted file mode 100644 index d7d96d0bc613..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/dtrace-patches/0011-dtrace-profile-and-tick-providers-built-on-cyclics.patch +++ /dev/null @@ -1,641 +0,0 @@ -From f7a0d3e1af253e7887d41af5f199fc2561372448 Mon Sep 17 00:00:00 2001 -From: Kris Van Hees <kris.van.hees@oracle.com> -Date: Mon, 19 Nov 2018 18:05:13 +0000 -Subject: [PATCH 11/19] dtrace: profile and tick providers built on cyclics - -Probes are constructed dynamically as called upon by the user: some -default commonly-used probes for common timing frequencies are provided -whether or not called upon. - -Signed-off-by: Kris Van Hees <kris.van.hees@oracle.com> -Signed-off-by: Nick Alcock <nick.alcock@oracle.com> -Signed-off-by: Tomas Jedlicka <tomas.jedlicka@oracle.com> -Signed-off-by: Eugene Loh <eugene.loh@oracle.com> -Signed-off-by: David Mc Lean <david.mclean@oracle.com> -Signed-off-by: Vincent Lim <vincent.lim@oracle.com> ---- - dtrace/Makefile | 2 + - dtrace/profile.h | 32 +++ - dtrace/profile_dev.c | 491 +++++++++++++++++++++++++++++++++++++++++++ - dtrace/profile_mod.c | 52 +++++ - 4 files changed, 577 insertions(+) - create mode 100644 dtrace/profile.h - create mode 100644 dtrace/profile_dev.c - create mode 100644 dtrace/profile_mod.c - -diff --git a/dtrace/Makefile b/dtrace/Makefile -index 126d4985967a..5e6fb362a4e9 100644 ---- a/dtrace/Makefile -+++ b/dtrace/Makefile -@@ -3,6 +3,7 @@ - # - - obj-$(CONFIG_DT_CORE) += dtrace.o -+obj-$(CONFIG_DT_PROFILE) += profile.o - obj-$(CONFIG_DT_SDT) += sdt.o - obj-$(CONFIG_DT_SYSTRACE) += systrace.o - obj-$(CONFIG_DT_DT_TEST) += dt_test.o -@@ -16,6 +17,7 @@ dtrace-y := dtrace_mod.o dtrace_dev.o \ - dtrace_probe.o dtrace_probe_ctx.o \ - dtrace_ptofapi.o dtrace_predicate.o \ - dtrace_spec.o dtrace_state.o dtrace_util.o -+profile-y := profile_mod.o profile_dev.o - sdt-y := sdt_mod.o sdt_dev.o - systrace-y := systrace_mod.o systrace_dev.o - dt_test-y := dt_test_mod.o dt_test_dev.o -diff --git a/dtrace/profile.h b/dtrace/profile.h -new file mode 100644 -index 000000000000..713886d1d8e8 ---- /dev/null -+++ b/dtrace/profile.h -@@ -0,0 +1,32 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Dynamic Tracing for Linux - profile provider -+ * -+ * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#ifndef _PROFILE_H_ -+#define _PROFILE_H_ -+ -+extern void profile_provide(void *, const struct dtrace_probedesc *); -+extern int profile_enable(void *, dtrace_id_t, void *); -+extern void profile_disable(void *, dtrace_id_t, void *); -+extern int profile_usermode(void *, dtrace_id_t, void *); -+extern void profile_destroy(void *, dtrace_id_t, void *); -+ -+extern dtrace_provider_id_t profile_id; -+ -+extern int profile_dev_init(void); -+extern void profile_dev_exit(void); -+ -+#endif /* _PROFILE_H_ */ -diff --git a/dtrace/profile_dev.c b/dtrace/profile_dev.c -new file mode 100644 -index 000000000000..ce7261fcc911 ---- /dev/null -+++ b/dtrace/profile_dev.c -@@ -0,0 +1,491 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: profile_dev.c -+ * DESCRIPTION: DTrace - profile provider device driver -+ * -+ * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/fs.h> -+#include <linux/ktime.h> -+#include <linux/miscdevice.h> -+#include <linux/slab.h> -+#include <asm/irq_regs.h> -+#include <asm/ptrace.h> -+ -+#include <linux/hardirq.h> -+#include <linux/profile.h> -+ -+#include "dtrace.h" -+#include "dtrace_dev.h" -+#include "profile.h" -+ -+#define PROF_NAMELEN 15 -+#define PROF_PROFILE 0 -+#define PROF_TICK 1 -+#define PROF_PREFIX_PROFILE "profile-" -+#define PROF_PREFIX_TICK "tick-" -+ -+struct profile_probe { -+ char prof_name[PROF_NAMELEN]; -+ dtrace_id_t prof_id; -+ int prof_kind; -+ ktime_t prof_interval; -+ cyclic_id_t prof_cyclic; -+}; -+ -+struct profile_probe_percpu { -+ ktime_t profc_expected; -+ ktime_t profc_interval; -+ struct profile_probe *profc_probe; -+}; -+ -+static ktime_t profile_interval_min = KTIME_INIT(0, NANOSEC / 5000); -+static int profile_aframes; -+ -+static int profile_rates[] = { -+ 97, 199, 499, 997, 1999, -+ 4001, 4999, 0, 0, 0, -+ 0, 0, 0, 0, 0, -+ 0, 0, 0, 0, 0, -+ }; -+static int profile_ticks[] = { -+ 1, 10, 100, 500, 1000, -+ 5000, 0, 0, 0, 0, -+ 0, 0, 0, 0, 0, -+ }; -+ -+/* -+ * profile_max defines the upper bound on the number of profile probes that -+ * can exist (this is to prevent malicious or clumsy users from exhausing -+ * system resources by creating a slew of profile probes). At mod load time, -+ * this gets its value from PROFILE_MAX_DEFAULT or profile-max-probes if it's -+ * present as module parameter. -+ * FIXME: module parameter yet to be implemented. -+ */ -+#define PROFILE_MAX_DEFAULT 1000 /* default max. number of probes */ -+ -+static int profile_max; /* maximum number of profile probes */ -+static atomic_t profile_total; /* current number of profile probes */ -+ -+static void profile_tick_fn(uintptr_t arg) -+{ -+ struct profile_probe *prof = (struct profile_probe *)arg; -+ unsigned long pc = 0, upc = 0; -+ struct pt_regs *regs = get_irq_regs(); -+ -+ /* -+ * If regs == NULL, then we were called from from softirq context which -+ * also means that we didn't actually interrupt any processing (kernel -+ * or user space). -+ * If regs != NULL, then we did actually get called from hardirq -+ * because the timer interrupt did really interrupt something that was -+ * going on on the CPU (could be user mode or kernel mode). -+ */ -+ if (regs == NULL) { -+ uint64_t stack[8]; -+ -+ dtrace_getpcstack(stack, 8, 0, NULL); -+ pc = stack[7]; -+ } else if (user_mode(regs)) -+ upc = instruction_pointer(regs); -+ else -+ pc = instruction_pointer(regs); -+ -+ dtrace_probe(prof->prof_id, pc, upc, 0, 0, 0, 0, 0); -+} -+ -+static void profile_prof_fn(uintptr_t arg) -+{ -+ struct profile_probe_percpu *pcpu = (struct profile_probe_percpu *)arg; -+ struct profile_probe *prof = pcpu->profc_probe; -+ ktime_t late; -+ struct pt_regs *regs = get_irq_regs(); -+ unsigned long pc = 0, upc = 0; -+ -+ late = ktime_sub(dtrace_gethrtime(), pcpu->profc_expected); -+ pcpu->profc_expected = ktime_add(pcpu->profc_expected, -+ pcpu->profc_interval); -+ -+ /* -+ * If regs == NULL, then we were called from from softirq context which -+ * also means that we didn't actually interrupt any processing (kernel -+ * or user space). -+ * If regs != NULL, then we did actually get called from hardirq -+ * because the timer interrupt did really interrupt something that was -+ * going on on the CPU (could be user mode or kernel mode). -+ */ -+ if (regs == NULL) { -+ uint64_t stack[8]; -+ -+ dtrace_getpcstack(stack, 8, 0, NULL); -+ pc = stack[7]; -+ } else if (user_mode(regs)) -+ upc = instruction_pointer(regs); -+ else -+ pc = instruction_pointer(regs); -+ -+ dtrace_probe(prof->prof_id, pc, upc, ktime_to_ns(late), 0, 0, 0, 0); -+} -+ -+static void profile_online(void *arg, processorid_t cpu, -+ struct cyc_handler *hdlr, -+ struct cyc_time *when) -+{ -+ struct profile_probe *prof = arg; -+ struct profile_probe_percpu *pcpu; -+ -+ pcpu = kzalloc(sizeof(struct profile_probe_percpu), GFP_KERNEL); -+ pcpu->profc_probe = prof; -+ -+ hdlr->cyh_func = profile_prof_fn; -+ hdlr->cyh_arg = (uintptr_t)pcpu; -+ hdlr->cyh_level = CY_HIGH_LEVEL; -+ -+ when->cyt_interval = prof->prof_interval; -+ when->cyt_when = ktime_add(dtrace_gethrtime(), when->cyt_interval); -+ -+ pcpu->profc_expected = when->cyt_when; -+ pcpu->profc_interval = when->cyt_interval; -+} -+ -+static void profile_offline(void *arg, processorid_t cpu, void *oarg) -+{ -+ struct profile_probe_percpu *pcpu = oarg; -+ -+ if (pcpu->profc_probe == arg) { -+ kfree(pcpu); -+ return; -+ } -+ -+ WARN_ONCE(1, "%s: called with mismatched probe info (%p vs %p)" -+ " - leaking %lu bytes\n", __func__, pcpu->profc_probe, arg, -+ sizeof(struct profile_probe_percpu)); -+ -+} -+ -+static void profile_create(ktime_t interval, const char *name, int kind) -+{ -+ struct profile_probe *prof; -+ int nr_frames = 0; /* FIXME */ -+ -+ if (profile_aframes) -+ nr_frames = profile_aframes; -+ -+ if (ktime_lt(interval, profile_interval_min)) -+ return; -+ -+ if (dtrace_probe_lookup(profile_id, NULL, NULL, name) != 0) -+ return; -+ -+ prof = kzalloc(sizeof(struct profile_probe), GFP_KERNEL); -+ if (prof == NULL) { -+ pr_warn("Unable to create probe %s: out of memory\n", name); -+ return; -+ } -+ -+ atomic_inc(&profile_total); -+ if (atomic_read(&profile_total) > profile_max) -+ goto errout; -+ -+ strcpy(prof->prof_name, name); -+ prof->prof_interval = interval; -+ prof->prof_cyclic = CYCLIC_NONE; -+ prof->prof_kind = kind; -+ prof->prof_id = dtrace_probe_create(profile_id, NULL, NULL, name, -+ nr_frames, prof); -+ -+ if (prof->prof_id == DTRACE_IDNONE) { -+ pr_warn("Unable to create probe %s: out of memory\n", name); -+ goto errout; -+ } -+ -+ return; -+ -+errout: -+ kfree(prof); -+ atomic_dec(&profile_total); -+ return; -+} -+ -+void profile_provide(void *arg, const struct dtrace_probedesc *desc) -+{ -+ int i, j, rate, kind; -+ long val = 0, mult = 1, mult_s = 0, mult_ns = 0, len; -+ ktime_t interval; -+ const char *name, *suffix = NULL; -+ const struct { -+ char *prefix; -+ int kind; -+ } types[] = { -+ { PROF_PREFIX_PROFILE, PROF_PROFILE }, -+ { PROF_PREFIX_TICK, PROF_TICK }, -+ { NULL, 0 }, -+ }; -+ -+ const struct { -+ char *name; -+ long mult_s; -+ long mult_ns; -+ } suffixes[] = { -+ { "ns", 0, 1 }, -+ { "nsec", 0, 1 }, -+ { "us", 0, NANOSEC / MICROSEC }, -+ { "usec", 0, NANOSEC / MICROSEC }, -+ { "ms", 0, NANOSEC / MILLISEC }, -+ { "msec", 0, NANOSEC / MILLISEC }, -+ { "s", 1, 0 }, -+ { "sec", 1, 0 }, -+ { "m", 60, 0 }, -+ { "min", 60, 0 }, -+ { "h", 60 * 60, 0 }, -+ { "hour", 60 * 60, 0 }, -+ { "d", 24 * 60 * 60, 0 }, -+ { "day", 24 * 60 * 60, 0 }, -+ { "hz", 0, 0 }, -+ { NULL, }, -+ }; -+ -+ if (desc == NULL) { -+ char n[PROF_NAMELEN]; -+ -+ /* -+ * If no description was provided, provide all of our probes. -+ */ -+ for (i = 0; i < sizeof(profile_rates) / sizeof(int); i++) { -+ rate = profile_rates[i]; -+ if (rate == 0) -+ continue; -+ -+ snprintf(n, PROF_NAMELEN, "%s%d", -+ PROF_PREFIX_PROFILE, rate); -+ profile_create(ktime_set(0, NANOSEC / rate), -+ n, PROF_PROFILE); -+ } -+ -+ for (i = 0; i < sizeof(profile_ticks) / sizeof(int); i++) { -+ rate = profile_ticks[i]; -+ if (rate == 0) -+ continue; -+ -+ snprintf(n, PROF_NAMELEN, "%s%d", -+ PROF_PREFIX_TICK, rate); -+ profile_create(ktime_set(0, NANOSEC / rate), -+ n, PROF_TICK); -+ } -+ -+ return; -+ } -+ -+ name = desc->dtpd_name; -+ -+ for (i = 0; types[i].prefix != NULL; i++) { -+ len = strlen(types[i].prefix); -+ -+ if (strncmp(name, types[i].prefix, len) != 0) -+ continue; -+ -+ break; -+ } -+ -+ if (types[i].prefix == NULL) -+ return; -+ -+ kind = types[i].kind; -+ -+ /* -+ * We need to start before any time suffix. -+ */ -+ for (j = strlen(name); j >= len; j--) { -+ if (name[j] >= '0' && name[j] <= '9') -+ break; -+ -+ suffix = &name[j]; -+ } -+ -+ if (suffix == NULL) { -+ WARN_ONCE(1, "%s: missing time suffix in %s\n", __func__, name); -+ return; -+ } -+ -+ /* -+ * Now determine the numerical value present in the probe name. -+ */ -+ for (; j >= len; j--) { -+ if (name[j] < '0' || name[j] > '9') -+ return; -+ -+ val += (name[j] - '0') * mult; -+ mult *= 10; -+ } -+ -+ if (val == 0) -+ return; -+ -+ /* -+ * Look up the suffix to determine the multiplier. -+ */ -+ for (i = 0; suffixes[i].name != NULL; i++) { -+ if (strcasecmp(suffixes[i].name, suffix) == 0) { -+ mult_s = suffixes[i].mult_s; -+ mult_ns = suffixes[i].mult_ns; -+ break; -+ } -+ } -+ -+ if (suffixes[i].name == NULL && *suffix != '\0') -+ return; -+ -+ if (mult_s == 0 && mult_ns == 0) { -+ /* -+ * The default is frequency (per-second). -+ */ -+ interval = ns_to_ktime((int64_t)NANOSEC / val); -+ } else { -+ long sec; -+ long nsec = val * mult_ns; -+ -+ sec = nsec / NANOSEC; -+ nsec %= NANOSEC; -+ -+ interval = ktime_set(val * mult_s + sec, nsec); -+ } -+ -+ -+ profile_create(interval, name, kind); -+} -+ -+int profile_enable(void *arg, dtrace_id_t id, void *parg) -+{ -+ struct profile_probe *prof = parg; -+ struct cyc_time when; -+ -+ if (!ktime_nz(prof->prof_interval)) { -+ WARN_ONCE(1, "%s: trying to enable 0-interval probe %s\n", -+ __func__, prof->prof_name); -+ return 1; -+ } -+ if (!MUTEX_HELD(&cpu_lock)) { -+ WARN_ONCE(1, "%s: not holding cpu_lock\n", __func__); -+ return 1; -+ } -+ -+ if (prof->prof_kind == PROF_TICK) { -+ struct cyc_handler hdlr; -+ -+ hdlr.cyh_func = profile_tick_fn; -+ hdlr.cyh_arg = (uintptr_t)prof; -+ hdlr.cyh_level = CY_HIGH_LEVEL; -+ -+ when.cyt_interval = prof->prof_interval; -+ when.cyt_when = ktime_set(0, 0); -+ -+ prof->prof_cyclic = cyclic_add(&hdlr, &when); -+ } else if (prof->prof_kind == PROF_PROFILE) { -+ struct cyc_omni_handler omni; -+ -+ omni.cyo_online = profile_online; -+ omni.cyo_offline = profile_offline; -+ omni.cyo_arg = prof; -+ -+ prof->prof_cyclic = cyclic_add_omni(&omni); -+ } else -+ pr_warn_once("%s: Invalid profile type %d\n", -+ __func__, prof->prof_kind); -+ -+ return 0; -+} -+ -+void profile_disable(void *arg, dtrace_id_t id, void *parg) -+{ -+ struct profile_probe *prof = parg; -+ -+ if (prof->prof_cyclic == CYCLIC_NONE) { -+ WARN_ONCE(1, "%s: trying to disable probe %s without cyclic\n", -+ __func__, prof->prof_name); -+ return; -+ } -+ if (!MUTEX_HELD(&cpu_lock)) { -+ WARN_ONCE(1, "%s: not holding cpu_lock\n", __func__); -+ return; -+ } -+ -+ cyclic_remove(prof->prof_cyclic); -+ prof->prof_cyclic = CYCLIC_NONE; -+} -+ -+int profile_usermode(void *arg, dtrace_id_t id, void *parg) -+{ -+ return 1; /* FIXME: awaiting unprivileged tracing */ -+} -+ -+void profile_destroy(void *arg, dtrace_id_t id, void *parg) -+{ -+ struct profile_probe *prof = parg; -+ -+ if (prof->prof_cyclic == CYCLIC_NONE) { -+ kfree(prof); -+ -+ if (atomic_read(&profile_total) >= 1) { -+ atomic_dec(&profile_total); -+ return; -+ } -+ -+ WARN_ONCE(1, "%s: profile_total refcount is 0!\n", __func__); -+ } -+ -+ WARN_ONCE(1, "%s: %s still assigned to cyclic\n", -+ __func__, prof->prof_name); -+} -+ -+static int profile_open(struct inode *inode, struct file *file) -+{ -+ return -EAGAIN; -+} -+ -+static int profile_close(struct inode *inode, struct file *file) -+{ -+ return 0; -+} -+ -+static const struct file_operations profile_fops = { -+ .owner = THIS_MODULE, -+ .open = profile_open, -+ .release = profile_close, -+}; -+ -+static struct miscdevice profile_dev = { -+ .minor = DT_DEV_PROFILE_MINOR, -+ .name = "profile", -+ .nodename = "dtrace/provider/profile", -+ .fops = &profile_fops, -+}; -+ -+int profile_dev_init(void) -+{ -+ int ret = 0; -+ -+ ret = misc_register(&profile_dev); -+ if (ret) -+ pr_err("%s: Can't register misc device %d\n", -+ profile_dev.name, profile_dev.minor); -+ -+ profile_max = PROFILE_MAX_DEFAULT; -+ -+ return ret; -+} -+ -+void profile_dev_exit(void) -+{ -+ misc_deregister(&profile_dev); -+} -diff --git a/dtrace/profile_mod.c b/dtrace/profile_mod.c -new file mode 100644 -index 000000000000..1fb54a29e57e ---- /dev/null -+++ b/dtrace/profile_mod.c -@@ -0,0 +1,52 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: profile_mod.c -+ * DESCRIPTION: DTrace - Profile provider kernel module -+ * -+ * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/module.h> -+ -+#include "dtrace.h" -+#include "dtrace_dev.h" -+#include "profile.h" -+ -+MODULE_AUTHOR("Kris Van Hees (kris.van.hees@oracle.com)"); -+MODULE_DESCRIPTION("Profile Interrupt Tracing"); -+MODULE_VERSION("v0.1"); -+MODULE_LICENSE("GPL"); -+ -+static const struct dtrace_pattr profile_attr = { -+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON }, -+{ DTRACE_STABILITY_UNSTABLE, DTRACE_STABILITY_UNSTABLE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON }, -+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON }, -+}; -+ -+static struct dtrace_pops profile_pops = { -+ .dtps_provide = profile_provide, -+ .dtps_provide_module = NULL, -+ .dtps_destroy_module = NULL, -+ .dtps_enable = profile_enable, -+ .dtps_disable = profile_disable, -+ .dtps_suspend = NULL, -+ .dtps_resume = NULL, -+ .dtps_getargdesc = NULL, -+ .dtps_getargval = NULL, -+ .dtps_usermode = profile_usermode, -+ .dtps_destroy = profile_destroy, -+}; -+ -+DT_PROVIDER_MODULE(profile, DTRACE_PRIV_KERNEL | DTRACE_PRIV_USER) --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/dtrace-patches/0012-dtrace-USDT-and-pid-provider-core-and-x86-components.patch b/sys-kernel/cairn-sources/files/5.10.13/dtrace-patches/0012-dtrace-USDT-and-pid-provider-core-and-x86-components.patch deleted file mode 100644 index dfe577d6ae57..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/dtrace-patches/0012-dtrace-USDT-and-pid-provider-core-and-x86-components.patch +++ /dev/null @@ -1,412 +0,0 @@ -From 18dbf51fb9a2c43ac740c698ecbe91b48050e259 Mon Sep 17 00:00:00 2001 -From: Kris Van Hees <kris.van.hees@oracle.com> -Date: Mon, 19 Nov 2018 18:58:27 +0000 -Subject: [PATCH 12/19] dtrace: USDT and pid provider core and x86 components - -This implements the core (linked-in) machinery needed for userspace -statically-defined tracepoints (for historical reasons, known as -'fasttrap' by DTrace) and for the pid provider, which allows USDT -probes to be dropped at addresses that do not correspond to symbols, -at locations named as a symbol plus an offset. Both are implemented in -terms of kprobes. - -Signed-off-by: Nick Alcock <nick.alcock@oracle.com> -Signed-off-by: Kris Van Hees <kris.van.hees@oracle.com> -Signed-off-by: Tomas Jedlicka <tomas.jedlicka@oracle.com> -Signed-off-by: Eugene Loh <eugene.loh@oracle.com> -Signed-off-by: David Mc Lean <david.mclean@oracle.com> -Signed-off-by: Vincent Lim <vincent.lim@oracle.com> ---- - include/linux/dtrace_os.h | 23 +++ - kernel/dtrace/Kconfig | 10 ++ - kernel/dtrace/dtrace_os.c | 272 ++++++++++++++++++++++++++++++++++++ - kernel/dtrace/dtrace_task.c | 15 ++ - 4 files changed, 320 insertions(+) - -diff --git a/include/linux/dtrace_os.h b/include/linux/dtrace_os.h -index f2921ce039a7..836825b1c7be 100644 ---- a/include/linux/dtrace_os.h -+++ b/include/linux/dtrace_os.h -@@ -14,6 +14,9 @@ - #include <linux/mm.h> - #include <linux/notifier.h> - #include <linux/timekeeper_internal.h> -+#if IS_ENABLED(CONFIG_DT_FASTTRAP) -+#include <linux/uprobes.h> -+#endif - #include <asm/unistd.h> - #include <linux/dtrace_cpu.h> - #include <linux/dtrace_task.h> -@@ -94,8 +97,28 @@ static inline int dtrace_no_pf(struct pt_regs *regs) - } - - extern void (*dtrace_helpers_cleanup)(struct task_struct *); -+extern void (*dtrace_fasttrap_probes_cleanup)(struct task_struct *); - extern void (*dtrace_helpers_fork)(struct task_struct *, struct task_struct *); - -+#if IS_ENABLED(CONFIG_DT_FASTTRAP) -+struct fasttrap_machtp { -+ struct inode *fmtp_ino; -+ loff_t fmtp_off; -+ struct uprobe_consumer fmtp_cns; -+}; -+ -+extern int (*dtrace_tracepoint_hit)(struct fasttrap_machtp *, -+ struct pt_regs *, int); -+ -+extern struct task_struct *register_pid_provider(pid_t); -+extern void unregister_pid_provider(pid_t); -+ -+extern int dtrace_copy_code(pid_t, uint8_t *, uintptr_t, size_t); -+extern int dtrace_tracepoint_enable(pid_t, uintptr_t, int, -+ struct fasttrap_machtp *); -+extern int dtrace_tracepoint_disable(pid_t, struct fasttrap_machtp *); -+#endif /* CONFIG_DT_FASTTRAP || CONFIG_DT_FASTTRAP_MODULE */ -+ - #else - - /* -diff --git a/kernel/dtrace/Kconfig b/kernel/dtrace/Kconfig -index 7b88206fe835..6bf6620981cd 100644 ---- a/kernel/dtrace/Kconfig -+++ b/kernel/dtrace/Kconfig -@@ -23,6 +23,16 @@ config DT_CORE - - if DT_CORE - -+config DT_FASTTRAP -+ tristate "Fasttrap Tracing" -+ default m -+ depends on ARCH_SUPPORTS_UPROBES -+ select UPROBE_EVENT -+ help -+ Userspace tracing, providing the kernel support needed for tracing -+ userspace programs. Currently, only statically defined probes -+ (USDT) are supported. -+ - config DT_PROFILE - tristate "Profile Interrupt Tracing" - default m -diff --git a/kernel/dtrace/dtrace_os.c b/kernel/dtrace/dtrace_os.c -index 931cfd0d0fbf..874e097b84fd 100644 ---- a/kernel/dtrace/dtrace_os.c -+++ b/kernel/dtrace/dtrace_os.c -@@ -40,6 +40,10 @@ - #include <linux/shmem_fs.h> - #include <linux/dtrace_task_impl.h> - -+#if IS_ENABLED(CONFIG_DT_FASTTRAP) -+# include <linux/uprobes.h> -+#endif /* CONFIG_DT_FASTTRAP || CONFIG_DT_FASTTRAP_MODULE */ -+ - /* - * OS SPECIFIC DTRACE SETUP - */ -@@ -413,3 +417,271 @@ void dtrace_disable(void) - dtrace_enabled = 0; - } - EXPORT_SYMBOL(dtrace_disable); -+ -+/* -+ * USER SPACE TRACING (FASTTRAP) SUPPORT -+ */ -+ -+#if IS_ENABLED(CONFIG_DT_FASTTRAP) -+int (*dtrace_tracepoint_hit)(struct fasttrap_machtp *, struct pt_regs *, int); -+EXPORT_SYMBOL(dtrace_tracepoint_hit); -+ -+struct task_struct *register_pid_provider(pid_t pid) -+{ -+ struct task_struct *p; -+ -+ /* -+ * Make sure the process exists, (FIXME: isn't a child created as the -+ * result of a vfork(2)), and isn't a zombie (but may be in fork). -+ */ -+ rcu_read_lock(); -+ p = find_task_by_vpid(pid); -+ if (p == NULL) { -+ rcu_read_unlock(); -+ return NULL; -+ } -+ -+ get_task_struct(p); -+ rcu_read_unlock(); -+ -+ if (p->state & TASK_DEAD || p->dt_task == NULL || -+ p->exit_state & (EXIT_ZOMBIE | EXIT_DEAD)) { -+ put_task_struct(p); -+ return NULL; -+ } -+ -+ /* -+ * Increment dtrace_probes so that the process knows to inform us -+ * when it exits or execs. fasttrap_provider_free() decrements this -+ * when we're done with this provider. -+ */ -+ if (p->dt_task != NULL) -+ p->dt_task->dt_probes++; -+ put_task_struct(p); -+ -+ return p; -+} -+EXPORT_SYMBOL(register_pid_provider); -+ -+void unregister_pid_provider(pid_t pid) -+{ -+ struct task_struct *p; -+ -+ /* -+ * Decrement dtrace_probes on the process whose provider we're -+ * freeing. We don't have to worry about clobbering somone else's -+ * modifications to it because we have locked the bucket that -+ * corresponds to this process's hash chain in the provider hash -+ * table. Don't sweat it if we can't find the process. -+ */ -+ rcu_read_lock(); -+ read_lock(&tasklist_lock); -+ if ((p = find_task_by_vpid(pid)) == NULL) { -+ read_unlock(&tasklist_lock); -+ rcu_read_unlock(); -+ return; -+ } -+ -+ get_task_struct(p); -+ read_unlock(&tasklist_lock); -+ rcu_read_unlock(); -+ -+ if (p->dt_task != NULL) -+ p->dt_task->dt_probes--; -+ put_task_struct(p); -+} -+EXPORT_SYMBOL(unregister_pid_provider); -+ -+int dtrace_copy_code(pid_t pid, uint8_t *buf, uintptr_t addr, size_t size) -+{ -+ struct task_struct *p; -+ struct inode *ino; -+ struct vm_area_struct *vma; -+ struct address_space *map; -+ loff_t off; -+ int rc = 0; -+ -+ /* -+ * First we determine the inode and offset that 'addr' refers to in the -+ * task referenced by 'pid'. -+ */ -+ rcu_read_lock(); -+ p = find_task_by_vpid(pid); -+ if (!p) { -+ rcu_read_unlock(); -+ pr_warn("PID %d not found\n", pid); -+ return -ESRCH; -+ } -+ get_task_struct(p); -+ rcu_read_unlock(); -+ -+ mmap_write_lock(p->mm); -+ vma = find_vma(p->mm, addr); -+ if (vma == NULL || vma->vm_file == NULL) { -+ rc = -EFAULT; -+ goto out; -+ } -+ -+ ino = vma->vm_file->f_mapping->host; -+ map = ino->i_mapping; -+ off = ((loff_t)vma->vm_pgoff << PAGE_SHIFT) + (addr - vma->vm_start); -+ -+ if (map->a_ops->readpage == NULL && !shmem_mapping(ino->i_mapping)) { -+ rc = -EIO; -+ goto out; -+ } -+ -+ /* -+ * Armed with inode and offset, we can start reading pages... -+ */ -+ do { -+ int len; -+ struct page *page; -+ void *kaddr; -+ -+ /* -+ * We cannot read beyond the end of the inode content. -+ */ -+ if (off >= i_size_read(ino)) -+ break; -+ -+ len = min_t(int, size, PAGE_SIZE - (off & ~PAGE_MASK)); -+ -+ /* -+ * Make sure that the page we're tring to read is populated and -+ * in page cache. -+ */ -+ if (map->a_ops->readpage) -+ page = read_mapping_page(map, off >> PAGE_SHIFT, -+ vma->vm_file); -+ else -+ page = shmem_read_mapping_page(map, off >> PAGE_SHIFT); -+ -+ if (IS_ERR(page)) { -+ rc = PTR_ERR(page); -+ break; -+ } -+ -+ kaddr = kmap_atomic(page); -+ memcpy(buf, kaddr + (off & ~PAGE_MASK), len); -+ kunmap_atomic(kaddr); -+ put_page(page); -+ -+ buf += len; -+ off += len; -+ size -= len; -+ } while (size > 0); -+ -+out: -+ mmap_write_unlock(p->mm); -+ put_task_struct(p); -+ -+ return rc; -+} -+EXPORT_SYMBOL(dtrace_copy_code); -+ -+static int handler(struct uprobe_consumer *self, struct pt_regs *regs, -+ int is_ret) -+{ -+ struct fasttrap_machtp *mtp; -+ int rc = 0; -+ -+ mtp = container_of(self, struct fasttrap_machtp, fmtp_cns); -+ -+ read_lock(&this_cpu_core->cpu_ft_lock); -+ if (dtrace_tracepoint_hit == NULL) -+ pr_warn("Fasttrap probes, but no handler\n"); -+ else -+ rc = (*dtrace_tracepoint_hit)(mtp, regs, is_ret); -+ read_unlock(&this_cpu_core->cpu_ft_lock); -+ -+ return rc; -+} -+ -+static int prb_handler(struct uprobe_consumer *self, struct pt_regs *regs) -+{ -+ return handler(self, regs, 0); -+} -+ -+static int ret_handler(struct uprobe_consumer *self, unsigned long func, -+ struct pt_regs *regs) -+{ -+ return handler(self, regs, 1); -+} -+ -+int dtrace_tracepoint_enable(pid_t pid, uintptr_t addr, int is_ret, -+ struct fasttrap_machtp *mtp) -+{ -+ struct task_struct *p; -+ struct inode *ino; -+ struct vm_area_struct *vma; -+ loff_t off; -+ int rc = 0; -+ -+ mtp->fmtp_ino = NULL; -+ mtp->fmtp_off = 0; -+ -+ p = find_task_by_vpid(pid); -+ if (!p) { -+ pr_warn("PID %d not found\n", pid); -+ return -ESRCH; -+ } -+ -+ if (p->dt_task == NULL) { -+ pr_warn("PID %d no dtrace_task\n", pid); -+ return -EFAULT; -+ } -+ -+ vma = find_vma(p->mm, addr); -+ if (vma == NULL || vma->vm_file == NULL) -+ return -EFAULT; -+ -+ ino = vma->vm_file->f_mapping->host; -+ off = ((loff_t)vma->vm_pgoff << PAGE_SHIFT) + (addr - vma->vm_start); -+ -+ if (is_ret) -+ mtp->fmtp_cns.ret_handler = ret_handler; -+ else -+ mtp->fmtp_cns.handler = prb_handler; -+ -+ rc = uprobe_register(ino, off, &mtp->fmtp_cns); -+ -+ /* -+ * If successful, increment the count of the number of -+ * tracepoints active in the victim process. -+ */ -+ if (rc == 0) { -+ mtp->fmtp_ino = ino; -+ mtp->fmtp_off = off; -+ -+ p->dt_task->dt_tp_count++; -+ } -+ -+ return rc; -+} -+EXPORT_SYMBOL(dtrace_tracepoint_enable); -+ -+int dtrace_tracepoint_disable(pid_t pid, struct fasttrap_machtp *mtp) -+{ -+ struct task_struct *p; -+ -+ if (!mtp || !mtp->fmtp_ino) -+ return -ENOENT; -+ -+ uprobe_unregister(mtp->fmtp_ino, mtp->fmtp_off, &mtp->fmtp_cns); -+ -+ mtp->fmtp_ino = NULL; -+ mtp->fmtp_off = 0; -+ -+ /* -+ * Decrement the count of the number of tracepoints active in -+ * the victim process (if it still exists). -+ */ -+ p = find_task_by_vpid(pid); -+ if (p != NULL && p->dt_task != NULL) -+ p->dt_task->dt_tp_count--; -+ -+ return 0; -+} -+EXPORT_SYMBOL(dtrace_tracepoint_disable); -+#endif /* CONFIG_DT_FASTTRAP || CONFIG_DT_FASTTRAP_MODULE */ -diff --git a/kernel/dtrace/dtrace_task.c b/kernel/dtrace/dtrace_task.c -index 02bcc6b7e0a2..8bae6e79c7f1 100644 ---- a/kernel/dtrace/dtrace_task.c -+++ b/kernel/dtrace/dtrace_task.c -@@ -22,6 +22,14 @@ - - struct kmem_cache *dtrace_task_cachep; - -+/* -+ * Fasttrap hooks that need to be called when a fasttrap meta provider -+ * is loaded and registered with the framework. -+ */ -+void (*dtrace_helpers_cleanup)(struct task_struct *); -+EXPORT_SYMBOL(dtrace_helpers_cleanup); -+void (*dtrace_fasttrap_probes_cleanup)(struct task_struct *); -+EXPORT_SYMBOL(dtrace_fasttrap_probes_cleanup); - void (*dtrace_helpers_fork)(struct task_struct *, struct task_struct *); - EXPORT_SYMBOL(dtrace_helpers_fork); - -@@ -76,6 +84,13 @@ static void dtrace_task_cleanup(struct task_struct *tsk) - if (tsk->dt_task == NULL) - return; - -+ /* Handle fasttrap provider cleanups. */ -+ if (tsk->dt_task->dt_helpers != NULL && dtrace_helpers_cleanup != NULL) -+ (*dtrace_helpers_cleanup)(tsk); -+ -+ if (tsk->dt_task->dt_probes && dtrace_fasttrap_probes_cleanup != NULL) -+ (*dtrace_fasttrap_probes_cleanup)(tsk); -+ - /* Release psinfo if any. */ - psinfo = tsk->dt_task->dt_psinfo; - if (psinfo != NULL) { --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/dtrace-patches/0013-dtrace-USDT-and-pid-providers.patch b/sys-kernel/cairn-sources/files/5.10.13/dtrace-patches/0013-dtrace-USDT-and-pid-providers.patch deleted file mode 100644 index 441bf139d28d..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/dtrace-patches/0013-dtrace-USDT-and-pid-providers.patch +++ /dev/null @@ -1,2691 +0,0 @@ -From 209f98383b9139b7d50f91f8433e50bf00c61236 Mon Sep 17 00:00:00 2001 -From: Kris Van Hees <kris.van.hees@oracle.com> -Date: Mon, 19 Nov 2018 18:08:41 +0000 -Subject: [PATCH 13/19] dtrace: USDT and pid providers - -For historical reasons, these are provided in a module named -fasttrap.ko. - -Much of this is arch-dependent code for jump-table detection and -implementation of globbed pid probes ("probe everything you can in this -function"), as well as arch-dependent code to look up arguments and code -to ensure that dropping a kprobe in a single process does not affect -other processes running from the same binary. - -Signed-off-by: Kris Van Hees <kris.van.hees@oracle.com> -Signed-off-by: Nick Alcock <nick.alcock@oracle.com> -Signed-off-by: Tomas Jedlicka <tomas.jedlicka@oracle.com> -Signed-off-by: Eugene Loh <eugene.loh@oracle.com> -Signed-off-by: David Mc Lean <david.mclean@oracle.com> -Signed-off-by: Vincent Lim <vincent.lim@oracle.com> ---- - arch/x86/dtrace/Makefile.arch | 2 + - arch/x86/dtrace/fasttrap_x86_64.c | 364 +++ - .../x86/dtrace/include/dtrace/fasttrap_arch.h | 29 + - dtrace/Makefile | 2 + - dtrace/fasttrap_dev.c | 1986 +++++++++++++++++ - dtrace/fasttrap_impl.h | 172 ++ - dtrace/fasttrap_mod.c | 38 + - 7 files changed, 2593 insertions(+) - create mode 100644 arch/x86/dtrace/fasttrap_x86_64.c - create mode 100644 arch/x86/dtrace/include/dtrace/fasttrap_arch.h - create mode 100644 dtrace/fasttrap_dev.c - create mode 100644 dtrace/fasttrap_impl.h - create mode 100644 dtrace/fasttrap_mod.c - -diff --git a/arch/x86/dtrace/Makefile.arch b/arch/x86/dtrace/Makefile.arch -index 8492eaee426d..e4655557e06a 100644 ---- a/arch/x86/dtrace/Makefile.arch -+++ b/arch/x86/dtrace/Makefile.arch -@@ -7,7 +7,9 @@ DTARCHDIR = ../arch/x86/dtrace - ccflags-y += -I$(srctree)/arch/x86/dtrace/include -Idtrace - - dtrace-obj += dtrace_asm_x86_64.o dtrace_isa_x86_64.o -+fasttrap-obj += fasttrap_x86_64.o - sdt-obj += sdt_x86_64.o - - dtrace-y += $(addprefix $(DTARCHDIR)/, $(dtrace-obj)) -+fasttrap-y += $(addprefix $(DTARCHDIR)/, $(fasttrap-obj)) - sdt-y += $(addprefix $(DTARCHDIR)/, $(sdt-obj)) -diff --git a/arch/x86/dtrace/fasttrap_x86_64.c b/arch/x86/dtrace/fasttrap_x86_64.c -new file mode 100644 -index 000000000000..012b2a50a46a ---- /dev/null -+++ b/arch/x86/dtrace/fasttrap_x86_64.c -@@ -0,0 +1,364 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: fasttrap_x86_64.c -+ * DESCRIPTION: DTrace - fasttrap provider implementation for x86 -+ * -+ * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <asm/insn.h> -+#include <linux/kernel.h> -+#include <linux/slab.h> -+#include <linux/uaccess.h> -+ -+#include "dtrace.h" -+#include "dtrace_dev.h" -+#include "fasttrap_impl.h" -+ -+#define DISASM_REX_PREFIX(pfx) (((pfx) & 0xf0) == 0x40) -+#define DISASM_MODRM_REG(modrm) (((modrm) >> 3) & 0x07) -+ -+static int has_jump_table(const asm_instr_t *addr, size_t size) -+{ -+ const asm_instr_t *end = addr + size; -+ -+ while (addr < end) { -+ int len; -+ -+ /* -+ * Register-dependent jump instructions start with a 0xff byte -+ * and have the modrm.reg field set to 4. Such instructions -+ * tend to be used for jump tables. -+ */ -+ if ((addr[0] == 0xff && DISASM_MODRM_REG(addr[1]) == 4) || -+ (DISASM_REX_PREFIX(addr[0]) && addr[1] == 0xff && -+ DISASM_MODRM_REG(addr[2]) == 4)) -+ return 1; -+ -+ len = dtrace_instr_size(addr); -+ -+ /* -+ * If we encounter a problem decoding an instruction, we will -+ * assume that there might be a jump table. Better safe than -+ * sorry... -+ */ -+ if (len < 0) -+ return 1; -+ -+ addr += len; -+ } -+ -+ return 0; -+} -+ -+static uint64_t *fasttrap_all_offsets(asm_instr_t *text, size_t size, -+ uint64_t *np) -+{ -+ uint64_t *offs = NULL; -+ uint64_t noffs; -+ asm_instr_t *instr; -+ asm_instr_t *end; -+ -+ /* -+ * Two passes are taken through this section of code. The first time -+ * around we merely count the number of probe points. The second time, -+ * we actually record their locations. -+ */ -+again: -+ noffs = 0; -+ instr = text; -+ end = text + size; -+ -+ while (instr < end) { -+ int len; -+ -+ /* -+ * If we fail to decode an instruction, it is time to give up. -+ */ -+ len = dtrace_instr_size(instr); -+ if (len < 0) -+ goto fail; -+ -+ if (offs) -+ offs[noffs] = (uint64_t)(instr - text); -+ noffs++; -+ -+ instr += len; -+ } -+ -+ if (offs == NULL) { -+ /* -+ * No matching offsets found - we are done. -+ */ -+ if (noffs == 0) -+ goto fail; -+ -+ /* -+ * We know how many tracepoint locations there are for this -+ * probe, so allocate member to record them, and kick off the -+ * second pass. -+ */ -+ offs = kmalloc(sizeof(uint64_t) * noffs, GFP_KERNEL); -+ if (!offs) -+ goto fail; -+ -+ goto again; -+ } -+ -+ *np = noffs; -+ -+ return offs; -+ -+fail: -+ *np = 0; -+ kfree(offs); -+ -+ return NULL; -+} -+ -+uint64_t *fasttrap_glob_offsets(struct fasttrap_probe_spec *probe, -+ uint64_t *np) -+{ -+ size_t size = probe->ftps_size; -+ asm_instr_t *text = NULL; -+ asm_instr_t *instr; -+ asm_instr_t *end; -+ uint64_t *offs = NULL; -+ uint64_t noffs; -+ int ret = 0; -+ char ostr[sizeof(instr) * 2 + 1]; -+ -+ text = kmalloc(size, GFP_KERNEL); -+ if (!text) -+ goto fail; -+ -+ ret = dtrace_copy_code(probe->ftps_pid, (uint8_t *)text, -+ probe->ftps_pc, size); -+ if (ret != 0) -+ goto fail; -+ -+ if (has_jump_table(text, size)) -+ goto fail; -+ -+ if (probe->ftps_glen == 1 && probe->ftps_gstr[0] == '*') { -+ offs = fasttrap_all_offsets(text, size, &noffs); -+ goto out; -+ } -+ -+ /* -+ * Two passes are taken through this section of code. The first time -+ * around we merely count the number of probe points. The second time, -+ * we actually record their locations. -+ */ -+again: -+ noffs = 0; -+ instr = text; -+ end = text + size; -+ -+ while (instr < end) { -+ int len; -+ uint64_t off = (uint64_t)(instr - text); -+ -+ /* -+ * If we fail to decode an instruction, it is time to give up. -+ */ -+ len = dtrace_instr_size(instr); -+ if (len < 0) -+ goto fail; -+ -+ snprintf(ostr, sizeof(ostr), "%llx", off); -+ if (dtrace_gmatch(ostr, probe->ftps_gstr)) { -+ if (offs) -+ offs[noffs] = off; -+ noffs++; -+ } -+ -+ instr += len; -+ } -+ -+ if (offs == NULL) { -+ /* -+ * No matching offsets found - we are done. -+ */ -+ if (noffs == 0) -+ goto fail; -+ -+ /* -+ * We know how many tracepoint locations there are for this -+ * probe, so allocate member to record them, and kick off the -+ * second pass. -+ */ -+ offs = kmalloc(sizeof(uint64_t) * noffs, GFP_KERNEL); -+ if (!offs) -+ goto fail; -+ -+ goto again; -+ } -+ -+out: -+ kfree(text); -+ -+ *np = noffs; -+ -+ return offs; -+ -+fail: -+ kfree(offs); -+ kfree(text); -+ -+ *np = 0; -+ return NULL; -+} -+ -+uint64_t fasttrap_pid_getarg(void *arg, dtrace_id_t id, void *parg, int argno, -+ int aframes) -+{ -+ struct pt_regs *regs = this_cpu_core->cpu_dtrace_regs; -+ uint64_t *st; -+ uint64_t val; -+ -+ if (regs == NULL) -+ return 0; -+ -+ switch (argno) { -+ case 0: -+ return regs->di; -+ case 1: -+ return regs->si; -+ case 2: -+ return regs->dx; -+ case 3: -+ return regs->cx; -+ case 4: -+ return regs->r8; -+ case 5: -+ return regs->r9; -+ } -+ -+ ASSERT(argno > 5); -+ -+ pagefault_disable(); -+ st = (uint64_t *)regs->sp; -+ __copy_from_user_inatomic_nocache(&val, (void *)&st[argno - 6 + 1], -+ sizeof(st[0])); -+ pagefault_enable(); -+ -+ return val; -+} -+ -+uint64_t fasttrap_usdt_getarg(void *arg, dtrace_id_t id, void *parg, -+ int argno, int aframes) -+{ -+ struct pt_regs *regs = this_cpu_core->cpu_dtrace_regs; -+ uint64_t *st; -+ uint64_t val; -+ -+ if (regs == NULL) -+ return 0; -+ -+ switch (argno) { -+ case 0: -+ return regs->di; -+ case 1: -+ return regs->si; -+ case 2: -+ return regs->dx; -+ case 3: -+ return regs->cx; -+ case 4: -+ return regs->r8; -+ case 5: -+ return regs->r9; -+ } -+ -+ ASSERT(argno > 5); -+ -+ pagefault_disable(); -+ st = (uint64_t *)regs->sp; -+ __copy_from_user_inatomic_nocache(&val, (void *)&st[argno - 6], -+ sizeof(st[0])); -+ pagefault_enable(); -+ -+ return val; -+} -+ -+static void fasttrap_map_args(struct fasttrap_probe *probe, -+ struct pt_regs *regs, -+ int argc, uintptr_t *argv) -+{ -+ int i, x, cap = min(argc, (int)probe->ftp_nargs); -+ uintptr_t *st = (uintptr_t *)regs->sp; -+ -+ for (i = 0; i < cap; i++) { -+ switch (x = probe->ftp_argmap[i]) { -+ case 0: -+ argv[i] = regs->di; -+ break; -+ case 1: -+ argv[i] = regs->si; -+ break; -+ case 2: -+ argv[i] = regs->dx; -+ break; -+ case 3: -+ argv[i] = regs->cx; -+ break; -+ case 4: -+ argv[i] = regs->r8; -+ break; -+ case 5: -+ argv[i] = regs->r9; -+ break; -+ default: -+ ASSERT(x > 5); -+ -+ __copy_from_user_inatomic_nocache(&argv[i], -+ (void *)&st[x - 6], -+ sizeof(st[0])); -+ } -+ } -+ -+ while (i < argc) -+ argv[i++] = 0; -+} -+ -+void fasttrap_pid_probe_arch(struct fasttrap_probe *ftp, struct pt_regs *regs) -+{ -+ if (ftp->ftp_argmap == NULL) { -+ dtrace_probe(ftp->ftp_id, regs->di, regs->si, regs->dx, -+ regs->cx, regs->r8, regs->r9, 0); -+ } else { -+ uintptr_t t[6]; -+ -+ fasttrap_map_args(ftp, regs, sizeof(t) / sizeof(t[0]), t); -+ dtrace_probe(ftp->ftp_id, t[0], t[1], t[2], t[3], -+ t[4], t[5], 0); -+ } -+} -+ -+void fasttrap_pid_retprobe_arch(struct fasttrap_probe *ftp, -+ struct pt_regs *regs) -+{ -+ /* -+ * FIXME: The first argument to the probe should be the offset in the -+ * function that the return occured at, but uprobes doesn't give -+ * us that information (or so it seems). -+ */ -+ dtrace_probe(ftp->ftp_id, 0, regs->ax, regs->dx, 0, 0, 0, 0); -+} -+ -+void fasttrap_set_enabled(struct pt_regs *regs) -+{ -+ regs->ax = 1; -+} -+ -diff --git a/arch/x86/dtrace/include/dtrace/fasttrap_arch.h b/arch/x86/dtrace/include/dtrace/fasttrap_arch.h -new file mode 100644 -index 000000000000..abbe9cb2bf38 ---- /dev/null -+++ b/arch/x86/dtrace/include/dtrace/fasttrap_arch.h -@@ -0,0 +1,29 @@ -+/* -+ * Dynamic Tracing for Linux - Fasttrap provider implementation defines -+ * -+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _X86_64_FASTTRAP_ARCH_H -+#define _X86_64_FASTTRAP_ARCH_H -+ -+#define FASTTRAP_ENTRY_AFRAMES 8 -+#define FASTTRAP_RETURN_AFRAMES 8 -+#define FASTTRAP_OFFSET_AFRAMES 8 -+ -+#endif /* _X86_64_FASTTRAP_ARCH_H */ -diff --git a/dtrace/Makefile b/dtrace/Makefile -index 5e6fb362a4e9..c7e3fc512a6c 100644 ---- a/dtrace/Makefile -+++ b/dtrace/Makefile -@@ -3,6 +3,7 @@ - # - - obj-$(CONFIG_DT_CORE) += dtrace.o -+obj-$(CONFIG_DT_FASTTRAP) += fasttrap.o - obj-$(CONFIG_DT_PROFILE) += profile.o - obj-$(CONFIG_DT_SDT) += sdt.o - obj-$(CONFIG_DT_SYSTRACE) += systrace.o -@@ -17,6 +18,7 @@ dtrace-y := dtrace_mod.o dtrace_dev.o \ - dtrace_probe.o dtrace_probe_ctx.o \ - dtrace_ptofapi.o dtrace_predicate.o \ - dtrace_spec.o dtrace_state.o dtrace_util.o -+fasttrap-y := fasttrap_mod.o fasttrap_dev.o - profile-y := profile_mod.o profile_dev.o - sdt-y := sdt_mod.o sdt_dev.o - systrace-y := systrace_mod.o systrace_dev.o -diff --git a/dtrace/fasttrap_dev.c b/dtrace/fasttrap_dev.c -new file mode 100644 -index 000000000000..f48581e00f4b ---- /dev/null -+++ b/dtrace/fasttrap_dev.c -@@ -0,0 +1,1986 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: fasttrap_dev.c -+ * DESCRIPTION: DTrace - fasttrap provider device driver -+ * -+ * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/atomic.h> -+#include <linux/fs.h> -+#include <linux/miscdevice.h> -+#include <linux/slab.h> -+#include <linux/sort.h> -+#include <linux/uaccess.h> -+#include <linux/vmalloc.h> -+#include <linux/workqueue.h> -+ -+#include "dtrace.h" -+#include "dtrace_dev.h" -+#include "fasttrap_impl.h" -+ -+#define FASTTRAP_MAX_DEFAULT 250000 -+static uint32_t fasttrap_max; -+static uint64_t fasttrap_pid_count; -+static atomic_t fasttrap_total; -+ -+#define FASTTRAP_TPOINTS_DEFAULT_SIZE 0x4000 -+#define FASTTRAP_PROVIDERS_DEFAULT_SIZE 0x100 -+#define FASTTRAP_PROCS_DEFAULT_SIZE 0x100 -+ -+#define FASTTRAP_PID_NAME "pid" -+#define FASTTRAP_ENABLE_FAIL 1 -+#define FASTTRAP_ENABLE_PARTIAL 2 -+ -+struct fasttrap_hash fasttrap_tpoints; -+static struct fasttrap_hash fasttrap_provs; -+static struct fasttrap_hash fasttrap_procs; -+ -+#define FASTTRAP_PROVS_INDEX(pid, name) \ -+ ((fasttrap_hash_str(name) + (pid)) & fasttrap_provs.fth_mask) -+#define FASTTRAP_PROCS_INDEX(pid) ((pid) & fasttrap_procs.fth_mask) -+ -+#define FASTTRAP_TPOINTS_ELEM(pid, pc) \ -+ FASTTRAP_ELEM_BUCKET(&fasttrap_tpoints.fth_table[FASTTRAP_TPOINTS_INDEX(pid, pc)]) -+#define FASTTRAP_PROVS_ELEM(pid, name) \ -+ FASTTRAP_ELEM_BUCKET(&fasttrap_provs.fth_table[FASTTRAP_PROVS_INDEX(pid, name)]) -+#define FASTTRAP_PROCS_ELEM(pid) \ -+ FASTTRAP_ELEM_BUCKET(&fasttrap_procs.fth_table[FASTTRAP_PROCS_INDEX(pid)]) -+ -+#define CLEANUP_NONE 0 -+#define CLEANUP_SCHEDULED 1 -+#define CLEANUP_DEFERRED 2 -+ -+DEFINE_MUTEX(fasttrap_cleanup_mtx); -+DEFINE_MUTEX(fasttrap_count_mtx); -+static uint_t fasttrap_cleanup_state; -+static uint_t fasttrap_cleanup_work; -+ -+static struct kmem_cache *tracepoint_cachep; -+ -+/* -+ * Generation count on modifications to the global tracepoint lookup table. -+ */ -+static volatile uint64_t fasttrap_mod_gen; -+ -+static void fasttrap_pid_cleanup(void); -+static void fasttrap_probes_cleanup(struct task_struct *); -+ -+static int fasttrap_pid_probe(struct fasttrap_machtp *mtp, -+ struct pt_regs *regs, int is_ret) -+{ -+ struct fasttrap_tracepoint *tp; -+ struct fasttrap_id *id; -+ int is_enabled = 0; -+ -+ tp = container_of(mtp, struct fasttrap_tracepoint, ftt_mtp); -+ -+ /* -+ * Verify that this probe event is actually related to the current -+ * process (task group). If not, ignore it. -+ * -+ * TODO: The underlying probe mechanism should register a single -+ * handler for the (inode, offset) combination. When the handler -+ * is called, it should run through a list of fasttrap -+ * tracepoints associated with the OS-level probe, looking for -+ * one that is related to the current task. -+ */ -+ if (tp->ftt_pid != current->tgid) -+ return 0; -+ -+ if (atomic64_read(&tp->ftt_proc->ftpc_acount) == 0) -+ return 0; -+ -+ this_cpu_core->cpu_dtrace_regs = regs; -+ -+ if (!is_ret) { -+ for (id = tp->ftt_ids; id != NULL; id = id->fti_next) { -+ struct fasttrap_probe *ftp = id->fti_probe; -+ -+ if (id->fti_ptype == DTFTP_IS_ENABLED) -+ is_enabled = 1; -+ else -+ fasttrap_pid_probe_arch(ftp, regs); -+ } -+ } else { -+ for (id = tp->ftt_retids; id != NULL; id = id->fti_next) { -+ struct fasttrap_probe *ftp = id->fti_probe; -+ -+ fasttrap_pid_retprobe_arch(ftp, regs); -+ } -+ } -+ -+ this_cpu_core->cpu_dtrace_regs = NULL; -+ -+ if (is_enabled) -+ fasttrap_set_enabled(regs); -+ -+ return 0; -+} -+ -+static void fasttrap_pid_provide(void *arg, -+ const struct dtrace_probedesc *desc) -+{ -+ /* -+ * There are no "default" pid probes. -+ */ -+} -+ -+static void fasttrap_enable_callbacks(void) -+{ -+ /* -+ * We don't have to play the RW lock game here because we're providing -+ * something rather than taking something away -- we can be sure that -+ * no threads have tried to follow these function pointers yet. -+ */ -+ mutex_lock(&fasttrap_count_mtx); -+ if (fasttrap_pid_count == 0) { -+ ASSERT(dtrace_tracepoint_hit == NULL); -+ -+ dtrace_fasttrap_probes_cleanup = &fasttrap_probes_cleanup; -+ dtrace_tracepoint_hit = &fasttrap_pid_probe; -+ } -+ -+ ASSERT(dtrace_fasttrap_probes_cleanup == &fasttrap_probes_cleanup); -+ ASSERT(dtrace_tracepoint_hit == &fasttrap_pid_probe); -+ -+ fasttrap_pid_count++; -+ mutex_unlock(&fasttrap_count_mtx); -+} -+ -+static void fasttrap_disable_callbacks(void) -+{ -+ ASSERT(MUTEX_HELD(&cpu_lock)); -+ -+ mutex_lock(&fasttrap_count_mtx); -+ ASSERT(fasttrap_pid_count > 0); -+ fasttrap_pid_count--; -+ -+ if (fasttrap_pid_count == 0) { -+ int cpu; -+ -+ for_each_present_cpu(cpu) { -+ struct cpu_core *cpuc = per_cpu_core(cpu); -+ -+ write_lock(&cpuc->cpu_ft_lock); -+ } -+ -+ dtrace_tracepoint_hit = NULL; -+ dtrace_fasttrap_probes_cleanup = NULL; -+ -+ for_each_present_cpu(cpu) { -+ struct cpu_core *cpuc = per_cpu_core(cpu); -+ -+ write_unlock(&cpuc->cpu_ft_lock); -+ } -+ } -+ -+ mutex_unlock(&fasttrap_count_mtx); -+} -+ -+/* -+ * This function ensures that no threads are actively using the memory -+ * associated with probes that were formerly live. -+ */ -+static void fasttrap_mod_barrier(uint64_t gen) -+{ -+ int cpu; -+ -+ if (gen < fasttrap_mod_gen) -+ return; -+ -+ fasttrap_mod_gen++; -+ -+ for_each_present_cpu(cpu) { -+ struct cpu_core *cpuc = per_cpu_core(cpu); -+ -+ mutex_lock(&cpuc->cpuc_pid_lock); -+ mutex_unlock(&cpuc->cpuc_pid_lock); -+ } -+} -+ -+static int fasttrap_tracepoint_enable(struct fasttrap_probe *probe, -+ uint_t index) -+{ -+ struct fasttrap_tracepoint *tp, *new_tp = NULL; -+ struct fasttrap_bucket *bucket; -+ struct fasttrap_id *id; -+ pid_t pid; -+ uintptr_t pc; -+ -+ ASSERT(index < probe->ftp_ntps); -+ -+ pid = probe->ftp_pid; -+ pc = probe->ftp_tps[index].fit_tp->ftt_pc; -+ id = &probe->ftp_tps[index].fit_id; -+ -+ ASSERT(probe->ftp_tps[index].fit_tp->ftt_pid == pid); -+ -+ /* -+ * Before we make any modifications, make sure we've imposed a barrier -+ * on the generation in which this probe was last modified. -+ */ -+ fasttrap_mod_barrier(probe->ftp_gen); -+ -+ bucket = FASTTRAP_TPOINTS_ELEM(pid, pc); -+ -+ /* -+ * If the tracepoint has already been enabled, just add our id to the -+ * list of interested probes. This may be our second time through -+ * this path in which case we'll have constructed the tracepoint we'd -+ * like to install. If we can't find a match, and have an allocated -+ * tracepoint ready to go, enable that one now. -+ * -+ * A tracepoint whose process is defunct is also considered defunct. -+ */ -+again: -+ mutex_lock(&bucket->ftb_mtx); -+ for (tp = bucket->ftb_data; tp != NULL; tp = tp->ftt_next) { -+ /* -+ * Note that it's safe to access the active count on the -+ * associated proc structure because we know that at least one -+ * provider (this one) will still be around throughout this -+ * operation. -+ */ -+ if (tp->ftt_pid != pid || tp->ftt_pc != pc || -+ atomic64_read(&tp->ftt_proc->ftpc_acount) == 0) -+ continue; -+ -+ /* -+ * Now that we've found a matching tracepoint, it would be -+ * a decent idea to confirm that the tracepoint is still -+ * enabled and the trap instruction hasn't been overwritten. -+ * Since this is a little hairy, we'll punt for now. -+ */ -+ -+ /* -+ * This can't be the first interested probe. We don't have -+ * to worry about another thread being in the midst of -+ * deleting this tracepoint (which would be the only valid -+ * reason for a tracepoint to have no interested probes) -+ * since we're holding P_PR_LOCK for this process. -+ */ -+ ASSERT(tp->ftt_ids != NULL || tp->ftt_retids != NULL); -+ -+ switch (id->fti_ptype) { -+ case DTFTP_ENTRY: -+ case DTFTP_OFFSETS: -+ case DTFTP_IS_ENABLED: -+ if (tp->ftt_ids == NULL) /* return tp */ -+ continue; -+ -+ ASSERT(tp->ftt_retids == NULL); -+ -+ id->fti_next = tp->ftt_ids; -+ dtrace_membar_producer(); -+ tp->ftt_ids = id; -+ dtrace_membar_producer(); -+ break; -+ -+ case DTFTP_RETURN: -+ case DTFTP_POST_OFFSETS: -+ if (tp->ftt_retids == NULL) /* non-return tp */ -+ continue; -+ -+ ASSERT(tp->ftt_ids == NULL); -+ -+ id->fti_next = tp->ftt_retids; -+ dtrace_membar_producer(); -+ tp->ftt_retids = id; -+ dtrace_membar_producer(); -+ break; -+ -+ default: -+ ASSERT(0); /* FIXME */ -+ } -+ -+ mutex_unlock(&bucket->ftb_mtx); -+ -+ if (new_tp != NULL) { -+ new_tp->ftt_ids = NULL; -+ new_tp->ftt_retids = NULL; -+ } -+ -+ return 0; -+ } -+ -+ /* -+ * If we have a good tracepoint ready to go, install it now while -+ * we have the lock held and no one can screw with us. -+ */ -+ if (new_tp != NULL) { -+ int rc = 0; -+ -+ new_tp->ftt_next = bucket->ftb_data; -+ dtrace_membar_producer(); -+ bucket->ftb_data = new_tp; -+ dtrace_membar_producer(); -+ mutex_unlock(&bucket->ftb_mtx); -+ -+ /* -+ * Activate the tracepoint in the ISA-specific manner. -+ * If this fails, we need to report the failure, but -+ * indicate that this tracepoint must still be disabled -+ * by calling fasttrap_tracepoint_disable(). -+ */ -+ rc = dtrace_tracepoint_enable(pid, pc, -+ id->fti_ptype == DTFTP_RETURN, -+ &new_tp->ftt_mtp); -+ -+ return rc ? FASTTRAP_ENABLE_PARTIAL : 0; -+ } -+ -+ mutex_unlock(&bucket->ftb_mtx); -+ -+ /* -+ * Initialize the tracepoint that's been preallocated with the probe. -+ */ -+ new_tp = probe->ftp_tps[index].fit_tp; -+ -+ ASSERT(new_tp->ftt_pid == pid); -+ ASSERT(new_tp->ftt_pc == pc); -+ ASSERT(new_tp->ftt_proc == probe->ftp_prov->ftp_proc); -+ ASSERT(new_tp->ftt_ids == NULL); -+ ASSERT(new_tp->ftt_retids == NULL); -+ -+ switch (id->fti_ptype) { -+ case DTFTP_ENTRY: -+ case DTFTP_OFFSETS: -+ case DTFTP_IS_ENABLED: -+ id->fti_next = NULL; -+ new_tp->ftt_ids = id; -+ break; -+ -+ case DTFTP_RETURN: -+ case DTFTP_POST_OFFSETS: -+ id->fti_next = NULL; -+ new_tp->ftt_retids = id; -+ break; -+ -+ default: -+ ASSERT(0); -+ } -+ -+ goto again; -+} -+ -+static void fasttrap_tracepoint_disable(struct fasttrap_probe *probe, -+ uint_t index) -+{ -+ struct fasttrap_bucket *bucket; -+ struct fasttrap_provider *prov = probe->ftp_prov; -+ struct fasttrap_tracepoint **pp, *tp; -+ struct fasttrap_id *id, **idp = NULL; -+ pid_t pid; -+ uintptr_t pc; -+ -+ ASSERT(index < probe->ftp_ntps); -+ -+ pid = probe->ftp_pid; -+ pc = probe->ftp_tps[index].fit_tp->ftt_pc; -+ id = &probe->ftp_tps[index].fit_id; -+ -+ ASSERT(probe->ftp_tps[index].fit_tp->ftt_pid == pid); -+ -+ /* -+ * Find the tracepoint and make sure that our id is one of the -+ * ones registered with it. Return probes are linked in their -+ * own tracepoint, even though they share the (pi, pc) pair with -+ * entry probes. -+ */ -+ bucket = FASTTRAP_TPOINTS_ELEM(pid, pc); -+ mutex_lock(&bucket->ftb_mtx); -+ for (tp = bucket->ftb_data; tp != NULL; tp = tp->ftt_next) { -+ if (tp->ftt_pid != pid || tp->ftt_pc != pc || -+ tp->ftt_proc != prov->ftp_proc) -+ continue; -+ -+ if (id->fti_ptype == DTFTP_RETURN && tp->ftt_retids == NULL) -+ continue; -+ -+ if (id->fti_ptype != DTFTP_RETURN && tp->ftt_ids == NULL) -+ continue; -+ -+ break; -+ } -+ -+ /* -+ * If we somehow lost this tracepoint, we are in trouble. -+ */ -+ ASSERT(tp != NULL); -+ -+ switch (id->fti_ptype) { -+ case DTFTP_ENTRY: -+ case DTFTP_OFFSETS: -+ case DTFTP_IS_ENABLED: -+ ASSERT(tp->ftt_ids != NULL); -+ idp = &tp->ftt_ids; -+ break; -+ -+ case DTFTP_RETURN: -+ case DTFTP_POST_OFFSETS: -+ ASSERT(tp->ftt_retids != NULL); -+ idp = &tp->ftt_retids; -+ break; -+ -+ default: -+ ASSERT(0); -+ } -+ -+ while ((*idp)->fti_probe != probe) { -+ idp = &(*idp)->fti_next; -+ ASSERT(*idp != NULL); -+ } -+ -+ id = *idp; -+ *idp = id->fti_next; -+ dtrace_membar_producer(); -+ -+ ASSERT(id->fti_probe == probe); -+ -+ /* -+ * If there are other registered enablings of this tracepoint, we're -+ * all done, but if this was the last probe assocated with this -+ * this tracepoint, we need to remove and free it. -+ */ -+ if (tp->ftt_ids != NULL || tp->ftt_retids != NULL) { -+ /* -+ * If the current probe's tracepoint is in use, swap it -+ * for an unused tracepoint. -+ */ -+ if (tp == probe->ftp_tps[index].fit_tp) { -+ struct fasttrap_probe *tmp_probe; -+ struct fasttrap_tracepoint **tmp_tp; -+ uint_t tmp_index; -+ -+ if (tp->ftt_ids != NULL) { -+ tmp_probe = tp->ftt_ids->fti_probe; -+ tmp_index = FASTTRAP_ID_INDEX(tp->ftt_ids); -+ tmp_tp = &tmp_probe->ftp_tps[tmp_index].fit_tp; -+ } else { -+ tmp_probe = tp->ftt_retids->fti_probe; -+ tmp_index = FASTTRAP_ID_INDEX(tp->ftt_retids); -+ tmp_tp = &tmp_probe->ftp_tps[tmp_index].fit_tp; -+ } -+ -+ ASSERT(*tmp_tp != NULL); -+ ASSERT(*tmp_tp != probe->ftp_tps[index].fit_tp); -+ ASSERT((*tmp_tp)->ftt_ids == NULL); -+ ASSERT((*tmp_tp)->ftt_retids == NULL); -+ -+ probe->ftp_tps[index].fit_tp = *tmp_tp; -+ *tmp_tp = tp; -+ } -+ -+ mutex_unlock(&bucket->ftb_mtx); -+ -+ /* -+ * Tag the modified probe with the generation in which it was -+ * changed. -+ */ -+ probe->ftp_gen = fasttrap_mod_gen; -+ return; -+ } -+ -+ mutex_unlock(&bucket->ftb_mtx); -+ -+ dtrace_tracepoint_disable(pid, &tp->ftt_mtp); -+ -+ /* -+ * Remove the probe from the hash table of active tracepoints. -+ */ -+ mutex_lock(&bucket->ftb_mtx); -+ pp = (struct fasttrap_tracepoint **)&bucket->ftb_data; -+ ASSERT(*pp != NULL); -+ while (*pp != tp) { -+ pp = &(*pp)->ftt_next; -+ ASSERT(*pp != NULL); -+ } -+ -+ *pp = tp->ftt_next; -+ dtrace_membar_producer(); -+ -+ mutex_unlock(&bucket->ftb_mtx); -+ -+ /* -+ * Tag the modified probe with the generation in which it was changed. -+ */ -+ probe->ftp_gen = fasttrap_mod_gen; -+} -+ -+static int fasttrap_pid_enable(void *arg, dtrace_id_t id, void *parg) -+{ -+ struct fasttrap_probe *probe = parg; -+ int i, rc; -+ -+ ASSERT(probe != NULL); -+ ASSERT(!probe->ftp_enabled); -+ ASSERT(id == probe->ftp_id); -+ ASSERT(MUTEX_HELD(&cpu_lock)); -+ -+ /* -+ * Increment the count of enabled probes on this probe's provider; -+ * the provider can't go away while the probe still exists. We -+ * must increment this even if we aren't able to properly enable -+ * this probe. -+ */ -+ mutex_lock(&probe->ftp_prov->ftp_mtx); -+ probe->ftp_prov->ftp_rcount++; -+ mutex_unlock(&probe->ftp_prov->ftp_mtx); -+ -+ /* -+ * If this probe's provider is retired (meaning it was valid in a -+ * previously exec'ed incarnation of this address space), bail out. The -+ * provider can't go away while we're in this code path. -+ */ -+ if (probe->ftp_prov->ftp_retired) -+ return 0; -+ -+#ifdef FIXME -+ /* -+ * If we can't find the process, it may be that we're in the context of -+ * a fork in which the traced process is being born and we're copying -+ * USDT probes. Otherwise, the process is gone so bail. -+ */ -+ p = sprlock(probe->ftp_pid); -+ if (p == NULL) { -+ if ((curproc->p_flag & SFORKING) == 0) -+ return 0; -+ -+ mutex_enter(&pidlock); -+ p = prfind(probe->ftp_pid); -+ -+ /* -+ * Confirm that curproc is indeed forking the process in which -+ * we're trying to enable probes. -+ */ -+ ASSERT(p != NULL); -+ ASSERT(p->p_parent == curproc); -+ ASSERT(p->p_stat == SIDL); -+ -+ mutex_enter(&p->p_lock); -+ mutex_exit(&pidlock); -+ -+ sprlock_proc(p); -+ } -+ -+ ASSERT(!(p->p_flag & SVFORK)); -+ mutex_exit(&p->p_lock); -+#endif -+ -+ /* -+ * We have to enable the trap entry point before any user threads have -+ * the chance to execute the trap instruction we're about to place -+ * in their process's text. -+ */ -+ fasttrap_enable_callbacks(); -+ -+ /* -+ * Enable all the tracepoints and add this probe's id to each -+ * tracepoint's list of active probes. -+ */ -+ for (i = 0; i < probe->ftp_ntps; i++) { -+ rc = fasttrap_tracepoint_enable(probe, i); -+ if (rc != 0) { -+ /* -+ * If enabling the tracepoint failed completely, -+ * we don't have to disable it; if the failure -+ * was only partial we must disable it. -+ */ -+ if (rc == FASTTRAP_ENABLE_FAIL) -+ i--; -+ else -+ ASSERT(rc == FASTTRAP_ENABLE_PARTIAL); -+ -+ /* -+ * Back up and pull out all the tracepoints we've -+ * created so far for this probe. -+ */ -+ while (i >= 0) { -+ fasttrap_tracepoint_disable(probe, i); -+ i--; -+ } -+ -+#ifdef FIXME -+ mutex_enter(&p->p_lock); -+ sprunlock(p); -+#endif -+ -+ /* -+ * Since we're not actually enabling this probe, -+ * drop our reference on the trap table entry. -+ */ -+ fasttrap_disable_callbacks(); -+ return 0; -+ } -+ } -+ -+#ifdef FIXME -+ mutex_enter(&p->p_lock); -+ sprunlock(p); -+#endif -+ -+ probe->ftp_enabled = 1; -+ return 0; -+} -+ -+static void fasttrap_pid_disable(void *arg, dtrace_id_t id, void *parg) -+{ -+ struct fasttrap_probe *probe = parg; -+ struct fasttrap_provider *prov = probe->ftp_prov; -+ int i, whack = 0; -+ -+ ASSERT(id == probe->ftp_id); -+ -+ mutex_lock(&prov->ftp_mtx); -+ -+ /* -+ * Disable all the associated tracepoints (for fully enabled probes). -+ */ -+ if (probe->ftp_enabled) { -+ for (i = 0; i < probe->ftp_ntps; i++) -+ fasttrap_tracepoint_disable(probe, i); -+ } -+ -+ ASSERT(prov->ftp_rcount > 0); -+ prov->ftp_rcount--; -+ -+ if ((prov->ftp_retired || prov->ftp_rcount == 0) && !prov->ftp_marked) -+ whack = prov->ftp_marked = 1; -+ -+ mutex_unlock(&prov->ftp_mtx); -+ -+ if (whack) -+ fasttrap_pid_cleanup(); -+ -+ if (!probe->ftp_enabled) -+ return; -+ -+ probe->ftp_enabled = 0; -+ -+ ASSERT(MUTEX_HELD(&cpu_lock)); -+ fasttrap_disable_callbacks(); -+} -+ -+static void fasttrap_pid_getargdesc(void *arg, dtrace_id_t id, void *parg, -+ struct dtrace_argdesc *desc) -+{ -+ struct fasttrap_probe *probe = parg; -+ char *str; -+ int i, ndx; -+ -+ desc->dtargd_native[0] = '\0'; -+ desc->dtargd_xlate[0] = '\0'; -+ -+ if (probe->ftp_prov->ftp_retired != 0 || -+ desc->dtargd_ndx >= probe->ftp_nargs) { -+ desc->dtargd_ndx = DTRACE_ARGNONE; -+ return; -+ } -+ -+ ndx = (probe->ftp_argmap != NULL) ? probe->ftp_argmap[desc->dtargd_ndx] -+ : desc->dtargd_ndx; -+ -+ str = probe->ftp_ntypes; -+ for (i = 0; i < ndx; i++) -+ str += strlen(str) + 1; -+ -+ ASSERT(strlen(str + 1) < sizeof(desc->dtargd_native)); -+ strcpy(desc->dtargd_native, str); -+ -+ if (probe->ftp_xtypes == NULL) -+ return; -+ -+ str = probe->ftp_xtypes; -+ for (i = 0; i < desc->dtargd_ndx; i++) -+ str += strlen(str) + 1; -+ -+ ASSERT(strlen(str + 1) < sizeof(desc->dtargd_xlate)); -+ strcpy(desc->dtargd_xlate, str); -+} -+ -+static void fasttrap_pid_destroy(void *arg, dtrace_id_t id, void *parg) -+{ -+ struct fasttrap_probe *probe = parg; -+ int i; -+ -+ ASSERT(probe != NULL); -+ ASSERT(!probe->ftp_enabled); -+ ASSERT(atomic_read(&fasttrap_total) >= probe->ftp_ntps); -+ -+ atomic_add(-probe->ftp_ntps, &fasttrap_total); -+ -+ if (probe->ftp_gen + 1 >= fasttrap_mod_gen) -+ fasttrap_mod_barrier(probe->ftp_gen); -+ -+ for (i = 0; i < probe->ftp_ntps; i++) -+ kmem_cache_free(tracepoint_cachep, probe->ftp_tps[i].fit_tp); -+ -+ kfree(probe); -+} -+ -+static const struct dtrace_pattr pid_attr = { -+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+}; -+ -+static struct dtrace_pops pid_pops = { -+ .dtps_provide = fasttrap_pid_provide, -+ .dtps_provide_module = NULL, -+ .dtps_destroy_module = NULL, -+ .dtps_enable = fasttrap_pid_enable, -+ .dtps_disable = fasttrap_pid_disable, -+ .dtps_suspend = NULL, -+ .dtps_resume = NULL, -+ .dtps_getargdesc = fasttrap_pid_getargdesc, -+ .dtps_getargval = fasttrap_pid_getarg, -+ .dtps_usermode = NULL, -+ .dtps_destroy = fasttrap_pid_destroy -+}; -+ -+static struct dtrace_pops usdt_pops = { -+ .dtps_provide = fasttrap_pid_provide, -+ .dtps_provide_module = NULL, -+ .dtps_destroy_module = NULL, -+ .dtps_enable = fasttrap_pid_enable, -+ .dtps_disable = fasttrap_pid_disable, -+ .dtps_suspend = NULL, -+ .dtps_resume = NULL, -+ .dtps_getargdesc = fasttrap_pid_getargdesc, -+ .dtps_getargval = fasttrap_usdt_getarg, -+ .dtps_usermode = NULL, -+ .dtps_destroy = fasttrap_pid_destroy -+}; -+ -+static uint_t fasttrap_hash_str(const char *p) -+{ -+ unsigned int g; -+ uint_t hval = 0; -+ -+ while (*p) { -+ hval = (hval << 4) + *p++; -+ g = hval & 0xf0000000; -+ if (g != 0) -+ hval ^= g >> 24; -+ hval &= ~g; -+ } -+ -+ return hval; -+} -+ -+static int fasttrap_uint32_cmp(const void *ap, const void *bp) -+{ -+ return (*(const uint32_t *)ap - *(const uint32_t *)bp); -+} -+ -+void fasttrap_meta_create_probe(void *arg, void *parg, -+ struct dtrace_helper_probedesc *dhpb) -+{ -+ struct fasttrap_provider *provider = parg; -+ struct fasttrap_probe *pp; -+ struct fasttrap_tracepoint *tp; -+ int i, j; -+ uint32_t ntps; -+ -+ /* -+ * Since the meta provider count is non-zero we don't have to worry -+ * about this provider disappearing. -+ */ -+ ASSERT(provider->ftp_mcount > 0); -+ -+ /* -+ * The offsets must be unique. -+ */ -+ sort(dhpb->dthpb_offs, dhpb->dthpb_noffs, sizeof(uint32_t), -+ fasttrap_uint32_cmp, NULL); -+ for (i = 1; i < dhpb->dthpb_noffs; i++) { -+ if (dhpb->dthpb_base + dhpb->dthpb_offs[i] <= -+ dhpb->dthpb_base + dhpb->dthpb_offs[i - 1]) -+ return; -+ } -+ -+ sort(dhpb->dthpb_enoffs, dhpb->dthpb_nenoffs, sizeof(uint32_t), -+ fasttrap_uint32_cmp, NULL); -+ for (i = 1; i < dhpb->dthpb_nenoffs; i++) { -+ if (dhpb->dthpb_base + dhpb->dthpb_enoffs[i] <= -+ dhpb->dthpb_base + dhpb->dthpb_enoffs[i - 1]) -+ return; -+ } -+ -+ /* -+ * Grab the creation lock to ensure consistency between calls to -+ * dtrace_probe_lookup() and dtrace_probe_create() in the face of -+ * other threads creating probes. -+ */ -+ mutex_lock(&provider->ftp_cmtx); -+ -+ if (dtrace_probe_lookup(provider->ftp_provid, dhpb->dthpb_mod, -+ dhpb->dthpb_func, dhpb->dthpb_name) != DTRACE_IDNONE) { -+ mutex_unlock(&provider->ftp_cmtx); -+ return; -+ } -+ -+ ntps = dhpb->dthpb_noffs + dhpb->dthpb_nenoffs; -+ ASSERT(ntps > 0); -+ -+ pp = kzalloc(offsetof(struct fasttrap_probe, ftp_tps[ntps]), -+ GFP_KERNEL); -+ if (pp == NULL) { -+ pr_warn("Unable to create probe %s: out of memory\n", -+ dhpb->dthpb_name); -+ mutex_unlock(&provider->ftp_cmtx); -+ return; -+ } -+ -+ atomic_add(ntps, &fasttrap_total); -+ if (atomic_read(&fasttrap_total) > fasttrap_max) { -+ kfree(pp); -+ atomic_add(-ntps, &fasttrap_total); -+ mutex_unlock(&provider->ftp_cmtx); -+ return; -+ } -+ -+ pp->ftp_prov = provider; -+ pp->ftp_pid = provider->ftp_pid; -+ pp->ftp_ntps = ntps; -+ pp->ftp_nargs = dhpb->dthpb_xargc; -+ pp->ftp_xtypes = dhpb->dthpb_xtypes; -+ pp->ftp_ntypes = dhpb->dthpb_ntypes; -+ -+ /* -+ * First create a tracepoint for each actual point of interest. -+ */ -+ for (i = 0; i < dhpb->dthpb_noffs; i++) { -+ tp = kmem_cache_alloc(tracepoint_cachep, GFP_KERNEL); -+ if (tp == NULL) -+ goto fail; -+ -+ tp->ftt_proc = provider->ftp_proc; -+ tp->ftt_pc = dhpb->dthpb_base + dhpb->dthpb_offs[i]; -+ tp->ftt_pid = provider->ftp_pid; -+ memset(&tp->ftt_mtp, 0, sizeof(struct fasttrap_machtp)); -+ tp->ftt_ids = NULL; -+ tp->ftt_retids = NULL; -+ tp->ftt_next = NULL; -+ -+ dt_dbg_dof(" Tracepoint at 0x%lx (0x%llx + 0x%x)\n", -+ tp->ftt_pc, dhpb->dthpb_base, dhpb->dthpb_offs[i]); -+ -+ pp->ftp_tps[i].fit_tp = tp; -+ pp->ftp_tps[i].fit_id.fti_probe = pp; -+ pp->ftp_tps[i].fit_id.fti_ptype = DTFTP_OFFSETS; -+ } -+ -+ /* -+ * Then create a tracepoint for each is-enabled point. -+ */ -+ for (j = 0; i < ntps; i++, j++) { -+ tp = kmem_cache_alloc(tracepoint_cachep, GFP_KERNEL); -+ if (tp == NULL) -+ goto fail; -+ -+ tp->ftt_proc = provider->ftp_proc; -+ tp->ftt_pc = dhpb->dthpb_base + dhpb->dthpb_enoffs[j]; -+ tp->ftt_pid = provider->ftp_pid; -+ memset(&tp->ftt_mtp, 0, sizeof(struct fasttrap_machtp)); -+ tp->ftt_ids = NULL; -+ tp->ftt_retids = NULL; -+ tp->ftt_next = NULL; -+ -+ pp->ftp_tps[i].fit_tp = tp; -+ pp->ftp_tps[i].fit_id.fti_probe = pp; -+ pp->ftp_tps[i].fit_id.fti_ptype = DTFTP_IS_ENABLED; -+ } -+ -+ /* -+ * If the arguments are shuffled around we set the argument remapping -+ * table. Later, when the probe fires, we only remap the arguments -+ * if the table is non-NULL. -+ */ -+ for (i = 0; i < dhpb->dthpb_xargc; i++) { -+ if (dhpb->dthpb_args[i] != i) { -+ pp->ftp_argmap = dhpb->dthpb_args; -+ break; -+ } -+ } -+ -+ /* -+ * The probe is fully constructed -- register it with DTrace. -+ */ -+ pp->ftp_id = dtrace_probe_create(provider->ftp_provid, dhpb->dthpb_mod, -+ dhpb->dthpb_func, dhpb->dthpb_name, -+ FASTTRAP_OFFSET_AFRAMES, pp); -+ if (pp->ftp_id == DTRACE_IDNONE) -+ goto fail; -+ -+ mutex_unlock(&provider->ftp_cmtx); -+ return; -+ -+fail: -+ pr_warn("Unable to create probe %s: out of memory\n", -+ dhpb->dthpb_name); -+ -+ for (i = 0; i < ntps; i++) -+ kmem_cache_free(tracepoint_cachep, pp->ftp_tps[i].fit_tp); -+ -+ kfree(pp); -+ atomic_add(-ntps, &fasttrap_total); -+ mutex_unlock(&provider->ftp_cmtx); -+} -+ -+static void fasttrap_proc_release(struct fasttrap_proc *proc) -+{ -+ struct fasttrap_bucket *bucket; -+ struct fasttrap_proc *fprc, **fprcp; -+ pid_t pid = proc->ftpc_pid; -+ -+ mutex_lock(&proc->ftpc_mtx); -+ -+ ASSERT(proc->ftpc_rcount != 0); -+ ASSERT(atomic64_read(&proc->ftpc_acount) <= proc->ftpc_rcount); -+ -+ if (--proc->ftpc_rcount != 0) { -+ mutex_unlock(&proc->ftpc_mtx); -+ return; -+ } -+ -+ mutex_unlock(&proc->ftpc_mtx); -+ -+ /* -+ * There should definitely be no live providers associated with this -+ * process at this point. -+ */ -+ ASSERT(atomic64_read(&proc->ftpc_acount) == 0); -+ -+ bucket = FASTTRAP_PROCS_ELEM(pid); -+ mutex_lock(&bucket->ftb_mtx); -+ -+ fprcp = (struct fasttrap_proc **)&bucket->ftb_data; -+ while ((fprc = *fprcp) != NULL) { -+ if (fprc == proc) -+ break; -+ -+ fprcp = &fprc->ftpc_next; -+ } -+ -+ /* -+ * Something strange has happened if we can't find the proc. -+ */ -+ ASSERT(fprc != NULL); -+ -+ *fprcp = fprc->ftpc_next; -+ -+ mutex_unlock(&bucket->ftb_mtx); -+ -+ kfree(fprc); -+} -+ -+static void fasttrap_provider_free(struct fasttrap_provider *provider) -+{ -+ pid_t pid = provider->ftp_pid; -+ -+ /* -+ * There need to be no associated enabled probes, no consumers -+ * creating probes, and no meta providers referencing this provider. -+ */ -+ ASSERT(provider->ftp_rcount == 0); -+ ASSERT(provider->ftp_ccount == 0); -+ ASSERT(provider->ftp_mcount == 0); -+ -+ /* -+ * If this provider hasn't been retired, we need to explicitly drop the -+ * count of active providers on the associated process structure. -+ */ -+ if (!provider->ftp_retired) { -+ atomic64_add(-1, &provider->ftp_proc->ftpc_acount); -+ ASSERT(atomic64_read(&provider->ftp_proc->ftpc_acount) < -+ provider->ftp_proc->ftpc_rcount); -+ } -+ -+ fasttrap_proc_release(provider->ftp_proc); -+ -+ kfree(provider); -+ -+ unregister_pid_provider(pid); -+} -+ -+static struct fasttrap_proc *fasttrap_proc_lookup(pid_t pid) -+{ -+ struct fasttrap_bucket *bucket; -+ struct fasttrap_proc *fprc, *new_fprc; -+ -+ bucket = FASTTRAP_PROCS_ELEM(pid); -+ mutex_lock(&bucket->ftb_mtx); -+ -+ for (fprc = bucket->ftb_data; fprc != NULL; fprc = fprc->ftpc_next) { -+ if (fprc->ftpc_pid == pid && -+ atomic64_read(&fprc->ftpc_acount) != 0) { -+ mutex_lock(&fprc->ftpc_mtx); -+ mutex_unlock(&bucket->ftb_mtx); -+ fprc->ftpc_rcount++; -+ atomic64_inc(&fprc->ftpc_acount); -+ ASSERT(atomic64_read(&fprc->ftpc_acount) <= -+ fprc->ftpc_rcount); -+ mutex_unlock(&fprc->ftpc_mtx); -+ -+ return fprc; -+ } -+ } -+ -+ /* -+ * Drop the bucket lock so we don't try to perform a sleeping -+ * allocation under it. -+ */ -+ mutex_unlock(&bucket->ftb_mtx); -+ -+ new_fprc = kzalloc(sizeof(struct fasttrap_proc), GFP_KERNEL); -+ if (new_fprc == NULL) -+ return NULL; -+ -+ new_fprc->ftpc_pid = pid; -+ new_fprc->ftpc_rcount = 1; -+ atomic64_set(&new_fprc->ftpc_acount, 1); -+ mutex_init(&new_fprc->ftpc_mtx); -+ -+ mutex_lock(&bucket->ftb_mtx); -+ -+ /* -+ * Take another lap through the list to make sure a proc hasn't -+ * been created for this pid while we weren't under the bucket lock. -+ */ -+ for (fprc = bucket->ftb_data; fprc != NULL; fprc = fprc->ftpc_next) { -+ if (fprc->ftpc_pid == pid && -+ atomic64_read(&fprc->ftpc_acount) != 0) { -+ mutex_lock(&fprc->ftpc_mtx); -+ mutex_unlock(&bucket->ftb_mtx); -+ fprc->ftpc_rcount++; -+ atomic64_inc(&fprc->ftpc_acount); -+ ASSERT(atomic64_read(&fprc->ftpc_acount) <= -+ fprc->ftpc_rcount); -+ mutex_unlock(&fprc->ftpc_mtx); -+ -+ kfree(new_fprc); -+ -+ return fprc; -+ } -+ } -+ -+ new_fprc->ftpc_next = bucket->ftb_data; -+ bucket->ftb_data = new_fprc; -+ -+ mutex_unlock(&bucket->ftb_mtx); -+ -+ return new_fprc; -+} -+ -+/* -+ * Lookup a fasttrap-managed provider based on its name and associated pid. -+ * If the pattr argument is non-NULL, this function instantiates the provider -+ * if it doesn't exist otherwise it returns NULL. The provider is returned -+ * with its lock held. -+ */ -+static struct fasttrap_provider * -+fasttrap_provider_lookup(pid_t pid, const char *name, -+ const struct dtrace_pattr *pa) -+{ -+ struct fasttrap_provider *fp, *new_fp = NULL; -+ struct fasttrap_proc *proc = NULL; -+ struct fasttrap_bucket *bucket; -+ char provname[DTRACE_PROVNAMELEN]; -+ struct task_struct *p; -+ const struct cred *cred = NULL; -+ -+ ASSERT(strlen(name) < sizeof(fp->ftp_name)); -+ ASSERT(pa != NULL); -+ -+ bucket = FASTTRAP_PROVS_ELEM(pid, name); -+ mutex_lock(&bucket->ftb_mtx); -+ -+ /* -+ * Take a lap through the list and return the match if we find it. -+ */ -+ for (fp = bucket->ftb_data; fp != NULL; fp = fp->ftp_next) { -+ if (fp->ftp_pid == pid && strcmp(fp->ftp_name, name) == 0 && -+ !fp->ftp_retired) { -+ mutex_lock(&fp->ftp_mtx); -+ mutex_unlock(&bucket->ftb_mtx); -+ -+ return fp; -+ } -+ } -+ -+ /* -+ * Drop the bucket lock so we don't try to perform a sleeping -+ * allocation under it. -+ */ -+ mutex_unlock(&bucket->ftb_mtx); -+ -+ p = register_pid_provider(pid); -+ if (p == NULL) -+ goto fail; -+ -+ /* -+ * Grab the credentials for this process so we have -+ * something to pass to dtrace_register(). -+ */ -+ cred = get_cred(p->cred); -+ -+ proc = fasttrap_proc_lookup(pid); -+ if (proc == NULL) -+ goto fail; -+ -+ new_fp = kzalloc(sizeof(struct fasttrap_provider), GFP_KERNEL); -+ if (new_fp == NULL) -+ goto fail; -+ -+ new_fp->ftp_pid = pid; -+ new_fp->ftp_proc = proc; -+ mutex_init(&new_fp->ftp_mtx); -+ mutex_init(&new_fp->ftp_cmtx); -+ -+ ASSERT(new_fp->ftp_proc != NULL); -+ -+ mutex_lock(&bucket->ftb_mtx); -+ -+ /* -+ * Take another lap through the list to make sure a provider hasn't -+ * been created for this pid while we weren't under the bucket lock. -+ */ -+ for (fp = bucket->ftb_data; fp != NULL; fp = fp->ftp_next) { -+ if (fp->ftp_pid == pid && strcmp(fp->ftp_name, name) == 0 && -+ !fp->ftp_retired) { -+ mutex_lock(&fp->ftp_mtx); -+ mutex_unlock(&bucket->ftb_mtx); -+ fasttrap_provider_free(new_fp); -+ put_cred(cred); -+ -+ return fp; -+ } -+ } -+ -+ strcpy(new_fp->ftp_name, name); -+ -+ /* -+ * Fail and return NULL if either the provider name is too long -+ * or we fail to register this new provider with the DTrace -+ * framework. Note that this is the only place we ever construct -+ * the full provider name -- we keep it in pieces in the provider -+ * structure. -+ */ -+ if (snprintf(provname, sizeof(provname), "%s%u", name, (uint_t)pid) >= -+ sizeof(provname) || -+ dtrace_register(provname, pa, -+ DTRACE_PRIV_PROC | DTRACE_PRIV_OWNER, cred, -+ pa == &pid_attr ? &pid_pops : &usdt_pops, -+ new_fp, &new_fp->ftp_provid) != 0) { -+ mutex_unlock(&bucket->ftb_mtx); -+ fasttrap_provider_free(new_fp); -+ put_cred(cred); -+ return NULL; -+ } -+ -+ new_fp->ftp_next = bucket->ftb_data; -+ bucket->ftb_data = new_fp; -+ -+ mutex_lock(&new_fp->ftp_mtx); -+ mutex_unlock(&bucket->ftb_mtx); -+ -+ put_cred(cred); -+ -+ return new_fp; -+ -+fail: -+ if (proc) -+ fasttrap_proc_release(proc); -+ if (cred) -+ put_cred(cred); -+ if (p) -+ unregister_pid_provider(pid); -+ -+ return NULL; -+} -+ -+void *fasttrap_meta_provide(void *arg, struct dtrace_helper_provdesc *dhpv, -+ pid_t pid) -+{ -+ struct fasttrap_provider *provider; -+ -+ if (strlen(dhpv->dthpv_provname) + 10 >= sizeof(provider->ftp_name)) { -+ pr_warn("Failed to instantiate provider %s: name too long " -+ "to accommodate pid\n", dhpv->dthpv_provname); -+ return NULL; -+ } -+ -+ /* -+ * Don't let folks spoof the true pid provider. -+ */ -+ if (strcmp(dhpv->dthpv_provname, FASTTRAP_PID_NAME) == 0) { -+ pr_warn("Failed to instantiate provider %s: %s is an invalid " -+ "name\n", dhpv->dthpv_provname, FASTTRAP_PID_NAME); -+ return NULL; -+ } -+ -+ /* -+ * The highest stability class that fasttrap supports is ISA; cap -+ * the stability of the new provider accordingly. -+ */ -+ if (dhpv->dthpv_pattr.dtpa_provider.dtat_class > DTRACE_CLASS_ISA) -+ dhpv->dthpv_pattr.dtpa_provider.dtat_class = DTRACE_CLASS_ISA; -+ if (dhpv->dthpv_pattr.dtpa_mod.dtat_class > DTRACE_CLASS_ISA) -+ dhpv->dthpv_pattr.dtpa_mod.dtat_class = DTRACE_CLASS_ISA; -+ if (dhpv->dthpv_pattr.dtpa_func.dtat_class > DTRACE_CLASS_ISA) -+ dhpv->dthpv_pattr.dtpa_func.dtat_class = DTRACE_CLASS_ISA; -+ if (dhpv->dthpv_pattr.dtpa_name.dtat_class > DTRACE_CLASS_ISA) -+ dhpv->dthpv_pattr.dtpa_name.dtat_class = DTRACE_CLASS_ISA; -+ if (dhpv->dthpv_pattr.dtpa_args.dtat_class > DTRACE_CLASS_ISA) -+ dhpv->dthpv_pattr.dtpa_args.dtat_class = DTRACE_CLASS_ISA; -+ -+ provider = fasttrap_provider_lookup(pid, dhpv->dthpv_provname, -+ &dhpv->dthpv_pattr); -+ if (provider == NULL) { -+ pr_warn("Failed to instantiate provider %s for process %u\n", -+ dhpv->dthpv_provname, (uint_t)pid); -+ return NULL; -+ } -+ -+ /* -+ * Up the meta provider count so this provider isn't removed until the -+ * meta provider has been told to remove it. -+ */ -+ provider->ftp_mcount++; -+ -+ mutex_unlock(&provider->ftp_mtx); -+ -+ return provider; -+} -+ -+static void fasttrap_pid_cleanup_cb(struct work_struct *work) -+{ -+ struct fasttrap_provider **fpp, *fp; -+ struct fasttrap_bucket *bucket; -+ dtrace_provider_id_t provid; -+ int i, later = 0; -+ -+ static volatile int in; -+ -+ ASSERT(in == 0); -+ in = 1; -+ -+ mutex_lock(&fasttrap_cleanup_mtx); -+ if (!fasttrap_cleanup_work && fasttrap_cleanup_state == CLEANUP_NONE) { -+ mutex_unlock(&fasttrap_cleanup_mtx); -+ in = 0; -+ return; -+ } -+ -+ dt_dbg_prov("Fasttrap provider cleanup callback processing...\n"); -+ while (fasttrap_cleanup_work) { -+ fasttrap_cleanup_work = 0; -+ mutex_unlock(&fasttrap_cleanup_mtx); -+ -+ later = 0; -+ -+ /* -+ * Iterate over all the providers trying to remove the marked -+ * ones. If a provider is marked but not retired, we just -+ * have to take a crack at removing it -- it's no big deal if -+ * we can't. -+ */ -+ for (i = 0; i < fasttrap_provs.fth_nent; i++) { -+ bucket = FASTTRAP_ELEM_BUCKET(&fasttrap_provs.fth_table[i]); -+ mutex_lock(&bucket->ftb_mtx); -+ fpp = (struct fasttrap_provider **)&bucket->ftb_data; -+ -+ while ((fp = *fpp) != NULL) { -+ dt_dbg_prov(" Trying to unregister %s%d " -+ "(%smarked)\n", -+ fp->ftp_name, fp->ftp_pid, -+ fp->ftp_marked ? "not " : ""); -+ if (!fp->ftp_marked) { -+ fpp = &fp->ftp_next; -+ continue; -+ } -+ -+ dt_dbg_prov(" ccount %llu, mcount %llu " -+ "rcount %llu, %sretired, " -+ "%smarked\n", -+ fp->ftp_ccount, fp->ftp_mcount, -+ fp->ftp_rcount, -+ fp->ftp_retired ? "" : "not ", -+ fp->ftp_marked ? "" : "not "); -+ -+ mutex_lock(&fp->ftp_mtx); -+ -+ /* -+ * If this provider has consumers actively -+ * creating probes (ftp_ccount) or is a USDT -+ * provider (ftp_mcount), we can't unregister -+ * or even condense. -+ */ -+ if (fp->ftp_ccount != 0 || -+ fp->ftp_mcount != 0) { -+ mutex_unlock(&fp->ftp_mtx); -+ fp->ftp_marked = 0; -+ continue; -+ } -+ -+ if (!fp->ftp_retired || fp->ftp_rcount != 0) -+ fp->ftp_marked = 0; -+ -+ mutex_unlock(&fp->ftp_mtx); -+ -+ /* -+ * If we successfully unregister this -+ * provider we can remove it from the hash -+ * chain and free the memory. If our attempt -+ * to unregister fails and this is a retired -+ * provider, increment our flag to try again -+ * pretty soon. If we've consumed more than -+ * half of our total permitted number of -+ * probes call dtrace_condense() to try to -+ * clean out the unenabled probes. -+ */ -+ provid = fp->ftp_provid; -+ mutex_lock(&module_mutex); -+ if (dtrace_unregister(provid) != 0) { -+ if (atomic_read(&fasttrap_total) > -+ fasttrap_max / 2) -+ dtrace_condense(provid); -+ -+ later += fp->ftp_marked; -+ fpp = &fp->ftp_next; -+ } else { -+ *fpp = fp->ftp_next; -+ fasttrap_provider_free(fp); -+ } -+ mutex_unlock(&module_mutex); -+ } -+ -+ mutex_unlock(&bucket->ftb_mtx); -+ } -+ -+ mutex_lock(&fasttrap_cleanup_mtx); -+ } -+ -+ ASSERT(fasttrap_cleanup_state != CLEANUP_NONE); -+ -+ /* -+ * If we were unable to remove a retired provider, try again after -+ * a second. This situation can occur in certain circumstances where -+ * providers cannot be unregistered even though they have no probes -+ * enabled because of an execution of dtrace -l or something similar. -+ * If the timeout has been disabled (set to 1 because we're trying -+ * to detach), we set fasttrap_cleanup_work to ensure that we'll -+ * get a chance to do that work if and when the timeout is reenabled -+ * (if detach fails). -+ */ -+ if (later > 0) { -+ dt_dbg_prov(" Some providers were not removed " -+ " (state %d, later = %d)\n", -+ fasttrap_cleanup_state, later); -+ if (fasttrap_cleanup_state == CLEANUP_DEFERRED) -+ fasttrap_cleanup_work = 1; -+ else { -+ struct delayed_work *dw = container_of( -+ work, -+ struct delayed_work, -+ work); -+ -+ fasttrap_cleanup_state = CLEANUP_SCHEDULED; -+ schedule_delayed_work(dw, HZ); -+ } -+ } else -+ fasttrap_cleanup_state = CLEANUP_NONE; -+ -+ mutex_unlock(&fasttrap_cleanup_mtx); -+ in = 0; -+ -+ dt_dbg_prov("Fasttrap provider cleanup callback done\n"); -+} -+ -+static DECLARE_DELAYED_WORK(fasttrap_cleanup, fasttrap_pid_cleanup_cb); -+ -+/* -+ * Activate the asynchronous cleanup mechanism. -+ */ -+static void fasttrap_pid_cleanup(void) -+{ -+ mutex_lock(&fasttrap_cleanup_mtx); -+ fasttrap_cleanup_work = 1; -+ fasttrap_cleanup_state = CLEANUP_SCHEDULED; -+ schedule_delayed_work(&fasttrap_cleanup, 3); -+ mutex_unlock(&fasttrap_cleanup_mtx); -+} -+ -+void fasttrap_provider_retire(pid_t pid, const char *name, int mprov) -+{ -+ struct fasttrap_provider *fp; -+ struct fasttrap_bucket *bucket; -+ dtrace_provider_id_t provid; -+ -+ ASSERT(strlen(name) < sizeof(fp->ftp_name)); -+ -+ dt_dbg_prov("Retiring %s %sprovider for PID %d\n", -+ name, mprov ? "meta-" : "", pid); -+ -+ bucket = FASTTRAP_PROVS_ELEM(pid, name); -+ mutex_lock(&bucket->ftb_mtx); -+ -+ for (fp = bucket->ftb_data; fp != NULL; fp = fp->ftp_next) { -+ if (fp->ftp_pid == pid && strcmp(fp->ftp_name, name) == 0 && -+ !fp->ftp_retired) -+ break; -+ } -+ -+ if (fp == NULL) { -+ mutex_unlock(&bucket->ftb_mtx); -+ return; -+ } -+ -+ mutex_lock(&fp->ftp_mtx); -+ ASSERT(!mprov || fp->ftp_mcount > 0); -+ if (mprov && --fp->ftp_mcount != 0) { -+ mutex_unlock(&fp->ftp_mtx); -+ mutex_unlock(&bucket->ftb_mtx); -+ return; -+ } -+ -+ /* -+ * Mark the provider to be removed in our post-processing step, mark it -+ * retired, and drop the active count on its proc. Marking it indicates -+ * that we should try to remove it; setting the retired flag indicates -+ * that we're done with this provider; dropping the active count on the -+ * proc releases our hold, and when this reaches zero (as it will -+ * during exit or exec) the proc and associated providers become -+ * defunct. -+ * -+ * We obviously need to take the bucket lock before the provider lock -+ * to perform the lookup, but we need to drop the provider lock -+ * before calling into the DTrace framework since we acquire the -+ * provider lock in callbacks invoked from the DTrace framework. The -+ * bucket lock therefore protects the integrity of the provider hash -+ * table. -+ */ -+ atomic64_dec(&fp->ftp_proc->ftpc_acount); -+ ASSERT(atomic64_read(&fp->ftp_proc->ftpc_acount) < -+ fp->ftp_proc->ftpc_rcount); -+ -+ fp->ftp_retired = 1; -+ fp->ftp_marked = 1; -+ provid = fp->ftp_provid; -+ mutex_unlock(&fp->ftp_mtx); -+ -+ /* -+ * We don't have to worry about invalidating the same provider twice -+ * since fasttrap_provider_lookup() will ignore provider that have -+ * been marked as retired. -+ */ -+ dtrace_invalidate(provid); -+ -+ mutex_unlock(&bucket->ftb_mtx); -+ -+ fasttrap_pid_cleanup(); -+} -+ -+static void fasttrap_probes_cleanup(struct task_struct *tsk) -+{ -+ fasttrap_provider_retire(tsk->pid, FASTTRAP_PID_NAME, 0); -+} -+ -+void fasttrap_meta_remove(void *arg, struct dtrace_helper_provdesc *dhpv, -+ pid_t pid) -+{ -+ /* -+ * Clean up the USDT provider. There may be active consumers of the -+ * provider busy adding probes, no damage will actually befall the -+ * provider until that count has dropped to zero. This just puts -+ * the provider on death row. -+ */ -+ fasttrap_provider_retire(pid, dhpv->dthpv_provname, 1); -+} -+ -+static int fasttrap_add_probe(struct fasttrap_probe_spec *probe) -+{ -+ struct fasttrap_provider *provider; -+ struct fasttrap_probe *pp; -+ struct fasttrap_tracepoint *tp; -+ uint64_t *offs = NULL; -+ uint64_t noffs; -+ char *name; -+ int aframes, retired; -+ -+ switch (probe->ftps_type) { -+ case DTFTP_ENTRY: -+ name = "entry"; -+ aframes = FASTTRAP_ENTRY_AFRAMES; -+ break; -+ case DTFTP_RETURN: -+ name = "return"; -+ aframes = FASTTRAP_RETURN_AFRAMES; -+ break; -+ case DTFTP_OFFSETS: -+ if (probe->ftps_glen <= 0) -+ return -EINVAL; -+ -+ name = "<offsets>"; -+ aframes = FASTTRAP_OFFSET_AFRAMES; -+ offs = fasttrap_glob_offsets(probe, &noffs); -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ provider = fasttrap_provider_lookup(probe->ftps_pid, FASTTRAP_PID_NAME, -+ &pid_attr); -+ if (provider == NULL) -+ return -ESRCH; -+ -+ /* -+ * Increment the consumer reference count on the provider to indicate -+ * that a new probe is being associated with the provider. This makes -+ * sure that the provider will not be removed while we are working with -+ * it. -+ * -+ * This also means that we can drop the provider lock. -+ */ -+ provider->ftp_ccount++; -+ mutex_unlock(&provider->ftp_mtx); -+ -+ /* -+ * Grab the probe creation lock for this provider to ensure consistency -+ * between dtrace_probe_lookup() and dtrace_probe_create() because -+ * other threads might be creating probes also. -+ */ -+ mutex_lock(&provider->ftp_cmtx); -+ -+ if (probe->ftps_type == DTFTP_OFFSETS) { -+ int i; -+ -+ for (i = 0; i < noffs; i++) { -+ char ostr[sizeof(*offs) + 1]; -+ -+ snprintf(ostr, sizeof(ostr), "%llx", offs[i]); -+ if (dtrace_probe_lookup(provider->ftp_provid, -+ probe->ftps_mod, -+ probe->ftps_func, ostr) != 0) -+ continue; -+ -+ atomic_add(1, &fasttrap_total); -+ if (atomic_read(&fasttrap_total) > fasttrap_max) -+ goto fail_reset; -+ -+ pp = kzalloc(sizeof(struct fasttrap_probe), GFP_KERNEL); -+ if (pp == NULL) -+ goto fail_reset; -+ -+ pp->ftp_prov = provider; -+ pp->ftp_pid = provider->ftp_pid; -+ pp->ftp_ntps = 1; -+ -+ tp = kmem_cache_alloc(tracepoint_cachep, GFP_KERNEL); -+ if (tp == NULL) -+ goto fail_reset; -+ -+ tp->ftt_proc = provider->ftp_proc; -+ tp->ftt_pc = probe->ftps_pc + offs[i]; -+ tp->ftt_pid = provider->ftp_pid; -+ memset(&tp->ftt_mtp, 0, -+ sizeof(struct fasttrap_machtp)); -+ tp->ftt_ids = NULL; -+ tp->ftt_retids = NULL; -+ tp->ftt_next = NULL; -+ -+ pp->ftp_tps[0].fit_tp = tp; -+ pp->ftp_tps[0].fit_id.fti_probe = pp; -+ pp->ftp_tps[0].fit_id.fti_ptype = probe->ftps_type; -+ -+ pp->ftp_id = dtrace_probe_create(provider->ftp_provid, -+ probe->ftps_mod, -+ probe->ftps_func, ostr, -+ aframes, pp); -+ if (pp->ftp_id == DTRACE_IDNONE) { -+ kmem_cache_free(tracepoint_cachep, tp); -+ kfree(pp); -+ -+ goto fail_reset; -+ } -+ } -+ } else if (dtrace_probe_lookup(provider->ftp_provid, probe->ftps_mod, -+ probe->ftps_func, name) == 0) { -+ atomic_add(1, &fasttrap_total); -+ if (atomic_read(&fasttrap_total) > fasttrap_max) -+ goto fail_reset; -+ -+ pp = kzalloc(sizeof(struct fasttrap_probe), GFP_KERNEL); -+ if (pp == NULL) -+ goto fail_reset; -+ -+ pp->ftp_prov = provider; -+ pp->ftp_pid = provider->ftp_pid; -+ pp->ftp_ntps = 1; -+ -+ tp = kmem_cache_alloc(tracepoint_cachep, GFP_KERNEL); -+ if (tp == NULL) -+ goto fail_reset; -+ -+ tp->ftt_proc = provider->ftp_proc; -+ tp->ftt_pc = probe->ftps_pc; -+ tp->ftt_pid = provider->ftp_pid; -+ memset(&tp->ftt_mtp, 0, sizeof(struct fasttrap_machtp)); -+ tp->ftt_ids = NULL; -+ tp->ftt_retids = NULL; -+ tp->ftt_next = NULL; -+ -+ pp->ftp_tps[0].fit_tp = tp; -+ pp->ftp_tps[0].fit_id.fti_probe = pp; -+ pp->ftp_tps[0].fit_id.fti_ptype = probe->ftps_type; -+ -+ pp->ftp_id = dtrace_probe_create(provider->ftp_provid, -+ probe->ftps_mod, -+ probe->ftps_func, name, -+ aframes, pp); -+ if (pp->ftp_id == DTRACE_IDNONE) { -+ kmem_cache_free(tracepoint_cachep, tp); -+ kfree(pp); -+ -+ goto fail_reset; -+ } -+ } -+ -+ mutex_unlock(&provider->ftp_cmtx); -+ -+ /* -+ * The provider is still around because of the consumer reference -+ * count that we incremented. If another thread tried to clean up the -+ * provider while we were using it (because the process called exec or -+ * exit), we'll trigger a cleanup. -+ */ -+ mutex_lock(&provider->ftp_mtx); -+ provider->ftp_ccount--; -+ retired = provider->ftp_retired; -+ mutex_unlock(&provider->ftp_mtx); -+ -+ if (retired) -+ fasttrap_pid_cleanup(); -+ -+ return 0; -+ -+fail_reset: -+ atomic_add(-1, &fasttrap_total); -+ -+ /* -+ * If we failed to create the probe, it usually means we ran out of -+ * memory. We'll try to remove this provider to free some. This -+ * usually happens when a user accidentally triggers the creation of -+ * a very large amount of probes (e.g. pid587:::). -+ */ -+ mutex_unlock(&provider->ftp_cmtx); -+ -+ kfree(offs); -+ -+ mutex_lock(&provider->ftp_mtx); -+ provider->ftp_ccount--; -+ provider->ftp_marked = 1; -+ mutex_unlock(&provider->ftp_mtx); -+ -+ fasttrap_pid_cleanup(); -+ -+ return -ENOMEM; -+} -+ -+static long fasttrap_ioctl(struct file *file, -+ unsigned int cmd, unsigned long arg) -+{ -+ void __user *argp = (void __user *)arg; -+ -+ if (cmd == FASTTRAPIOC_MAKEPROBE) { -+ struct fasttrap_probe_spec __user *uprobe = argp; -+ struct fasttrap_probe_spec *probe; -+ uint8_t glen; -+ size_t size; -+ int ret; -+ char *c; -+ -+ dt_dbg_ioctl("PID IOCTL MAKEPROBE (cmd %#x), argp %p\n", -+ cmd, argp); -+ -+ if (copy_from_user(&glen, &uprobe->ftps_glen, -+ sizeof(uprobe->ftps_glen))) -+ return -EFAULT; -+ -+ size = sizeof(struct fasttrap_probe_spec) + -+ sizeof(probe->ftps_gstr[0]) * (glen - 1); -+ -+ if (size > 1024 * 1024) -+ return -ENOMEM; -+ -+ probe = kmalloc(size, GFP_KERNEL); -+ if (!probe) -+ return -ENOMEM; -+ -+ if (copy_from_user(probe, uprobe, size) != 0) { -+ ret = -EFAULT; -+ goto err; -+ } -+ -+ for (c = &probe->ftps_func[0]; *c != '\0'; c++) { -+ if (*c < 0x20 || 0x7f <= *c) { -+ ret = -EINVAL; -+ goto err; -+ } -+ } -+ -+ for (c = &probe->ftps_mod[0]; *c != '\0'; c++) { -+ if (*c < 0x20 || 0x7f <= *c) { -+ ret = -EINVAL; -+ goto err; -+ } -+ } -+ -+ ret = fasttrap_add_probe(probe); -+err: -+ kfree(probe); -+ -+ return ret; -+ } -+ -+ return -EAGAIN; -+} -+ -+static int fasttrap_open(struct inode *inode, struct file *file) -+{ -+ return 0; -+} -+ -+static int fasttrap_close(struct inode *inode, struct file *file) -+{ -+ return 0; -+} -+ -+static const struct file_operations fasttrap_fops = { -+ .owner = THIS_MODULE, -+ .unlocked_ioctl = fasttrap_ioctl, -+ .open = fasttrap_open, -+ .release = fasttrap_close, -+}; -+ -+static struct miscdevice fasttrap_dev = { -+ .minor = DT_DEV_FASTTRAP_MINOR, -+ .name = "fasttrap", -+ .nodename = "dtrace/provider/fasttrap", -+ .fops = &fasttrap_fops, -+}; -+ -+static int fasttrap_init_htable(struct fasttrap_hash *fth, ulong_t nent) -+{ -+ ulong_t i; -+ -+ if ((nent & (nent - 1)) == 0) -+ fth->fth_nent = nent; -+ else -+ fth->fth_nent = 1 << fls(nent); -+ -+ ASSERT(fth->fth_nent > 0); -+ -+ fth->fth_mask = fth->fth_nent - 1; -+ fth->fth_table = vzalloc(fth->fth_nent * -+ sizeof(struct fasttrap_bucket_elem)); -+ -+ if (fth->fth_table == NULL) -+ return -ENOMEM; -+ -+ for (i = 0; i < fth->fth_nent; i++) -+ mutex_init(&fth->fth_table[i].bucket.ftb_mtx); -+ -+ return 0; -+} -+ -+int fasttrap_dev_init(void) -+{ -+ int ret = 0; -+ ulong_t nent; -+ -+ ret = misc_register(&fasttrap_dev); -+ if (ret) { -+ pr_err("%s: Can't register misc device %d\n", -+ fasttrap_dev.name, fasttrap_dev.minor); -+ goto fail; -+ } -+ -+#ifdef FIXME -+ dtrace_fasttrap_exit_ptr = &fasttrap_exec_exit; -+ dtrace_fasttrap_exec_ptr = &fasttrap_exec_exit; -+#endif -+ -+ tracepoint_cachep = KMEM_CACHE(fasttrap_tracepoint, 0); -+ -+ fasttrap_max = FASTTRAP_MAX_DEFAULT; -+ atomic_set(&fasttrap_total, 0); -+ -+ /* -+ * Conjure up the tracepoints hashtable... -+ */ -+ nent = FASTTRAP_TPOINTS_DEFAULT_SIZE; -+ -+ if (nent == 0 || nent > 0x1000000) -+ nent = FASTTRAP_TPOINTS_DEFAULT_SIZE; -+ -+ if (fasttrap_init_htable(&fasttrap_tpoints, nent) != 0) -+ return -ENOMEM; -+ -+ /* -+ * ... and the providers hash table... -+ */ -+ nent = FASTTRAP_PROVIDERS_DEFAULT_SIZE; -+ if (fasttrap_init_htable(&fasttrap_provs, nent) != 0) -+ return -ENOMEM; -+ -+ /* -+ * ... and the procs hash table. -+ */ -+ nent = FASTTRAP_PROCS_DEFAULT_SIZE; -+ if (fasttrap_init_htable(&fasttrap_procs, nent) != 0) -+ return -ENOMEM; -+ -+fail: -+ return ret; -+} -+ -+/* -+ * This function is called with module_mutex held. -+ */ -+int fasttrap_prov_exit(void) -+{ -+ int fail = 0; -+ ulong_t i; -+ -+ if (dtrace_meta_unregister(fasttrap_id) != 0) -+ return 0; -+ -+ /* -+ * Prevent any new timeouts from running by setting fasttrap_timeout -+ * to a non-zero value, and wait for the current timeout to complete. -+ */ -+ mutex_lock(&fasttrap_cleanup_mtx); -+ fasttrap_cleanup_work = 0; -+ -+ while (fasttrap_cleanup_state != CLEANUP_DEFERRED) { -+ uint_t tmp; -+ -+ tmp = fasttrap_cleanup_state; -+ fasttrap_cleanup_state = CLEANUP_DEFERRED; -+ -+ if (tmp != CLEANUP_NONE) { -+ mutex_unlock(&fasttrap_cleanup_mtx); -+ flush_delayed_work(&fasttrap_cleanup); -+ mutex_lock(&fasttrap_cleanup_mtx); -+ } -+ } -+ -+ fasttrap_cleanup_work = 0; -+ mutex_unlock(&fasttrap_cleanup_mtx); -+ -+ /* -+ * Iterate over all of our providers. If there's still a process -+ * that corresponds to that pid, fail to detach. -+ */ -+ for (i = 0; i < fasttrap_provs.fth_nent; i++) { -+ struct fasttrap_provider **fpp, *fp; -+ struct fasttrap_bucket *bucket; -+ -+ bucket = FASTTRAP_ELEM_BUCKET(&fasttrap_provs.fth_table[i]); -+ mutex_lock(&bucket->ftb_mtx); -+ fpp = (struct fasttrap_provider **)&bucket->ftb_data; -+ while ((fp = *fpp) != NULL) { -+ /* -+ * Acquire and release the lock as a simple way of -+ * waiting for any other consumer to finish with -+ * this provider. A thread must first acquire the -+ * bucket lock so there's no chance of another thread -+ * blocking on the provider's lock. -+ */ -+ mutex_lock(&fp->ftp_mtx); -+ mutex_unlock(&fp->ftp_mtx); -+ -+ if (dtrace_unregister(fp->ftp_provid) != 0) { -+ fail = 1; -+ fpp = &fp->ftp_next; -+ } else { -+ *fpp = fp->ftp_next; -+ fasttrap_provider_free(fp); -+ } -+ } -+ -+ mutex_unlock(&bucket->ftb_mtx); -+ } -+ -+ if (fail) { -+ uint_t work; -+ -+ /* -+ * If we're failing to detach, we need to unblock timeouts -+ * and start a new timeout if any work has accumulated while -+ * we've been unsuccessfully trying to detach. -+ */ -+ mutex_lock(&fasttrap_cleanup_mtx); -+ fasttrap_cleanup_state = CLEANUP_NONE; -+ work = fasttrap_cleanup_work; -+ mutex_unlock(&fasttrap_cleanup_mtx); -+ -+ if (work) -+ fasttrap_pid_cleanup(); -+ -+ dtrace_meta_register("fasttrap", &fasttrap_mops, NULL, -+ &fasttrap_id); -+ -+ return 0; -+ } -+ -+ return 1; -+} -+ -+void fasttrap_dev_exit(void) -+{ -+#ifdef DEBUG -+ mutex_lock(&fasttrap_count_mtx); -+ ASSERT(fasttrap_pid_count == 0); -+ mutex_unlock(&fasttrap_count_mtx); -+#endif -+ -+ if (fasttrap_tpoints.fth_table) -+ vfree(fasttrap_tpoints.fth_table); -+ fasttrap_tpoints.fth_nent = 0; -+ -+ if (fasttrap_provs.fth_table) -+ vfree(fasttrap_provs.fth_table); -+ fasttrap_provs.fth_nent = 0; -+ -+ if (fasttrap_procs.fth_table) -+ vfree(fasttrap_procs.fth_table); -+ fasttrap_procs.fth_nent = 0; -+ -+ kmem_cache_destroy(tracepoint_cachep); -+ -+#ifdef FIXME -+ ASSERT(dtrace_fasttrap_exec_ptr == &fasttrap_exec_exit); -+ dtrace_fasttrap_exec_ptr = NULL; -+ -+ ASSERT(dtrace_fasttrap_exit_ptr == &fasttrap_exec_exit); -+ dtrace_fasttrap_exit_ptr = NULL; -+#endif -+ -+ misc_deregister(&fasttrap_dev); -+} -diff --git a/dtrace/fasttrap_impl.h b/dtrace/fasttrap_impl.h -new file mode 100644 -index 000000000000..cd2c4a28871e ---- /dev/null -+++ b/dtrace/fasttrap_impl.h -@@ -0,0 +1,172 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Dynamic Tracing for Linux - fasttrap provider -+ * -+ * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#ifndef _FASTTRAP_IMPL_H_ -+#define _FASTTRAP_IMPL_H_ -+ -+#include <linux/dtrace/fasttrap.h> -+#include <dtrace/fasttrap_arch.h> -+#include <linux/cache.h> -+ -+/* -+ * Fasttrap Providers, Probes and Tracepoints -+ * -+ * Each Solaris process can have multiple providers -- the pid provider as -+ * well as any number of user-level statically defined tracing (USDT) -+ * providers. Those providers are each represented by a fasttrap_provider. -+ * All providers for a given process have a pointer to a shared -+ * fasttrap_proc. The fasttrap_proc has two states: active or defunct. -+ * When the count of active providers goes to zero it becomes defunct; a -+ * provider drops its active count when it is removed individually or as part -+ * of a mass removal when a process exits or performs an exec. -+ * -+ * Each probe is represented by a fasttrap_probe which has a pointer to -+ * its associated provider as well as a list of fasttrap_id_tp structures -+ * which are tuples combining a fasttrap_id and a fasttrap_tracepoint. -+ * A fasttrap_tracepoint represents the actual point of instrumentation -+ * and it contains two lists of fasttrap_id structures (to be fired pre- -+ * and post-instruction emulation) that identify the probes attached to the -+ * tracepoint. Tracepoints also have a pointer to the fasttrap_proc for the -+ * process they trace which is used when looking up a tracepoint both when a -+ * probe fires and when enabling and disabling probes. -+ * -+ * It's important to note that probes are preallocated with the necessary -+ * number of tracepoints, but that tracepoints can be shared by probes and -+ * swapped between probes. If a probe's preallocated tracepoint is enabled -+ * (and, therefore, the associated probe is enabled), and that probe is -+ * then disabled, ownership of that tracepoint may be exchanged for an -+ * unused tracepoint belonging to another probe that was attached to the -+ * enabled tracepoint. -+ */ -+struct fasttrap_proc { -+ pid_t ftpc_pid; /* process ID for this proc */ -+ atomic64_t ftpc_acount; /* count of active providers */ -+ uint64_t ftpc_rcount; /* count of extant providers */ -+ struct mutex ftpc_mtx; /* lock on all but acount */ -+ struct fasttrap_proc *ftpc_next; /* next proc in hash chain */ -+}; -+ -+struct fasttrap_provider { -+ pid_t ftp_pid; /* process ID for this prov */ -+ char ftp_name[DTRACE_PROVNAMELEN]; /* prov name (w/o the pid) */ -+ dtrace_provider_id_t ftp_provid; /* DTrace provider handle */ -+ uint_t ftp_marked; /* mark for possible removal */ -+ uint_t ftp_retired; /* mark when retired */ -+ struct mutex ftp_mtx; /* provider lock */ -+ struct mutex ftp_cmtx; /* lock on creating probes */ -+ uint64_t ftp_rcount; /* enabled probes ref count */ -+ uint64_t ftp_ccount; /* consumers creating probes */ -+ uint64_t ftp_mcount; /* meta provider count */ -+ struct fasttrap_proc *ftp_proc; /* shared proc for all provs */ -+ struct fasttrap_provider *ftp_next; /* next prov in hash chain */ -+}; -+ -+struct fasttrap_id { -+ struct fasttrap_probe *fti_probe; /* referrring probe */ -+ struct fasttrap_id *fti_next; /* enabled probe list on tp */ -+ enum fasttrap_probe_type fti_ptype; /* probe type */ -+}; -+ -+struct fasttrap_tracepoint { -+ struct fasttrap_proc *ftt_proc; /* associated process struct */ -+ uintptr_t ftt_pc; /* address of tracepoint */ -+ pid_t ftt_pid; /* pid of tracepoint */ -+ struct fasttrap_machtp ftt_mtp; /* ISA-specific portion */ -+ struct fasttrap_id *ftt_ids; /* NULL-terminated list */ -+ struct fasttrap_id *ftt_retids; /* NULL-terminated list */ -+ struct fasttrap_tracepoint *ftt_next; /* link in global hash */ -+}; -+ -+struct fasttrap_id_tp { -+ struct fasttrap_id fit_id; -+ struct fasttrap_tracepoint *fit_tp; -+}; -+ -+struct fasttrap_probe { -+ dtrace_id_t ftp_id; /* DTrace probe identifier */ -+ pid_t ftp_pid; /* pid for this probe */ -+ struct fasttrap_provider *ftp_prov; /* this probe's provider */ -+ uint64_t ftp_gen; /* modification generation */ -+ uint64_t ftp_ntps; /* number of tracepoints */ -+ uint8_t *ftp_argmap; /* native to translated args */ -+ uint8_t ftp_nargs; /* translated argument count */ -+ uint8_t ftp_enabled; /* is this probe enabled */ -+ char *ftp_xtypes; /* translated types index */ -+ char *ftp_ntypes; /* native types index */ -+ struct fasttrap_id_tp ftp_tps[1]; /* flexible array */ -+}; -+ -+struct fasttrap_bucket_elem { -+ union { -+ struct fasttrap_bucket { -+ struct mutex ftb_mtx; /* bucket lock */ -+ void *ftb_data; /* data payload */ -+ } bucket; -+ -+ /* -+ * Fill a cacheline, no matter how large struct mutex is. -+ */ -+ uint8_t ftb_pad[(sizeof(struct fasttrap_bucket) + -+ L1_CACHE_BYTES - 1) & ~(L1_CACHE_BYTES - 1)]; -+ }; -+}; -+typedef struct fasttrap_bucket fasttrap_bucket_t; -+ -+#define FASTTRAP_ELEM_BUCKET(elem) ((fasttrap_bucket_t *) (elem)) -+ -+struct fasttrap_hash { -+ ulong_t fth_nent; /* power-of-2 num. of entries */ -+ ulong_t fth_mask; /* fth_nent - 1 */ -+ struct fasttrap_bucket_elem *fth_table; /* array of buckets */ -+}; -+ -+extern struct fasttrap_hash fasttrap_tpoints; -+ -+#define FASTTRAP_ID_INDEX(id) \ -+ ((struct fasttrap_id_tp *)(((char *)(id) - \ -+ offsetof(struct fasttrap_id_tp, fit_id))) - \ -+ &(id)->fti_probe->ftp_tps[0]) -+#define FASTTRAP_TPOINTS_INDEX(pid, pc) \ -+ (((pc) / sizeof(fasttrap_instr_t) + (pid)) & \ -+ fasttrap_tpoints.fth_mask) -+ -+extern uint64_t *fasttrap_glob_offsets(struct fasttrap_probe_spec *probe, -+ uint64_t *np); -+extern uint64_t fasttrap_pid_getarg(void *arg, dtrace_id_t id, void *parg, -+ int argno, int aframes); -+extern uint64_t fasttrap_usdt_getarg(void *arg, dtrace_id_t id, void *parg, -+ int argno, int aframes); -+extern void fasttrap_pid_probe_arch(struct fasttrap_probe *ftp, -+ struct pt_regs *regs); -+extern void fasttrap_pid_retprobe_arch(struct fasttrap_probe *ftp, -+ struct pt_regs *regs); -+extern void fasttrap_set_enabled(struct pt_regs *regs); -+ -+extern void fasttrap_meta_create_probe(void *, void *, -+ struct dtrace_helper_probedesc *); -+extern void *fasttrap_meta_provide(void *, struct dtrace_helper_provdesc *, -+ pid_t); -+extern void fasttrap_meta_remove(void *, struct dtrace_helper_provdesc *, -+ pid_t); -+ -+extern dtrace_meta_provider_id_t fasttrap_id; -+extern struct dtrace_mops fasttrap_mops; -+ -+extern int fasttrap_dev_init(void); -+extern void fasttrap_dev_exit(void); -+ -+#endif /* _FASTTRAP_IMPL_H_ */ -diff --git a/dtrace/fasttrap_mod.c b/dtrace/fasttrap_mod.c -new file mode 100644 -index 000000000000..e9bd0eb065f1 ---- /dev/null -+++ b/dtrace/fasttrap_mod.c -@@ -0,0 +1,38 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: fasttrap_mod.c -+ * DESCRIPTION: DTrace - fasttrap provider kernel module -+ * -+ * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/module.h> -+ -+#define DTRACE_HAVE_PROV_EXIT -+ -+#include "dtrace.h" -+#include "dtrace_dev.h" -+#include "fasttrap_impl.h" -+ -+MODULE_AUTHOR("Kris Van Hees (kris.van.hees@oracle.com)"); -+MODULE_DESCRIPTION("Fasttrap Tracing"); -+MODULE_VERSION("v0.1"); -+MODULE_LICENSE("GPL"); -+ -+struct dtrace_mops fasttrap_mops = { -+ fasttrap_meta_create_probe, -+ fasttrap_meta_provide, -+ fasttrap_meta_remove -+}; -+ -+DT_META_PROVIDER_MODULE(fasttrap) --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/dtrace-patches/0014-dtrace-function-boundary-tracing-FBT-core-and-x86-co.patch b/sys-kernel/cairn-sources/files/5.10.13/dtrace-patches/0014-dtrace-function-boundary-tracing-FBT-core-and-x86-co.patch deleted file mode 100644 index 8bee6b6fd438..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/dtrace-patches/0014-dtrace-function-boundary-tracing-FBT-core-and-x86-co.patch +++ /dev/null @@ -1,1799 +0,0 @@ -From bc81b22d39f0332275cd6834fdffb749368e62a0 Mon Sep 17 00:00:00 2001 -From: Kris Van Hees <kris.van.hees@oracle.com> -Date: Mon, 19 Nov 2018 19:02:39 +0000 -Subject: [PATCH 14/19] dtrace: function boundary tracing (FBT) core and x86 - components - -This commit implements the core components needed for FBT tracing. -Unlike ftrace we allow the tracing of very large numbers of functions at -once: the intent is that the system should still be stable when every -eligible function in the kernel is traced simultaneously. Functions -that are not safe for this (because e.g. they are used in trap handling, -or by functions called by the DTrace module itself during probe -processing) are (semi-manually) blacklisted from being probed. - -As part of this, a treewide change to the prototype of traps is started: -they all return 0 by default now, with a nonzero return value indicating -that the trap happened as a result of an FBT probe: the return value is -the opcode atop which the trap was originally placed for later emulation. - -Signed-off-by: Kris Van Hees <kris.van.hees@oracle.com> -Signed-off-by: Tomas Jedlicka <tomas.jedlicka@oracle.com> -Signed-off-by: Nick Alcock <nick.alcock@oracle.com> -Signed-off-by: Eugene Loh <eugene.loh@oracle.com> -Signed-off-by: David Mc Lean <david.mclean@oracle.com> -Signed-off-by: Vincent Lim <vincent.lim@oracle.com> ---- - arch/x86/entry/entry_64.S | 134 ++++++++++++++++++- - arch/x86/hyperv/hv_init.c | 1 + - arch/x86/include/asm/idtentry.h | 86 +++++++------ - arch/x86/include/asm/irq_stack.h | 36 +++--- - arch/x86/kernel/apic/apic.c | 4 + - arch/x86/kernel/apic/vector.c | 1 + - arch/x86/kernel/cpu/acrn.c | 1 + - arch/x86/kernel/cpu/mce/amd.c | 1 + - arch/x86/kernel/cpu/mce/core.c | 3 + - arch/x86/kernel/cpu/mce/therm_throt.c | 1 + - arch/x86/kernel/cpu/mce/threshold.c | 1 + - arch/x86/kernel/cpu/mshyperv.c | 2 + - arch/x86/kernel/dtrace_fbt.c | 177 ++++++++++++++++++++++++++ - arch/x86/kernel/fbt_blacklist.h | 95 ++++++++++++++ - arch/x86/kernel/irq.c | 5 + - arch/x86/kernel/irq_work.c | 1 + - arch/x86/kernel/kvm.c | 1 + - arch/x86/kernel/nmi.c | 5 +- - arch/x86/kernel/sev-es.c | 6 +- - arch/x86/kernel/smp.c | 4 + - arch/x86/kernel/traps.c | 91 ++++++++----- - arch/x86/mm/fault.c | 3 +- - arch/x86/xen/enlighten_hvm.c | 1 + - arch/x86/xen/enlighten_pv.c | 8 +- - include/linux/dtrace_fbt.h | 48 +++++++ - kernel/dtrace/Kconfig | 7 + - kernel/dtrace/Makefile | 4 +- - kernel/dtrace/dtrace_fbt_core.c | 125 ++++++++++++++++++ - kernel/dtrace/dtrace_os.c | 2 + - kernel/kprobes.c | 8 ++ - 30 files changed, 764 insertions(+), 98 deletions(-) - create mode 100644 arch/x86/kernel/dtrace_fbt.c - create mode 100644 arch/x86/kernel/fbt_blacklist.h - create mode 100644 include/linux/dtrace_fbt.h - create mode 100644 kernel/dtrace/dtrace_fbt_core.c - -diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S -index cad08703c4ad..689b45e5b0c4 100644 ---- a/arch/x86/entry/entry_64.S -+++ b/arch/x86/entry/entry_64.S -@@ -38,7 +38,7 @@ - #include <asm/frame.h> - #include <asm/trapnr.h> - #include <asm/nospec-branch.h> --#include <asm/fsgsbase.h> -+#include <asm/dtrace_util.h> - #include <linux/err.h> - - #include "calling.h" -@@ -335,6 +335,15 @@ SYM_CODE_END(ret_from_fork) - - call \cfunc - -+#ifdef CONFIG_DTRACE -+ /* -+ * Nonzero exit from a trap handler means we want to emulate -+ * an instruction. -+ */ -+ test %rax,%rax -+ jnz dtrace_error_return -+#endif -+ - jmp error_return - .endm - -@@ -1097,6 +1106,129 @@ SYM_CODE_START_LOCAL(error_return) - jmp swapgs_restore_regs_and_return_to_usermode - SYM_CODE_END(error_return) - -+#ifdef CONFIG_DTRACE -+/* -+ * Emulate an instruction (given by one of the DTRACE_INVOP constants) on exit -+ * from a trap handler. -+ */ -+SYM_CODE_START_LOCAL(dtrace_error_return) -+ UNWIND_HINT_REGS -+ -+ negq %rax -+ -+ cmpl $DTRACE_INVOP_MOV_RSP_RBP,%eax -+ je dtrace_emu_mov -+ cmpl $DTRACE_INVOP_PUSH_BP,%eax -+ je dtrace_emu_push -+ cmpl $DTRACE_INVOP_LEAVE,%eax -+ je dtrace_emu_leave -+ cmpl $DTRACE_INVOP_NOP,%eax -+ je dtrace_emu_nop -+ cmpl $DTRACE_INVOP_RET,%eax -+ je dtrace_emu_ret -+ -+ leaq dtrace_error_msg(%rip),%rdi -+ movq %rax,%rsi -+ movq (%rsp),%rdx -+ call printk -+ -+ jmp error_return -+ -+dtrace_emu_mov: -+ POP_REGS -+ addq $8, %rsp /* skip regs->orig_ax */ -+ -+ /* Emulate "mov %rsp, %rbp" instruction. */ -+ pushq %rax /* push temp */ -+ movq 8(%rsp),%rax /* load calling RIP */ -+ addq $3,%rax /* increment over trapping instr */ -+ movq %rax,8(%rsp) /* store calling RIP */ -+ movq 32(%rsp),%rbp /* load %rsp into %rbp */ -+ popq %rax /* pop off temp */ -+ -+ INTERRUPT_RETURN -+ -+dtrace_emu_push: -+ POP_REGS -+ addq $8, %rsp /* skip regs->orig_ax */ -+ -+ /* -+ * Emulate a "pushq %rbp" instruction. We need to move the stack down -+ * to make room for the extra address getting pushed. -+ */ -+ subq $16,%rsp /* make room for %rbp */ -+ pushq %rax /* push temp */ -+ movq 24(%rsp),%rax /* load calling RIP */ -+ addq $1,%rax /* increment over trapping instr */ -+ movq %rax,8(%rsp) /* store calling RIP */ -+ movq 32(%rsp),%rax /* load calling CS */ -+ movq %rax,16(%rsp) /* store calling CS */ -+ movq 40(%rsp),%rax /* load calling RFLAGS */ -+ movq %rax,24(%rsp) /* store calling RFLAGS */ -+ movq 48(%rsp),%rax /* load calling RSP */ -+ subq $8,%rax /* make room for %rbp */ -+ movq %rax,32(%rsp) /* store calling RSP */ -+ movq 56(%rsp),%rax /* load calling SS */ -+ movq %rax,40(%rsp) /* store calling SS */ -+ movq 32(%rsp),%rax /* reload calling RSP */ -+ movq %rbp,(%rax) /* store %rbp there */ -+ popq %rax /* pop off temp */ -+ -+ INTERRUPT_RETURN -+ -+dtrace_emu_nop: -+ POP_REGS -+ addq $8, %rsp /* skip regs->orig_ax */ -+ -+ /* Emulate a "nop" instruction. */ -+ incq (%rsp) -+ -+ INTERRUPT_RETURN -+ -+dtrace_emu_leave: -+ POP_REGS -+ addq $8, %rsp /* skip regs->orig_ax */ -+ -+ /* -+ * Emulate a "leave" instruction. This is equivalent to the sequence: -+ * movq %rbp,%rsp -+ * popq %rbp -+ * We can use the fact that on x86_64 %rsp is saved explicitly, so we -+ * do not need to move any data around. -+ */ -+ pushq %rax /* push temp */ -+ movq 8(%rsp),%rax /* load calling RIP */ -+ addq $1,%rax /* increment over trapping instr */ -+ movq %rax,8(%rsp) /* store calling RIP */ -+ movq (%rbp),%rax /* get new %rbp */ -+ addq $8,%rbp /* adjust new %rsp */ -+ movq %rbp,32(%rsp) /* store new %rsp */ -+ movq %rax,%rbp /* set new %rbp */ -+ popq %rax /* pop off temp */ -+ -+ INTERRUPT_RETURN -+ -+dtrace_emu_ret: -+ POP_REGS -+ addq $8, %rsp /* skip regs->orig_ax */ -+ -+ /* Emulate a "ret" instruction. */ -+ pushq %rax /* push temp */ -+ movq 32(%rsp),%rax /* load %rsp */ -+ movq (%rax),%rax /* load calling RIP */ -+ movq %rax,8(%rsp) /* store calling RIP */ -+ addq $8,32(%rsp) /* adjust new %rsp */ -+ popq %rax /* pop off temp */ -+ -+ INTERRUPT_RETURN -+SYM_CODE_END(dtrace_error_return) -+ -+.pushsection .rodata, "a" -+dtrace_error_msg: -+ .asciz "DTRACE: non-zero (%x) return from trap at %x\n" -+.popsection -+#endif -+ - /* - * Runs on exception stack. Xen PV does not go through this path at all, - * so we can use real assembly here. -diff --git a/arch/x86/hyperv/hv_init.c b/arch/x86/hyperv/hv_init.c -index 6375967a8244..e22347681c03 100644 ---- a/arch/x86/hyperv/hv_init.c -+++ b/arch/x86/hyperv/hv_init.c -@@ -161,6 +161,7 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_hyperv_reenlightenment) - ack_APIC_irq(); - inc_irq_stat(irq_hv_reenlightenment_count); - schedule_delayed_work(&hv_reenlightenment_work, HZ/10); -+ return 0; - } - - void set_hv_tscchange_cb(void (*cb)(void)) -diff --git a/arch/x86/include/asm/idtentry.h b/arch/x86/include/asm/idtentry.h -index b2442eb0ac2f..2222870fb7ab 100644 ---- a/arch/x86/include/asm/idtentry.h -+++ b/arch/x86/include/asm/idtentry.h -@@ -32,7 +32,7 @@ void idtentry_exit_nmi(struct pt_regs *regs, bool irq_state); - #define DECLARE_IDTENTRY(vector, func) \ - asmlinkage void asm_##func(void); \ - asmlinkage void xen_asm_##func(void); \ -- __visible void func(struct pt_regs *regs) -+ __visible int func(struct pt_regs *regs) - - /** - * DEFINE_IDTENTRY - Emit code for simple IDT entry points -@@ -48,19 +48,21 @@ void idtentry_exit_nmi(struct pt_regs *regs, bool irq_state); - * which has to run before returning to the low level assembly code. - */ - #define DEFINE_IDTENTRY(func) \ --static __always_inline void __##func(struct pt_regs *regs); \ -+static __always_inline int __##func(struct pt_regs *regs); \ - \ --__visible noinstr void func(struct pt_regs *regs) \ -+__visible noinstr int func(struct pt_regs *regs) \ - { \ - irqentry_state_t state = irqentry_enter(regs); \ -+ int ret; \ - \ - instrumentation_begin(); \ -- __##func (regs); \ -+ ret = __##func (regs); \ - instrumentation_end(); \ - irqentry_exit(regs, state); \ -+ return ret; \ - } \ - \ --static __always_inline void __##func(struct pt_regs *regs) -+static __always_inline int __##func(struct pt_regs *regs) - - /* Special case for 32bit IRET 'trap' */ - #define DECLARE_IDTENTRY_SW DECLARE_IDTENTRY -@@ -83,7 +85,7 @@ static __always_inline void __##func(struct pt_regs *regs) - #define DECLARE_IDTENTRY_ERRORCODE(vector, func) \ - asmlinkage void asm_##func(void); \ - asmlinkage void xen_asm_##func(void); \ -- __visible void func(struct pt_regs *regs, unsigned long error_code) -+ __visible int func(struct pt_regs *regs, unsigned long error_code) - - /** - * DEFINE_IDTENTRY_ERRORCODE - Emit code for simple IDT entry points -@@ -93,22 +95,24 @@ static __always_inline void __##func(struct pt_regs *regs) - * Same as DEFINE_IDTENTRY, but has an extra error_code argument - */ - #define DEFINE_IDTENTRY_ERRORCODE(func) \ --static __always_inline void __##func(struct pt_regs *regs, \ -- unsigned long error_code); \ -+static __always_inline int __##func(struct pt_regs *regs, \ -+ unsigned long error_code); \ - \ --__visible noinstr void func(struct pt_regs *regs, \ -- unsigned long error_code) \ -+__visible noinstr int func(struct pt_regs *regs, \ -+ unsigned long error_code) \ - { \ - irqentry_state_t state = irqentry_enter(regs); \ -+ int ret; \ - \ - instrumentation_begin(); \ -- __##func (regs, error_code); \ -+ ret = __##func (regs, error_code); \ - instrumentation_end(); \ - irqentry_exit(regs, state); \ -+ return ret; \ - } \ - \ --static __always_inline void __##func(struct pt_regs *regs, \ -- unsigned long error_code) -+static __always_inline int __##func(struct pt_regs *regs, \ -+ unsigned long error_code) - - /** - * DECLARE_IDTENTRY_RAW - Declare functions for raw IDT entry points -@@ -136,7 +140,7 @@ static __always_inline void __##func(struct pt_regs *regs, \ - * is required before the enter/exit() helpers are invoked. - */ - #define DEFINE_IDTENTRY_RAW(func) \ --__visible noinstr void func(struct pt_regs *regs) -+__visible noinstr int func(struct pt_regs *regs) - - /** - * DECLARE_IDTENTRY_RAW_ERRORCODE - Declare functions for raw IDT entry points -@@ -164,7 +168,7 @@ __visible noinstr void func(struct pt_regs *regs) - * is required before the enter/exit() helpers are invoked. - */ - #define DEFINE_IDTENTRY_RAW_ERRORCODE(func) \ --__visible noinstr void func(struct pt_regs *regs, unsigned long error_code) -+__visible noinstr int func(struct pt_regs *regs, unsigned long error_code) - - /** - * DECLARE_IDTENTRY_IRQ - Declare functions for device interrupt IDT entry -@@ -190,23 +194,25 @@ __visible noinstr void func(struct pt_regs *regs, unsigned long error_code) - * has to be done in the function body if necessary. - */ - #define DEFINE_IDTENTRY_IRQ(func) \ --static __always_inline void __##func(struct pt_regs *regs, u8 vector); \ -+static __always_inline int __##func(struct pt_regs *regs, u8 vector); \ - \ --__visible noinstr void func(struct pt_regs *regs, \ -- unsigned long error_code) \ -+__visible noinstr int func(struct pt_regs *regs, \ -+ unsigned long error_code) \ - { \ - irqentry_state_t state = irqentry_enter(regs); \ -+ int ret; \ - \ - instrumentation_begin(); \ - irq_enter_rcu(); \ - kvm_set_cpu_l1tf_flush_l1d(); \ -- __##func (regs, (u8)error_code); \ -+ ret = __##func (regs, (u8)error_code); \ - irq_exit_rcu(); \ - instrumentation_end(); \ - irqentry_exit(regs, state); \ -+ return ret; \ - } \ - \ --static __always_inline void __##func(struct pt_regs *regs, u8 vector) -+static __always_inline int __##func(struct pt_regs *regs, u8 vector) - - /** - * DECLARE_IDTENTRY_SYSVEC - Declare functions for system vector entry points -@@ -233,22 +239,24 @@ static __always_inline void __##func(struct pt_regs *regs, u8 vector) - * Runs the function on the interrupt stack if the entry hit kernel mode - */ - #define DEFINE_IDTENTRY_SYSVEC(func) \ --static void __##func(struct pt_regs *regs); \ -+static int __##func(struct pt_regs *regs); \ - \ --__visible noinstr void func(struct pt_regs *regs) \ -+__visible noinstr int func(struct pt_regs *regs) \ - { \ - irqentry_state_t state = irqentry_enter(regs); \ -+ int ret; \ - \ - instrumentation_begin(); \ - irq_enter_rcu(); \ - kvm_set_cpu_l1tf_flush_l1d(); \ -- run_sysvec_on_irqstack_cond(__##func, regs); \ -+ ret = run_sysvec_on_irqstack_cond(__##func, regs); \ - irq_exit_rcu(); \ - instrumentation_end(); \ - irqentry_exit(regs, state); \ -+ return ret; \ - } \ - \ --static noinline void __##func(struct pt_regs *regs) -+static noinline int __##func(struct pt_regs *regs) - - /** - * DEFINE_IDTENTRY_SYSVEC_SIMPLE - Emit code for simple system vector IDT -@@ -262,22 +270,24 @@ static noinline void __##func(struct pt_regs *regs) - * interrupt vectors. - */ - #define DEFINE_IDTENTRY_SYSVEC_SIMPLE(func) \ --static __always_inline void __##func(struct pt_regs *regs); \ -+static __always_inline int __##func(struct pt_regs *regs); \ - \ --__visible noinstr void func(struct pt_regs *regs) \ -+__visible noinstr int func(struct pt_regs *regs) \ - { \ - irqentry_state_t state = irqentry_enter(regs); \ -+ int ret; \ - \ - instrumentation_begin(); \ - __irq_enter_raw(); \ - kvm_set_cpu_l1tf_flush_l1d(); \ -- __##func (regs); \ -+ ret = __##func (regs); \ - __irq_exit_raw(); \ - instrumentation_end(); \ - irqentry_exit(regs, state); \ -+ return ret; \ - } \ - \ --static __always_inline void __##func(struct pt_regs *regs) -+static __always_inline int __##func(struct pt_regs *regs) - - /** - * DECLARE_IDTENTRY_XENCB - Declare functions for XEN HV callback entry point -@@ -306,7 +316,7 @@ static __always_inline void __##func(struct pt_regs *regs) - */ - #define DECLARE_IDTENTRY_IST(vector, func) \ - DECLARE_IDTENTRY_RAW(vector, func); \ -- __visible void noist_##func(struct pt_regs *regs) -+ __visible int noist_##func(struct pt_regs *regs) - - /** - * DECLARE_IDTENTRY_VC - Declare functions for the VC entry point -@@ -318,8 +328,8 @@ static __always_inline void __##func(struct pt_regs *regs) - */ - #define DECLARE_IDTENTRY_VC(vector, func) \ - DECLARE_IDTENTRY_RAW_ERRORCODE(vector, func); \ -- __visible noinstr void ist_##func(struct pt_regs *regs, unsigned long error_code); \ -- __visible noinstr void safe_stack_##func(struct pt_regs *regs, unsigned long error_code) -+ __visible noinstr int ist_##func(struct pt_regs *regs, unsigned long error_code); \ -+ __visible noinstr int safe_stack_##func(struct pt_regs *regs, unsigned long error_code) - - /** - * DEFINE_IDTENTRY_IST - Emit code for IST entry points -@@ -401,10 +411,10 @@ static __always_inline void __##func(struct pt_regs *regs) - * - The C handler called from the C shim - */ - #define DECLARE_IDTENTRY_DF(vector, func) \ -- asmlinkage void asm_##func(void); \ -- __visible void func(struct pt_regs *regs, \ -- unsigned long error_code, \ -- unsigned long address) -+ asmlinkage int asm_##func(void); \ -+ __visible int func(struct pt_regs *regs, \ -+ unsigned long error_code, \ -+ unsigned long address) - - /** - * DEFINE_IDTENTRY_DF - Emit code for double fault on 32bit -@@ -414,9 +424,9 @@ static __always_inline void __##func(struct pt_regs *regs) - * cr2 in the address argument. - */ - #define DEFINE_IDTENTRY_DF(func) \ --__visible noinstr void func(struct pt_regs *regs, \ -- unsigned long error_code, \ -- unsigned long address) -+__visible noinstr int func(struct pt_regs *regs, \ -+ unsigned long error_code, \ -+ unsigned long address) - - #endif /* !CONFIG_X86_64 */ - -diff --git a/arch/x86/include/asm/irq_stack.h b/arch/x86/include/asm/irq_stack.h -index 775816965c6a..04f91986cee3 100644 ---- a/arch/x86/include/asm/irq_stack.h -+++ b/arch/x86/include/asm/irq_stack.h -@@ -12,11 +12,11 @@ static __always_inline bool irqstack_active(void) - return __this_cpu_read(irq_count) != -1; - } - --void asm_call_on_stack(void *sp, void (*func)(void), void *arg); --void asm_call_sysvec_on_stack(void *sp, void (*func)(struct pt_regs *regs), -- struct pt_regs *regs); --void asm_call_irq_on_stack(void *sp, void (*func)(struct irq_desc *desc), -- struct irq_desc *desc); -+int asm_call_on_stack(void *sp, void (*func)(void), void *arg); -+int asm_call_sysvec_on_stack(void *sp, int (*func)(struct pt_regs *regs), -+ struct pt_regs *regs); -+int asm_call_irq_on_stack(void *sp, void (*func)(struct irq_desc *desc), -+ struct irq_desc *desc); - - static __always_inline void __run_on_irqstack(void (*func)(void)) - { -@@ -27,15 +27,17 @@ static __always_inline void __run_on_irqstack(void (*func)(void)) - __this_cpu_sub(irq_count, 1); - } - --static __always_inline void --__run_sysvec_on_irqstack(void (*func)(struct pt_regs *regs), -+static __always_inline int -+__run_sysvec_on_irqstack(int (*func)(struct pt_regs *regs), - struct pt_regs *regs) - { - void *tos = __this_cpu_read(hardirq_stack_ptr); -+ int ret; - - __this_cpu_add(irq_count, 1); -- asm_call_sysvec_on_stack(tos - 8, func, regs); -+ ret = asm_call_sysvec_on_stack(tos - 8, func, regs); - __this_cpu_sub(irq_count, 1); -+ return ret; - } - - static __always_inline void -@@ -51,11 +53,11 @@ __run_irq_on_irqstack(void (*func)(struct irq_desc *desc), - - #else /* CONFIG_X86_64 */ - static inline bool irqstack_active(void) { return false; } --static inline void __run_on_irqstack(void (*func)(void)) { } --static inline void __run_sysvec_on_irqstack(void (*func)(struct pt_regs *regs), -- struct pt_regs *regs) { } --static inline void __run_irq_on_irqstack(void (*func)(struct irq_desc *desc), -- struct irq_desc *desc) { } -+static inline int __run_on_irqstack(int (*func)(void)) { } -+static inline int __run_sysvec_on_irqstack(int (*func)(struct pt_regs *regs), -+ struct pt_regs *regs) { } -+static inline int __run_irq_on_irqstack(int (*func)(struct irq_desc *desc), -+ struct irq_desc *desc) { } - #endif /* !CONFIG_X86_64 */ - - static __always_inline bool irq_needs_irq_stack(struct pt_regs *regs) -@@ -79,16 +81,16 @@ static __always_inline void run_on_irqstack_cond(void (*func)(void), - func(); - } - --static __always_inline void --run_sysvec_on_irqstack_cond(void (*func)(struct pt_regs *regs), -+static __always_inline int -+run_sysvec_on_irqstack_cond(int (*func)(struct pt_regs *regs), - struct pt_regs *regs) - { - lockdep_assert_irqs_disabled(); - - if (irq_needs_irq_stack(regs)) -- __run_sysvec_on_irqstack(func, regs); -+ return __run_sysvec_on_irqstack(func, regs); - else -- func(regs); -+ return func(regs); - } - - static __always_inline void -diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c -index 113f6ca7b828..06bd0bf3ae5a 100644 ---- a/arch/x86/kernel/apic/apic.c -+++ b/arch/x86/kernel/apic/apic.c -@@ -1098,6 +1098,7 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_apic_timer_interrupt) - trace_local_timer_exit(LOCAL_TIMER_VECTOR); - - set_irq_regs(old_regs); -+ return 0; - } - - int setup_profiling_timer(unsigned int multiplier) -@@ -2160,11 +2161,13 @@ DEFINE_IDTENTRY_IRQ(spurious_interrupt) - } - out: - trace_spurious_apic_exit(vector); -+ return 0; - } - - DEFINE_IDTENTRY_SYSVEC(sysvec_spurious_apic_interrupt) - { - __spurious_interrupt(regs, SPURIOUS_APIC_VECTOR); -+ return 0; - } - - /* -@@ -2207,6 +2210,7 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_error_interrupt) - apic_printk(APIC_DEBUG, KERN_CONT "\n"); - - trace_error_apic_exit(ERROR_APIC_VECTOR); -+ return 0; - } - - /** -diff --git a/arch/x86/kernel/apic/vector.c b/arch/x86/kernel/apic/vector.c -index 758bbf25ef74..a841e833f267 100644 ---- a/arch/x86/kernel/apic/vector.c -+++ b/arch/x86/kernel/apic/vector.c -@@ -887,6 +887,7 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_irq_move_cleanup) - } - - raw_spin_unlock(&vector_lock); -+ return 0; - } - - static void __send_cleanup_vector(struct apic_chip_data *apicd) -diff --git a/arch/x86/kernel/cpu/acrn.c b/arch/x86/kernel/cpu/acrn.c -index 0b2c03943ac6..b17c61c16e99 100644 ---- a/arch/x86/kernel/cpu/acrn.c -+++ b/arch/x86/kernel/cpu/acrn.c -@@ -53,6 +53,7 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_acrn_hv_callback) - acrn_intr_handler(); - - set_irq_regs(old_regs); -+ return 0; - } - - const __initconst struct hypervisor_x86 x86_hyper_acrn = { -diff --git a/arch/x86/kernel/cpu/mce/amd.c b/arch/x86/kernel/cpu/mce/amd.c -index 0c6b02dd744c..8126b080d488 100644 ---- a/arch/x86/kernel/cpu/mce/amd.c -+++ b/arch/x86/kernel/cpu/mce/amd.c -@@ -928,6 +928,7 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_deferred_error) - deferred_error_int_vector(); - trace_deferred_error_apic_exit(DEFERRED_ERROR_VECTOR); - ack_APIC_irq(); -+ return 0; - } - - /* -diff --git a/arch/x86/kernel/cpu/mce/core.c b/arch/x86/kernel/cpu/mce/core.c -index 311688202ea5..e94cf10e05f7 100644 ---- a/arch/x86/kernel/cpu/mce/core.c -+++ b/arch/x86/kernel/cpu/mce/core.c -@@ -2030,6 +2030,7 @@ DEFINE_IDTENTRY_MCE(exc_machine_check) - dr7 = local_db_save(); - exc_machine_check_kernel(regs); - local_db_restore(dr7); -+ return 0; - } - - /* The user mode variant. */ -@@ -2040,6 +2041,7 @@ DEFINE_IDTENTRY_MCE_USER(exc_machine_check) - dr7 = local_db_save(); - exc_machine_check_user(regs); - local_db_restore(dr7); -+ return 0; - } - #else - /* 32bit unified entry point */ -@@ -2053,6 +2055,7 @@ DEFINE_IDTENTRY_RAW(exc_machine_check) - else - exc_machine_check_kernel(regs); - local_db_restore(dr7); -+ return 0; - } - #endif - -diff --git a/arch/x86/kernel/cpu/mce/therm_throt.c b/arch/x86/kernel/cpu/mce/therm_throt.c -index a7cd2d203ced..8e86a3baf32e 100644 ---- a/arch/x86/kernel/cpu/mce/therm_throt.c -+++ b/arch/x86/kernel/cpu/mce/therm_throt.c -@@ -621,6 +621,7 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_thermal) - smp_thermal_vector(); - trace_thermal_apic_exit(THERMAL_APIC_VECTOR); - ack_APIC_irq(); -+ return 0; - } - - /* Thermal monitoring depends on APIC, ACPI and clock modulation */ -diff --git a/arch/x86/kernel/cpu/mce/threshold.c b/arch/x86/kernel/cpu/mce/threshold.c -index 6a059a035021..fa361a5b297a 100644 ---- a/arch/x86/kernel/cpu/mce/threshold.c -+++ b/arch/x86/kernel/cpu/mce/threshold.c -@@ -28,4 +28,5 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_threshold) - mce_threshold_vector(); - trace_threshold_apic_exit(THRESHOLD_APIC_VECTOR); - ack_APIC_irq(); -+ return 0; - } -diff --git a/arch/x86/kernel/cpu/mshyperv.c b/arch/x86/kernel/cpu/mshyperv.c -index 6cc50ab07bde..5146b1f713e0 100644 ---- a/arch/x86/kernel/cpu/mshyperv.c -+++ b/arch/x86/kernel/cpu/mshyperv.c -@@ -53,6 +53,7 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_hyperv_callback) - ack_APIC_irq(); - - set_irq_regs(old_regs); -+ return 0; - } - - int hv_setup_vmbus_irq(int irq, void (*handler)(void)) -@@ -88,6 +89,7 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_hyperv_stimer0) - ack_APIC_irq(); - - set_irq_regs(old_regs); -+ return 0; - } - - int hv_setup_stimer0_irq(int *irq, int *vector, void (*handler)(void)) -diff --git a/arch/x86/kernel/dtrace_fbt.c b/arch/x86/kernel/dtrace_fbt.c -new file mode 100644 -index 000000000000..52ff3f49d101 ---- /dev/null -+++ b/arch/x86/kernel/dtrace_fbt.c -@@ -0,0 +1,177 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_fbt.c -+ * DESCRIPTION: Dynamic Tracing: FBT registration code (arch-specific) -+ * -+ * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/kallsyms.h> -+#include <linux/dtrace_os.h> -+#include <linux/dtrace_fbt.h> -+#include <linux/slab.h> -+#include <linux/sort.h> -+#include <asm/insn.h> -+#include <asm/sections.h> -+ -+#define FBT_MOV_RSP_RBP_1 0x48 -+#define FBT_MOV_RSP_RBP_2 0x89 -+#define FBT_MOV_RSP_RBP_3 0xe5 -+#define FBT_PUSHL_EBP 0x55 -+#define FBT_NOP 0x90 -+#define FBT_RET_IMM16 0xc2 -+#define FBT_RET 0xc3 -+#define FBT_LEAVE 0xc9 -+ -+#define BL_SENTRY(tp, nm) extern tp nm; -+#define BL_DENTRY(tp, nm) -+#include "fbt_blacklist.h" -+#undef BL_DENTRY -+#undef BL_SENTRY -+ -+static void -+dtrace_fbt_populate_bl(void) -+{ -+#define BL_SENTRY(tp, nm) dtrace_fbt_bl_add((unsigned long)&nm, \ -+ __stringify(nm)); -+#define BL_DENTRY(tp, nm) dtrace_fbt_bl_add(0, __stringify(nm)); -+#include "fbt_blacklist.h" -+#undef BL_SENTRY -+#undef BL_DENTRY -+} -+ -+void dtrace_fbt_init(fbt_add_probe_fn fbt_add_probe, struct module *mp, -+ void *arg) -+{ -+ loff_t pos; -+ struct kallsym_iter sym; -+ asm_instr_t *paddr = NULL; -+ struct dt_fbt_bl_entry *blent = NULL; -+ -+ /* -+ * Look up any unresolved symbols in the blacklist, and sort the list -+ * by ascending address. -+ */ -+ dtrace_fbt_populate_bl(); -+ blent = dtrace_fbt_bl_first(); -+ -+ pos = 0; -+ kallsyms_iter_reset(&sym, 0); -+ while (kallsyms_iter_update(&sym, pos++)) { -+ asm_instr_t *addr, *end; -+ int state = 0, insc = 0; -+ void *fbtp = NULL; -+ -+ /* -+ * There is no point considering non-function symbols for FBT, -+ * or symbols that have a zero size. We could consider weak -+ * symbols but that gets quite complicated and there is no -+ * demands for that (so far). -+ */ -+ if (sym.type != 'T' && sym.type != 't') -+ continue; -+ if (!sym.size) -+ continue; -+ -+ /* -+ * Handle only symbols that belong to the module we have been -+ * asked for. -+ */ -+ if (mp == dtrace_kmod && !core_kernel_text(sym.value)) -+ continue; -+ -+ /* -+ * Ensure we have not been given .init symbol from kallsyms -+ * interface. This could lead to memory corruption once DTrace -+ * tries to enable probe in already freed memory. -+ */ -+ if (mp != dtrace_kmod && !within_module_core(sym.value, mp)) -+ continue; -+ -+ /* -+ * See if the symbol is on the FBT's blacklist. Since both -+ * iterators are workng in sort order by ascending address we -+ * can use concurrent traversal. -+ */ -+ while (blent != NULL && -+ dtrace_fbt_bl_entry_addr(blent) < sym.value) { -+ blent = dtrace_fbt_bl_next(blent); -+ } -+ if (dtrace_fbt_bl_entry_addr(blent) == sym.value) -+ continue; -+ -+ /* -+ * No FBT tracing for DTrace functions, and functions that are -+ * crucial to probe processing. -+ * Also weed out symbols that are not relevant here. -+ */ -+ if (strncmp(sym.name, "dtrace_", 7) == 0) -+ continue; -+ if (strncmp(sym.name, "insn_", 5) == 0) -+ continue; -+ if (strncmp(sym.name, "inat_", 5) == 0) -+ continue; -+ if (strncmp(sym.name, "_GLOBAL_", 8) == 0) -+ continue; -+ if (strncmp(sym.name, "do_", 3) == 0) -+ continue; -+ if (strncmp(sym.name, "xen_", 4) == 0) -+ continue; -+ -+ addr = (asm_instr_t *)sym.value; -+ end = (asm_instr_t *)(sym.value + sym.size); -+ -+ /* -+ * FIXME: -+ * When there are multiple symbols for the same address, we -+ * should link them together as probes associated with the -+ * same function. When a probe for that function is triggered -+ * all associated probes should fire. -+ * -+ * For now, we ignore duplicates. -+ */ -+ if (addr == paddr) -+ continue; -+ paddr = addr; -+ -+ while (addr < end) { -+ struct insn insn; -+ -+ insc++; -+ -+ switch (state) { -+ case 0: /* start of function */ -+ if (*addr == FBT_PUSHL_EBP) { -+ fbt_add_probe( -+ mp, sym.name, -+ FBT_ENTRY, *addr, addr, 0, -+ NULL, arg); -+ state = 1; -+ } else if (insc > 10) -+ state = 2; -+ break; -+ case 1: /* look for ret */ -+ if (*addr == FBT_RET) { -+ uintptr_t off; -+ -+ off = addr - (asm_instr_t *)sym.value; -+ fbtp = fbt_add_probe( -+ mp, sym.name, -+ FBT_RETURN, *addr, addr, off, -+ fbtp, arg); -+ } -+ break; -+ } -+ -+ if (state == 2) -+ break; -+ -+ kernel_insn_init(&insn, addr, MAX_INSN_SIZE); -+ insn_get_length(&insn); -+ -+ addr += insn.length; -+ } -+ } -+} -+EXPORT_SYMBOL(dtrace_fbt_init); -diff --git a/arch/x86/kernel/fbt_blacklist.h b/arch/x86/kernel/fbt_blacklist.h -new file mode 100644 -index 000000000000..2e1ce2a90c86 ---- /dev/null -+++ b/arch/x86/kernel/fbt_blacklist.h -@@ -0,0 +1,95 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Functions used in die notifier chain calling. -+ */ -+BL_SENTRY(void *, notify_die) -+BL_DENTRY(void *, notifier_call_chain) -+BL_SENTRY(typeof(atomic_notifier_call_chain_robust), atomic_notifier_call_chain_robust) -+BL_SENTRY(typeof(atomic_notifier_call_chain), atomic_notifier_call_chain) -+BL_SENTRY(typeof(raw_notifier_call_chain_robust), raw_notifier_call_chain_robust) -+BL_SENTRY(typeof(raw_notifier_call_chain), raw_notifier_call_chain) -+BL_DENTRY(void *, hw_breakpoint_exceptions_notify) -+BL_DENTRY(void *, kprobe_exceptions_notify) -+ -+/* -+ * Functions used to update vtime in probe context. -+ */ -+BL_SENTRY(typeof(ktime_get_raw_fast_ns), ktime_get_raw_fast_ns) -+BL_DENTRY(void *, raw_read_seqcount) -+BL_DENTRY(void *, read_seqcount_retry) -+BL_DENTRY(void *, __read_seqcount_retry) -+ -+/* xen_clocksource */ -+BL_DENTRY(void *, xen_clocksource_get_cycles) -+BL_DENTRY(void *, xen_clocksource_read) -+BL_DENTRY(void *, pvclock_clocksource_read) -+BL_DENTRY(void *, pvclock_touch_watchdogs) -+BL_DENTRY(void *, touch_softlockup_watchdog_sync) -+BL_DENTRY(void *, clocksource_touch_watchdog) -+BL_DENTRY(void *, clocksource_resume_watchdog) -+BL_DENTRY(void *, reset_hung_task_detector) -+/* clocksource_tsc */ -+BL_DENTRY(void *, read_tsc) -+BL_DENTRY(void *, get_cycles) -+/* clocksource_hpet */ -+BL_DENTRY(void *, read_hpet) -+BL_DENTRY(void *, hpet_readl) -+/* kvm_clock */ -+BL_DENTRY(void *, kvm_clock_get_cycles) -+BL_DENTRY(void *, kvm_clock_read) -+ -+/* -+ * Functions used in trap handling. -+ */ -+BL_DENTRY(void *, fixup_exception) -+BL_DENTRY(void *, paranoid_entry) -+BL_DENTRY(void *, kgdb_ll_trap) -+BL_DENTRY(void *, error_entry) -+BL_DENTRY(void *, xen_int3) -+BL_DENTRY(void *, ftrace_int3_handler) -+BL_DENTRY(typeof(poke_int3_handler), poke_int3_handler) -+BL_DENTRY(void *, fixup_bad_iret) -+BL_DENTRY(void *, xen_adjust_exception_frame) -+BL_DENTRY(void *, paravirt_nop) -+BL_DENTRY(void *, ist_enter) -+BL_DENTRY(void *, rcu_nmi_enter) -+BL_DENTRY(void *, rcu_dynticks_curr_cpu_in_eqs) -+BL_DENTRY(void *, rcu_dynticks_eqs_exit) -+BL_DENTRY(void *, trace_rcu_dyntick) -+BL_DENTRY(void *, rcu_nmi_exit) -+BL_DENTRY(void *, rcu_irq_exit) -+BL_DENTRY(void *, rcu_nmi_exit_common) -+BL_DENTRY(void *, rcu_dynticks_eqs_enter) -+BL_DENTRY(void *, ist_exit) -+ -+/* -+ * Functions used in page fault handling. -+ */ -+BL_DENTRY(void *, do_kern_addr_fault) -+BL_DENTRY(void *, do_kern_addr_fault) -+BL_DENTRY(void *, handle_page_fault) -+BL_DENTRY(void *, huge_page_mask) -+BL_DENTRY(void *, mmap_address_hint_valid) -+BL_DENTRY(void *, vm_start_gap) -+BL_DENTRY(void *, hugetlb_get_unmapped_area_bottomup) -+BL_DENTRY(void *, hugetlb_get_unmapped_area_topdown) -+BL_DENTRY(void *, down_read_trylock) -+BL_DENTRY(void *, __get_user_pages_fast) -+BL_DENTRY(void *, gup_pud_range) -+BL_DENTRY(void *, gup_huge_pud) -+BL_DENTRY(void *, gup_pmd_range) -+BL_DENTRY(void *, gup_huge_pmd) -+BL_DENTRY(void *, gup_pte_range) -+BL_DENTRY(void *, pte_mfn_to_pfn) -+ -+/* -+ * Functions used under 4.12 idr_find -+ */ -+BL_DENTRY(void *, idr_find) -+BL_DENTRY(void *, find_next_bit) -+BL_DENTRY(void *, _find_next_bit) -+BL_DENTRY(void *, radix_tree_lookup) -+BL_DENTRY(void *, __radix_tree_lookup) -+BL_DENTRY(void *, radix_tree_load_root) -+BL_DENTRY(void *, radix_tree_descend) -+BL_DENTRY(void *, is_sibling_entry) -diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c -index c5dd50369e2f..b80211006fb2 100644 ---- a/arch/x86/kernel/irq.c -+++ b/arch/x86/kernel/irq.c -@@ -260,6 +260,7 @@ DEFINE_IDTENTRY_IRQ(common_interrupt) - } - - set_irq_regs(old_regs); -+ return 0; - } - - #ifdef CONFIG_X86_LOCAL_APIC -@@ -279,6 +280,7 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_x86_platform_ipi) - x86_platform_ipi_callback(); - trace_x86_platform_ipi_exit(X86_PLATFORM_IPI_VECTOR); - set_irq_regs(old_regs); -+ return 0; - } - #endif - -@@ -302,6 +304,7 @@ DEFINE_IDTENTRY_SYSVEC_SIMPLE(sysvec_kvm_posted_intr_ipi) - { - ack_APIC_irq(); - inc_irq_stat(kvm_posted_intr_ipis); -+ return 0; - } - - /* -@@ -312,6 +315,7 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_kvm_posted_intr_wakeup_ipi) - ack_APIC_irq(); - inc_irq_stat(kvm_posted_intr_wakeup_ipis); - kvm_posted_intr_wakeup_handler(); -+ return 0; - } - - /* -@@ -321,6 +325,7 @@ DEFINE_IDTENTRY_SYSVEC_SIMPLE(sysvec_kvm_posted_intr_nested_ipi) - { - ack_APIC_irq(); - inc_irq_stat(kvm_posted_intr_nested_ipis); -+ return 0; - } - #endif - -diff --git a/arch/x86/kernel/irq_work.c b/arch/x86/kernel/irq_work.c -index 890d4778cd35..ac74998e2faa 100644 ---- a/arch/x86/kernel/irq_work.c -+++ b/arch/x86/kernel/irq_work.c -@@ -21,6 +21,7 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_irq_work) - inc_irq_stat(apic_irq_work_irqs); - irq_work_run(); - trace_irq_work_exit(IRQ_WORK_VECTOR); -+ return 0; - } - - void arch_irq_work_raise(void) -diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c -index 7f57ede3cb8e..07ea0a6336e9 100644 ---- a/arch/x86/kernel/kvm.c -+++ b/arch/x86/kernel/kvm.c -@@ -285,6 +285,7 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_kvm_asyncpf_interrupt) - } - - set_irq_regs(old_regs); -+ return 0; - } - - static void __init paravirt_ops_setup(void) -diff --git a/arch/x86/kernel/nmi.c b/arch/x86/kernel/nmi.c -index 4bc77aaf1303..c3c8eec1a597 100644 ---- a/arch/x86/kernel/nmi.c -+++ b/arch/x86/kernel/nmi.c -@@ -484,11 +484,11 @@ DEFINE_IDTENTRY_RAW(exc_nmi) - sev_es_nmi_complete(); - - if (IS_ENABLED(CONFIG_SMP) && arch_cpu_is_offline(smp_processor_id())) -- return; -+ return 0; - - if (this_cpu_read(nmi_state) != NMI_NOT_RUNNING) { - this_cpu_write(nmi_state, NMI_LATCHED); -- return; -+ return 0; - } - this_cpu_write(nmi_state, NMI_EXECUTING); - this_cpu_write(nmi_cr2, read_cr2()); -@@ -522,6 +522,7 @@ DEFINE_IDTENTRY_RAW(exc_nmi) - - if (user_mode(regs)) - mds_user_clear_cpu_buffers(); -+ return 0; - } - - void stop_nmi(void) -diff --git a/arch/x86/kernel/sev-es.c b/arch/x86/kernel/sev-es.c -index 84c1821819af..536e85e4932d 100644 ---- a/arch/x86/kernel/sev-es.c -+++ b/arch/x86/kernel/sev-es.c -@@ -1260,7 +1260,7 @@ DEFINE_IDTENTRY_VC_SAFE_STACK(exc_vmm_communication) - */ - if (error_code == SVM_EXIT_EXCP_BASE + X86_TRAP_DB) { - vc_handle_trap_db(regs); -- return; -+ return 0; - } - - instrumentation_begin(); -@@ -1326,7 +1326,7 @@ DEFINE_IDTENTRY_VC_SAFE_STACK(exc_vmm_communication) - out: - instrumentation_end(); - -- return; -+ return 0; - - fail: - if (user_mode(regs)) { -@@ -1359,6 +1359,7 @@ DEFINE_IDTENTRY_VC_IST(exc_vmm_communication) - instrumentation_begin(); - panic("Can't handle #VC exception from unsupported context\n"); - instrumentation_end(); -+ return 0; - } - - DEFINE_IDTENTRY_VC(exc_vmm_communication) -@@ -1367,6 +1368,7 @@ DEFINE_IDTENTRY_VC(exc_vmm_communication) - safe_stack_exc_vmm_communication(regs, error_code); - else - ist_exc_vmm_communication(regs, error_code); -+ return 0; - } - - bool __init handle_vc_boot_ghcb(struct pt_regs *regs) -diff --git a/arch/x86/kernel/smp.c b/arch/x86/kernel/smp.c -index eff4ce3b10da..2b3046a5b07e 100644 ---- a/arch/x86/kernel/smp.c -+++ b/arch/x86/kernel/smp.c -@@ -136,6 +136,7 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_reboot) - ack_APIC_irq(); - cpu_emergency_vmxoff(); - stop_this_cpu(NULL); -+ return 0; - } - - static int register_stop_handler(void) -@@ -229,6 +230,7 @@ DEFINE_IDTENTRY_SYSVEC_SIMPLE(sysvec_reschedule_ipi) - inc_irq_stat(irq_resched_count); - scheduler_ipi(); - trace_reschedule_exit(RESCHEDULE_VECTOR); -+ return 0; - } - - DEFINE_IDTENTRY_SYSVEC(sysvec_call_function) -@@ -238,6 +240,7 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_call_function) - inc_irq_stat(irq_call_count); - generic_smp_call_function_interrupt(); - trace_call_function_exit(CALL_FUNCTION_VECTOR); -+ return 0; - } - - DEFINE_IDTENTRY_SYSVEC(sysvec_call_function_single) -@@ -247,6 +250,7 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_call_function_single) - inc_irq_stat(irq_call_count); - generic_smp_call_function_single_interrupt(); - trace_call_function_single_exit(CALL_FUNCTION_SINGLE_VECTOR); -+ return 0; - } - - static int __init nonmi_ipi_setup(char *str) -diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c -index 170c94ec0068..39f2ab128cc7 100644 ---- a/arch/x86/kernel/traps.c -+++ b/arch/x86/kernel/traps.c -@@ -166,17 +166,20 @@ do_trap(int trapnr, int signr, char *str, struct pt_regs *regs, - } - NOKPROBE_SYMBOL(do_trap); - --static void do_error_trap(struct pt_regs *regs, long error_code, char *str, -+static int do_error_trap(struct pt_regs *regs, long error_code, char *str, - unsigned long trapnr, int signr, int sicode, void __user *addr) - { -+ int ret; -+ - RCU_LOCKDEP_WARN(!rcu_is_watching(), "entry code didn't wake RCU"); - -- if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) != -- NOTIFY_STOP) { -+ ret = notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr); -+ if ((ret & NOTIFY_STOP_MASK) != NOTIFY_STOP_MASK) { - cond_local_irq_enable(regs); - do_trap(trapnr, signr, str, regs, error_code, sicode, addr); - cond_local_irq_disable(regs); - } -+ return notifier_to_errno(ret); - } - - /* -@@ -196,13 +199,14 @@ static __always_inline void __user *error_get_trap_addr(struct pt_regs *regs) - - DEFINE_IDTENTRY(exc_divide_error) - { -- do_error_trap(regs, 0, "divide error", X86_TRAP_DE, SIGFPE, -- FPE_INTDIV, error_get_trap_addr(regs)); -+ return do_error_trap(regs, 0, "divide error", X86_TRAP_DE, SIGFPE, -+ FPE_INTDIV, error_get_trap_addr(regs)); - } - - DEFINE_IDTENTRY(exc_overflow) - { -- do_error_trap(regs, 0, "overflow", X86_TRAP_OF, SIGSEGV, 0, NULL); -+ return do_error_trap(regs, 0, "overflow", X86_TRAP_OF, SIGSEGV, -+ 0, NULL); - } - - #ifdef CONFIG_X86_F00F_BUG -@@ -253,37 +257,38 @@ DEFINE_IDTENTRY_RAW(exc_invalid_op) - * in case exception entry is the one triggering WARNs. - */ - if (!user_mode(regs) && handle_bug(regs)) -- return; -+ return 0; - - state = irqentry_enter(regs); - instrumentation_begin(); - handle_invalid_op(regs); - instrumentation_end(); - irqentry_exit(regs, state); -+ return 0; - } - - DEFINE_IDTENTRY(exc_coproc_segment_overrun) - { -- do_error_trap(regs, 0, "coprocessor segment overrun", -- X86_TRAP_OLD_MF, SIGFPE, 0, NULL); -+ return do_error_trap(regs, 0, "coprocessor segment overrun", -+ X86_TRAP_OLD_MF, SIGFPE, 0, NULL); - } - - DEFINE_IDTENTRY_ERRORCODE(exc_invalid_tss) - { -- do_error_trap(regs, error_code, "invalid TSS", X86_TRAP_TS, SIGSEGV, -- 0, NULL); -+ return do_error_trap(regs, error_code, "invalid TSS", X86_TRAP_TS, -+ SIGSEGV, 0, NULL); - } - - DEFINE_IDTENTRY_ERRORCODE(exc_segment_not_present) - { -- do_error_trap(regs, error_code, "segment not present", X86_TRAP_NP, -- SIGBUS, 0, NULL); -+ return do_error_trap(regs, error_code, "segment not present", X86_TRAP_NP, -+ SIGBUS, 0, NULL); - } - - DEFINE_IDTENTRY_ERRORCODE(exc_stack_segment) - { -- do_error_trap(regs, error_code, "stack segment", X86_TRAP_SS, SIGBUS, -- 0, NULL); -+ return do_error_trap(regs, error_code, "stack segment", X86_TRAP_SS, -+ SIGBUS, 0, NULL); - } - - DEFINE_IDTENTRY_ERRORCODE(exc_alignment_check) -@@ -291,7 +296,7 @@ DEFINE_IDTENTRY_ERRORCODE(exc_alignment_check) - char *str = "alignment check"; - - if (notify_die(DIE_TRAP, str, regs, error_code, X86_TRAP_AC, SIGBUS) == NOTIFY_STOP) -- return; -+ return 0; - - if (!user_mode(regs)) - die("Split lock detected\n", regs, error_code); -@@ -306,6 +311,7 @@ DEFINE_IDTENTRY_ERRORCODE(exc_alignment_check) - - out: - local_irq_disable(); -+ return 0; - } - - #ifdef CONFIG_VMAP_STACK -@@ -402,7 +408,7 @@ DEFINE_IDTENTRY_DF(exc_double_fault) - regs->ip = (unsigned long)asm_exc_general_protection; - regs->sp = (unsigned long)&gpregs->orig_ax; - -- return; -+ return 0; - } - #endif - -@@ -461,13 +467,14 @@ DEFINE_IDTENTRY_DF(exc_double_fault) - die("double fault", regs, error_code); - panic("Machine halted."); - instrumentation_end(); -+ return 0; - } - - DEFINE_IDTENTRY(exc_bounds) - { - if (notify_die(DIE_TRAP, "bounds", regs, 0, - X86_TRAP_BR, SIGSEGV) == NOTIFY_STOP) -- return; -+ return 0; - cond_local_irq_enable(regs); - - if (!user_mode(regs)) -@@ -476,6 +483,7 @@ DEFINE_IDTENTRY(exc_bounds) - do_trap(X86_TRAP_BR, SIGSEGV, "bounds", regs, 0, 0, NULL); - - cond_local_irq_disable(regs); -+ return 0; - } - - enum kernel_gp_hint { -@@ -529,7 +537,7 @@ DEFINE_IDTENTRY_ERRORCODE(exc_general_protection) - enum kernel_gp_hint hint = GP_NO_HINT; - struct task_struct *tsk; - unsigned long gp_addr; -- int ret; -+ int ret = 0; - - cond_local_irq_enable(regs); - -@@ -542,7 +550,7 @@ DEFINE_IDTENTRY_ERRORCODE(exc_general_protection) - local_irq_enable(); - handle_vm86_fault((struct kernel_vm86_regs *) regs, error_code); - local_irq_disable(); -- return; -+ return 0; - } - - tsk = current; -@@ -572,8 +580,10 @@ DEFINE_IDTENTRY_ERRORCODE(exc_general_protection) - goto exit; - - ret = notify_die(DIE_GPF, desc, regs, error_code, X86_TRAP_GP, SIGSEGV); -- if (ret == NOTIFY_STOP) -+ if ((ret & NOTIFY_STOP_MASK) == NOTIFY_STOP_MASK) { -+ ret = notifier_to_errno(ret); - goto exit; -+ } - - if (error_code) - snprintf(desc, sizeof(desc), "segment-related " GPFSTR); -@@ -597,9 +607,10 @@ DEFINE_IDTENTRY_ERRORCODE(exc_general_protection) - - exit: - cond_local_irq_disable(regs); -+ return ret; - } - --static bool do_int3(struct pt_regs *regs) -+static bool do_int3(struct pt_regs *regs, int *error_code) - { - int res; - -@@ -615,28 +626,37 @@ static bool do_int3(struct pt_regs *regs) - #endif - res = notify_die(DIE_INT3, "int3", regs, 0, X86_TRAP_BP, SIGTRAP); - -- return res == NOTIFY_STOP; -+ if ((res & NOTIFY_STOP_MASK) == NOTIFY_STOP_MASK) { -+ *error_code = notifier_to_errno (res); -+ return true; -+ } -+ -+ return false; - } - --static void do_int3_user(struct pt_regs *regs) -+static int do_int3_user(struct pt_regs *regs) - { -- if (do_int3(regs)) -- return; -+ int ret = 0; -+ if (do_int3(regs, &ret)) -+ return ret; - - cond_local_irq_enable(regs); - do_trap(X86_TRAP_BP, SIGTRAP, "int3", regs, 0, 0, NULL); - cond_local_irq_disable(regs); -+ return 0; - } - - DEFINE_IDTENTRY_RAW(exc_int3) - { -+ int ret = 0; -+ - /* - * poke_int3_handler() is completely self contained code; it does (and - * must) *NOT* call out to anything, lest it hits upon yet another - * INT3. - */ - if (poke_int3_handler(regs)) -- return; -+ return 0; - - /* - * irqentry_enter_from_user_mode() uses static_branch_{,un}likely() -@@ -648,17 +668,18 @@ DEFINE_IDTENTRY_RAW(exc_int3) - if (user_mode(regs)) { - irqentry_enter_from_user_mode(regs); - instrumentation_begin(); -- do_int3_user(regs); -+ ret = do_int3_user(regs); - instrumentation_end(); - irqentry_exit_to_user_mode(regs); - } else { - bool irq_state = idtentry_enter_nmi(regs); - instrumentation_begin(); -- if (!do_int3(regs)) -+ if (!do_int3(regs, &ret)) - die("int3", regs, 0); - instrumentation_end(); - idtentry_exit_nmi(regs, irq_state); - } -+ return ret; - } - - #ifdef CONFIG_X86_64 -@@ -988,12 +1009,14 @@ static __always_inline void exc_debug_user(struct pt_regs *regs, - DEFINE_IDTENTRY_DEBUG(exc_debug) - { - exc_debug_kernel(regs, debug_read_clear_dr6()); -+ return 0; - } - - /* User entry, runs on regular task stack */ - DEFINE_IDTENTRY_DEBUG_USER(exc_debug) - { - exc_debug_user(regs, debug_read_clear_dr6()); -+ return 0; - } - #else - /* 32 bit does not have separate entry points. */ -@@ -1005,6 +1028,7 @@ DEFINE_IDTENTRY_RAW(exc_debug) - exc_debug_user(regs, dr6); - else - exc_debug_kernel(regs, dr6); -+ return 0; - } - #endif - -@@ -1058,6 +1082,7 @@ static void math_error(struct pt_regs *regs, int trapnr) - DEFINE_IDTENTRY(exc_coprocessor_error) - { - math_error(regs, X86_TRAP_MF); -+ return 0; - } - - DEFINE_IDTENTRY(exc_simd_coprocessor_error) -@@ -1066,10 +1091,11 @@ DEFINE_IDTENTRY(exc_simd_coprocessor_error) - /* AMD 486 bug: INVD in CPL 0 raises #XF instead of #GP */ - if (!static_cpu_has(X86_FEATURE_XMM)) { - __exc_general_protection(regs, 0); -- return; -+ return 0; - } - } - math_error(regs, X86_TRAP_XF); -+ return 0; - } - - DEFINE_IDTENTRY(exc_spurious_interrupt_bug) -@@ -1093,6 +1119,7 @@ DEFINE_IDTENTRY(exc_spurious_interrupt_bug) - * In theory this could be limited to 32bit, but the handler is not - * hurting and who knows which other CPUs suffer from this. - */ -+ return 0; - } - - DEFINE_IDTENTRY(exc_device_not_available) -@@ -1109,7 +1136,7 @@ DEFINE_IDTENTRY(exc_device_not_available) - math_emulate(&info); - - cond_local_irq_disable(regs); -- return; -+ return 0; - } - #endif - -@@ -1125,6 +1152,7 @@ DEFINE_IDTENTRY(exc_device_not_available) - */ - die("unexpected #NM exception", regs, 0); - } -+ return 0; - } - - #ifdef CONFIG_X86_32 -@@ -1137,6 +1165,7 @@ DEFINE_IDTENTRY_SW(iret_error) - ILL_BADSTK, (void __user *)NULL); - } - local_irq_disable(); -+ return 0; - } - #endif - -diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c -index 5b16183100d0..d5b9734946c3 100644 ---- a/arch/x86/mm/fault.c -+++ b/arch/x86/mm/fault.c -@@ -1493,7 +1493,7 @@ DEFINE_IDTENTRY_RAW_ERRORCODE(exc_page_fault) - * itself. - */ - if (kvm_handle_async_pf(regs, (u32)address)) -- return; -+ return 0; - - /* - * Entry handling for valid #PF from kernel mode is slightly -@@ -1512,4 +1512,5 @@ DEFINE_IDTENTRY_RAW_ERRORCODE(exc_page_fault) - instrumentation_end(); - - irqentry_exit(regs, state); -+ return 0; - } -diff --git a/arch/x86/xen/enlighten_hvm.c b/arch/x86/xen/enlighten_hvm.c -index ec50b7423a4c..1c4b08f2dc3b 100644 ---- a/arch/x86/xen/enlighten_hvm.c -+++ b/arch/x86/xen/enlighten_hvm.c -@@ -129,6 +129,7 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_xen_hvm_callback) - xen_hvm_evtchn_do_upcall(); - - set_irq_regs(old_regs); -+ return 0; - } - - #ifdef CONFIG_KEXEC_CORE -diff --git a/arch/x86/xen/enlighten_pv.c b/arch/x86/xen/enlighten_pv.c -index 4409306364dc..080702bf757b 100644 ---- a/arch/x86/xen/enlighten_pv.c -+++ b/arch/x86/xen/enlighten_pv.c -@@ -563,12 +563,12 @@ static void xen_write_ldt_entry(struct desc_struct *dt, int entrynum, - preempt_enable(); - } - --void noist_exc_debug(struct pt_regs *regs); -+int noist_exc_debug(struct pt_regs *regs); - - DEFINE_IDTENTRY_RAW(xenpv_exc_nmi) - { - /* On Xen PV, NMI doesn't use IST. The C part is the sane as native. */ -- exc_nmi(regs); -+ return exc_nmi(regs); - } - - DEFINE_IDTENTRY_RAW(xenpv_exc_debug) -@@ -578,9 +578,9 @@ DEFINE_IDTENTRY_RAW(xenpv_exc_debug) - * to the correct handler. - */ - if (user_mode(regs)) -- noist_exc_debug(regs); -+ return noist_exc_debug(regs); - else -- exc_debug(regs); -+ return exc_debug(regs); - } - - struct trap_array_entry { -diff --git a/include/linux/dtrace_fbt.h b/include/linux/dtrace_fbt.h -new file mode 100644 -index 000000000000..d11e273cee31 ---- /dev/null -+++ b/include/linux/dtrace_fbt.h -@@ -0,0 +1,48 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ *Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+#ifndef _LINUX_DTRACE_FBT_H -+#define _LINUX_DTRACE_FBT_H -+ -+#include <linux/module.h> -+#include <asm/dtrace_arch.h> -+ -+extern unsigned long dtrace_fbt_nfuncs __attribute__((weak)); -+ -+/* -+ * Prototype for callback function that handles the actual creation of FBT -+ * probes. -+ * -+ * Arguments to pass: -+ * - Pointer to module the probe will belong to -+ * - function name -+ * - probe type (FBT_ENTRY or FBT_RETURN) -+ * - probe subtype (arch-specific) -+ * - address (location of the probe) -+ * - offset from the function start -+ * - return value from previous callback invocation -+ * - cookie passed to dtrace_fbt_init -+ * Returns: -+ * - generic pointer (only to be used to pass back in) -+ */ -+#define FBT_ENTRY 0 -+#define FBT_RETURN 1 -+ -+typedef void *(*fbt_add_probe_fn)(struct module *, char *, int, int, -+ asm_instr_t *, uintptr_t, void *, void *); -+extern void dtrace_fbt_init(fbt_add_probe_fn, struct module *, void *); -+ -+/* -+ * Dynamic blacklist routines. -+ */ -+struct dt_fbt_bl_entry; -+ -+extern struct dt_fbt_bl_entry *dtrace_fbt_bl_add(unsigned long, const char *); -+extern struct dt_fbt_bl_entry *dtrace_fbt_bl_first(void); -+extern struct dt_fbt_bl_entry *dtrace_fbt_bl_next(struct dt_fbt_bl_entry *); -+extern unsigned long dtrace_fbt_bl_entry_addr(struct dt_fbt_bl_entry *); -+extern const char *dtrace_fbt_bl_entry_name(struct dt_fbt_bl_entry *); -+ -+#endif /* _LINUX_DTRACE_FBT_H */ -diff --git a/kernel/dtrace/Kconfig b/kernel/dtrace/Kconfig -index 6bf6620981cd..1f070e49c69f 100644 ---- a/kernel/dtrace/Kconfig -+++ b/kernel/dtrace/Kconfig -@@ -55,6 +55,13 @@ config DT_SDT_PERF - Provides the perf provider, containing a DTrace probe for each - perf-events tracepoint in the system. - -+config DT_FBT -+ tristate "Function boundary tracing" -+ default m -+ select FTRACE -+ help -+ Provides function boundary tracing for functions in the kernel. -+ - config DT_SYSTRACE - tristate "System Call Tracing" - default m -diff --git a/kernel/dtrace/Makefile b/kernel/dtrace/Makefile -index 06329cbe52cb..0e5fb34b7b47 100644 ---- a/kernel/dtrace/Makefile -+++ b/kernel/dtrace/Makefile -@@ -4,11 +4,11 @@ - - DT_CORE_ARCH_OBJS = $(addprefix ../../arch/$(SRCARCH)/kernel/, \ - dtrace_syscall.o dtrace_syscall_stubs.o \ -- dtrace_sdt.o dtrace_util.o) -+ dtrace_fbt.o dtrace_sdt.o dtrace_util.o) - - ifdef CONFIG_DT_CORE - obj-y += cyclic.o dtrace_os.o dtrace_cpu.o \ -- dtrace_sdt_core.o \ -+ dtrace_sdt_core.o dtrace_fbt_core.o \ - dtrace_task.o dtrace_psinfo.o \ - $(DT_CORE_ARCH_OBJS) - endif -diff --git a/kernel/dtrace/dtrace_fbt_core.c b/kernel/dtrace/dtrace_fbt_core.c -new file mode 100644 -index 000000000000..67182a3b13fc ---- /dev/null -+++ b/kernel/dtrace/dtrace_fbt_core.c -@@ -0,0 +1,125 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_fbt_core.c -+ * DESCRIPTION: DTrace - FBT common code -+ * -+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/kallsyms.h> -+#include <linux/rbtree.h> -+#include <linux/slab.h> -+#include <linux/dtrace_fbt.h> -+ -+struct dt_fbt_bl_entry { -+ struct rb_node dfbe_node; -+ unsigned long dfbe_addr; -+ const char *dfbe_name; -+}; -+ -+static struct rb_root dt_fbt_root = RB_ROOT; -+ -+struct dt_fbt_bl_entry * -+dtrace_fbt_bl_add(unsigned long addr, const char *name) -+{ -+ struct rb_node **p = &dt_fbt_root.rb_node; -+ struct rb_node *parent = NULL; -+ struct dt_fbt_bl_entry *entry; -+ -+ /* -+ * If no address was given, we need to do a symbol name lookup: -+ * - If no symbol name was given, we cannot add anything. -+ * - If the lookup failed, we cannot add anything. -+ */ -+ if (addr == 0) { -+ if (name == NULL) -+ return NULL; -+ -+ addr = kallsyms_lookup_name(name); -+ -+ if (addr == 0) -+ return NULL; -+ } -+ -+ /* Find place in the tree. */ -+ while (*p) { -+ parent = *p; -+ entry = rb_entry(parent, struct dt_fbt_bl_entry, dfbe_node); -+ -+ if (addr > entry->dfbe_addr) -+ p = &parent->rb_right; -+ else if (addr < entry->dfbe_addr) -+ p = &parent->rb_left; -+ else -+ return NULL; /* no duplicates please */ -+ } -+ -+ /* Create a new blacklist entry. */ -+ entry = kmalloc(sizeof(*entry), GFP_KERNEL); -+ if (entry == NULL) -+ return NULL; -+ -+ entry->dfbe_name = name; -+ entry->dfbe_addr = addr; -+ -+ /* Update the tree. */ -+ rb_link_node(&entry->dfbe_node, parent, p); -+ rb_insert_color(&entry->dfbe_node, &dt_fbt_root); -+ -+ return entry; -+} -+ -+/* -+ * Iterators for blacklisted symbols. The iteration happens in sort order by -+ * virtual memory address. Symbols with pending resolution are inored. -+ */ -+struct dt_fbt_bl_entry * -+dtrace_fbt_bl_first(void) -+{ -+ struct rb_node *node = rb_first(&dt_fbt_root); -+ -+ if (node == NULL) -+ return (NULL); -+ -+ return rb_entry(node, struct dt_fbt_bl_entry, dfbe_node); -+} -+ -+struct dt_fbt_bl_entry * -+dtrace_fbt_bl_next(struct dt_fbt_bl_entry *entry) -+{ -+ struct rb_node *node = rb_next(&entry->dfbe_node); -+ -+ if (node == NULL) -+ return (NULL); -+ -+ return rb_entry(node, struct dt_fbt_bl_entry, dfbe_node); -+} -+ -+unsigned long -+dtrace_fbt_bl_entry_addr(struct dt_fbt_bl_entry *entry) -+{ -+ if (entry == NULL) -+ return (0); -+ -+ return entry->dfbe_addr; -+} -+ -+const char * -+dtrace_fbt_bl_entry_name(struct dt_fbt_bl_entry *entry) -+{ -+ if (entry == NULL) -+ return (NULL); -+ -+ return entry->dfbe_name; -+} -diff --git a/kernel/dtrace/dtrace_os.c b/kernel/dtrace/dtrace_os.c -index 874e097b84fd..bb5650cf72eb 100644 ---- a/kernel/dtrace/dtrace_os.c -+++ b/kernel/dtrace/dtrace_os.c -@@ -18,6 +18,7 @@ - - #include <linux/binfmts.h> - #include <linux/dtrace_cpu.h> -+#include <linux/dtrace_fbt.h> - #include <linux/dtrace_os.h> - #include <linux/dtrace_sdt.h> - #include <linux/fs.h> -@@ -103,6 +104,7 @@ void __init dtrace_os_init(void) - dtrace_kmod->core_layout.size = 0x2000000; - #endif - -+ dtrace_kmod->num_ftrace_callsites = dtrace_fbt_nfuncs; - dtrace_kmod->state = MODULE_STATE_LIVE; - atomic_inc(&dtrace_kmod->refcnt); - -diff --git a/kernel/kprobes.c b/kernel/kprobes.c -index 41fdbb7953c6..b702c7c484e7 100644 ---- a/kernel/kprobes.c -+++ b/kernel/kprobes.c -@@ -38,6 +38,10 @@ - #include <linux/perf_event.h> - #include <linux/static_call.h> - -+#ifdef CONFIG_DTRACE -+#include <linux/dtrace_fbt.h> -+#endif -+ - #include <asm/sections.h> - #include <asm/cacheflush.h> - #include <asm/errno.h> -@@ -2336,6 +2340,10 @@ int kprobe_add_ksym_blacklist(unsigned long entry) - !kallsyms_lookup_size_offset(entry, &size, &offset)) - return -EINVAL; - -+#ifdef CONFIG_DTRACE -+ dtrace_fbt_bl_add(entry, NULL); -+#endif -+ - ent = kmalloc(sizeof(*ent), GFP_KERNEL); - if (!ent) - return -ENOMEM; --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/dtrace-patches/0015-dtrace-fbt-provider-modular-components.patch b/sys-kernel/cairn-sources/files/5.10.13/dtrace-patches/0015-dtrace-fbt-provider-modular-components.patch deleted file mode 100644 index 700f494ff26d..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/dtrace-patches/0015-dtrace-fbt-provider-modular-components.patch +++ /dev/null @@ -1,683 +0,0 @@ -From b3955b4ec46d8139665fc881dd088e9fcb67ff36 Mon Sep 17 00:00:00 2001 -From: Kris Van Hees <kris.van.hees@oracle.com> -Date: Mon, 19 Nov 2018 18:12:44 +0000 -Subject: [PATCH 15/19] dtrace: fbt provider, modular components - -This uses the fbt machinery added in the previous commit. - -Signed-off-by: Kris Van Hees <kris.van.hees@oracle.com> -Signed-off-by: Nick Alcock <nick.alcock@oracle.com> -Signed-off-by: Tomas Jedlicka <tomas.jedlicka@oracle.com> -Signed-off-by: Eugene Loh <eugene.loh@oracle.com> -Signed-off-by: David Mc Lean <david.mclean@oracle.com> -Signed-off-by: Vincent Lim <vincent.lim@oracle.com> ---- - arch/x86/dtrace/Makefile.arch | 2 + - arch/x86/dtrace/fbt_x86_64.c | 156 ++++++++++++ - arch/x86/dtrace/include/dtrace/fbt_arch.h | 42 ++++ - dtrace/Makefile | 2 + - dtrace/fbt_dev.c | 281 ++++++++++++++++++++++ - dtrace/fbt_impl.h | 52 ++++ - dtrace/fbt_mod.c | 56 +++++ - 7 files changed, 591 insertions(+) - create mode 100644 arch/x86/dtrace/fbt_x86_64.c - create mode 100644 arch/x86/dtrace/include/dtrace/fbt_arch.h - create mode 100644 dtrace/fbt_dev.c - create mode 100644 dtrace/fbt_impl.h - create mode 100644 dtrace/fbt_mod.c - -diff --git a/arch/x86/dtrace/Makefile.arch b/arch/x86/dtrace/Makefile.arch -index e4655557e06a..906fa8c7e17c 100644 ---- a/arch/x86/dtrace/Makefile.arch -+++ b/arch/x86/dtrace/Makefile.arch -@@ -8,8 +8,10 @@ ccflags-y += -I$(srctree)/arch/x86/dtrace/include -Idtrace - - dtrace-obj += dtrace_asm_x86_64.o dtrace_isa_x86_64.o - fasttrap-obj += fasttrap_x86_64.o -+fbt-obj += fbt_x86_64.o - sdt-obj += sdt_x86_64.o - - dtrace-y += $(addprefix $(DTARCHDIR)/, $(dtrace-obj)) - fasttrap-y += $(addprefix $(DTARCHDIR)/, $(fasttrap-obj)) -+fbt-y += $(addprefix $(DTARCHDIR)/, $(fbt-obj)) - sdt-y += $(addprefix $(DTARCHDIR)/, $(sdt-obj)) -diff --git a/arch/x86/dtrace/fbt_x86_64.c b/arch/x86/dtrace/fbt_x86_64.c -new file mode 100644 -index 000000000000..a8a05292be7e ---- /dev/null -+++ b/arch/x86/dtrace/fbt_x86_64.c -@@ -0,0 +1,156 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: fbt_x86_64.c -+ * DESCRIPTION: DTrace - FBT provider implementation for x86 -+ * -+ * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/dtrace_fbt.h> -+#include <linux/vmalloc.h> -+#include <asm/dtrace_util.h> -+ -+#include "dtrace.h" -+#include "dtrace_dev.h" -+#include "fbt_impl.h" -+ -+/* -+ * Use 0xf0 (LOCK Prefix) and X86_TRAP_UD for Invalid Opcode traps to be used. -+ * Use 0xcc (INT 3) and X86_TRAP_BP for Breakpoint traps to be used. -+ */ -+#define FBT_ENTRY_PATCHVAL 0xcc -+#define FBT_ENTRY_TRAP X86_TRAP_BP -+#define FBT_RETURN_PATCHVAL 0xcc -+#define FBT_RETURN_TRAP X86_TRAP_BP -+ -+static uint8_t fbt_invop(struct pt_regs *regs) -+{ -+ struct fbt_probe *fbp = fbt_probetab[FBT_ADDR2NDX(regs->ip)]; -+ -+ for (; fbp != NULL; fbp = fbp->fbp_hashnext) { -+ if ((uintptr_t)fbp->fbp_patchpoint == regs->ip) { -+ struct pt_regs *old = this_cpu_core->cpu_dtrace_regs; -+ -+ this_cpu_core->cpu_dtrace_regs = regs; -+ if (fbp->fbp_roffset == 0) { -+ dtrace_probe(fbp->fbp_id, regs->di, regs->si, -+ regs->dx, regs->cx, regs->r8, -+ regs->r9, 0); -+ } else { -+ dtrace_probe(fbp->fbp_id, fbp->fbp_roffset, -+ regs->ax, 0, 0, 0, 0, 0); -+ } -+ -+ this_cpu_core->cpu_dtrace_regs = old; -+ -+ return fbp->fbp_rval; -+ } -+ } -+ -+ return 0; -+} -+ -+uint64_t fbt_getarg(void *arg, dtrace_id_t id, void *parg, int argno, -+ int aframes) -+{ -+ struct pt_regs *regs = this_cpu_core->cpu_dtrace_regs; -+ uint64_t *st; -+ uint64_t val; -+ -+ if (regs == NULL) -+ return 0; -+ -+ switch (argno) { -+ case 0: -+ return regs->di; -+ case 1: -+ return regs->si; -+ case 2: -+ return regs->dx; -+ case 3: -+ return regs->cx; -+ case 4: -+ return regs->r8; -+ case 5: -+ return regs->r9; -+ } -+ -+ ASSERT(argno > 5); -+ -+ st = (uint64_t *)regs->sp; -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); -+ /* -+ * Skip the topmost slot of the stack because that holds the return -+ * address for the call to the function we are entering. At this point -+ * the BP has not been pushed yet, so we are still working within the -+ * caller's stack frame. -+ */ -+ val = st[1 + argno - 6]; -+ DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); -+ -+ return val; -+} -+ -+void fbt_provide_probe_arch(struct fbt_probe *fbp, int probetype, int stype) -+{ -+ fbp->fbp_patchval = probetype == FBT_ENTRY ? FBT_ENTRY_PATCHVAL -+ : FBT_RETURN_PATCHVAL; -+ fbp->fbp_savedval = *fbp->fbp_patchpoint; -+ fbp->fbp_rval = probetype == FBT_ENTRY ? DTRACE_INVOP_PUSH_BP -+ : DTRACE_INVOP_RET; -+} -+ -+int fbt_can_patch_return_arch(asm_instr_t *addr) -+{ -+ return 1; -+} -+ -+int fbt_provide_module_arch(void *arg, struct module *mp) -+{ -+ return 1; -+} -+ -+void fbt_destroy_module(void *arg, struct module *mp) -+{ -+} -+ -+void fbt_enable_arch(struct fbt_probe *fbp, dtrace_id_t id, void *arg) -+{ -+ dtrace_invop_enable(fbp->fbp_patchpoint, fbp->fbp_patchval); -+} -+ -+void fbt_disable_arch(struct fbt_probe *fbp, dtrace_id_t id, void *arg) -+{ -+ dtrace_invop_disable(fbp->fbp_patchpoint, fbp->fbp_savedval); -+} -+ -+int fbt_dev_init_arch(void) -+{ -+ fbt_probetab_mask = fbt_probetab_size - 1; -+ fbt_probetab = dtrace_vzalloc_try(fbt_probetab_size * -+ sizeof(struct fbt_probe *)); -+ -+ if (fbt_probetab == NULL) -+ return -ENOMEM; -+ -+ return dtrace_invop_add(fbt_invop); -+} -+ -+void fbt_dev_exit_arch(void) -+{ -+ vfree(fbt_probetab); -+ fbt_probetab_mask = 0; -+ fbt_probetab_size = 0; -+ -+ dtrace_invop_remove(fbt_invop); -+} -diff --git a/arch/x86/dtrace/include/dtrace/fbt_arch.h b/arch/x86/dtrace/include/dtrace/fbt_arch.h -new file mode 100644 -index 000000000000..7e90b2b75bba ---- /dev/null -+++ b/arch/x86/dtrace/include/dtrace/fbt_arch.h -@@ -0,0 +1,42 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Dynamic Tracing for Linux - FBT Implementation defines -+ * -+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _X86_64_FBT_ARCH_H -+#define _X86_64_FBT_ARCH_H -+ -+#define FBT_AFRAMES 7 -+ -+struct fbt_probe { -+ char *fbp_name; /* name of probe */ -+ dtrace_id_t fbp_id; /* probe ID */ -+ struct module *fbp_module; /* defining module */ -+ int fbp_primary; /* non-zero if primary mod */ -+ asm_instr_t *fbp_patchpoint;/* patch point */ -+ asm_instr_t fbp_patchval; /* instruction to patch */ -+ asm_instr_t fbp_savedval; /* saved instruction value */ -+ uintptr_t fbp_roffset; /* relative offset */ -+ int fbp_rval; -+ struct fbt_probe *fbp_next; /* next probe */ -+ struct fbt_probe *fbp_hashnext; /* next on hash */ -+}; -+ -+#endif /* _X86_64_FBT_ARCH_H */ -diff --git a/dtrace/Makefile b/dtrace/Makefile -index c7e3fc512a6c..35b8b098123f 100644 ---- a/dtrace/Makefile -+++ b/dtrace/Makefile -@@ -4,6 +4,7 @@ - - obj-$(CONFIG_DT_CORE) += dtrace.o - obj-$(CONFIG_DT_FASTTRAP) += fasttrap.o -+obj-$(CONFIG_DT_FBT) += fbt.o - obj-$(CONFIG_DT_PROFILE) += profile.o - obj-$(CONFIG_DT_SDT) += sdt.o - obj-$(CONFIG_DT_SYSTRACE) += systrace.o -@@ -19,6 +20,7 @@ dtrace-y := dtrace_mod.o dtrace_dev.o \ - dtrace_ptofapi.o dtrace_predicate.o \ - dtrace_spec.o dtrace_state.o dtrace_util.o - fasttrap-y := fasttrap_mod.o fasttrap_dev.o -+fbt-y := fbt_mod.o fbt_dev.o - profile-y := profile_mod.o profile_dev.o - sdt-y := sdt_mod.o sdt_dev.o - systrace-y := systrace_mod.o systrace_dev.o -diff --git a/dtrace/fbt_dev.c b/dtrace/fbt_dev.c -new file mode 100644 -index 000000000000..281fd749aae7 ---- /dev/null -+++ b/dtrace/fbt_dev.c -@@ -0,0 +1,281 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: fbt_dev.c -+ * DESCRIPTION: DTrace - FBT provider device driver -+ * -+ * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/fs.h> -+#include <linux/miscdevice.h> -+#include <linux/kallsyms.h> -+#include <linux/slab.h> -+#include <linux/vmalloc.h> -+#include <linux/dtrace_fbt.h> -+ -+#include "dtrace.h" -+#include "dtrace_dev.h" -+#include "fbt_impl.h" -+ -+#define FBT_PROBETAB_SIZE 0x8000 /* 32k entries -- 128K total */ -+ -+struct fbt_probe **fbt_probetab; -+int fbt_probetab_size = FBT_PROBETAB_SIZE; -+int fbt_probetab_mask; -+ -+static void *fbt_provide_probe(struct module *mp, char *func, int probetype, -+ int stype, asm_instr_t *addr, uintptr_t off, -+ void *pfbt, void *arg) -+{ -+ struct fbt_probe *fbp; -+ struct fbt_probe *prev; -+ int *skipped = arg; -+ -+ switch (probetype) { -+ case FBT_ENTRY: -+ fbp = kzalloc(sizeof(struct fbt_probe), GFP_KERNEL); -+ fbp->fbp_name = kstrdup(func, GFP_KERNEL); -+ if (fbp->fbp_name == NULL) -+ goto err_probe; -+ -+ fbp->fbp_id = dtrace_probe_create(fbt_id, mp->name, func, -+ "entry", FBT_AFRAMES, fbp); -+ if (fbp->fbp_id == DTRACE_IDNONE) -+ goto err_name; -+ -+ fbp->fbp_module = mp; -+ fbp->fbp_primary = 1; /* FIXME */ -+ fbp->fbp_roffset = off; -+ fbp->fbp_patchpoint = addr; -+ fbt_provide_probe_arch(fbp, probetype, stype); -+ -+ fbp->fbp_hashnext = fbt_probetab[FBT_ADDR2NDX(fbp->fbp_patchpoint)]; -+ fbt_probetab[FBT_ADDR2NDX(fbp->fbp_patchpoint)] = fbp; -+ -+ PDATA(mp)->fbt_probe_cnt++; -+ -+ return fbp; -+ case FBT_RETURN: -+ -+ /* Check if we are able to patch this return probe. */ -+ if (!fbt_can_patch_return_arch(addr)) -+ return pfbt; -+ -+ fbp = kzalloc(sizeof(struct fbt_probe), GFP_KERNEL); -+ fbp->fbp_name = kstrdup(func, GFP_KERNEL); -+ if (fbp->fbp_name == NULL) -+ goto err_probe; -+ -+ prev = (struct fbt_probe *)pfbt; -+ if (prev != NULL) { -+ prev->fbp_next = fbp; -+ fbp->fbp_id = prev->fbp_id; -+ } else { -+ fbp->fbp_id = dtrace_probe_create(fbt_id, mp->name, -+ func, "return", -+ FBT_AFRAMES, fbp); -+ if (fbp->fbp_id == DTRACE_IDNONE) -+ goto err_name; -+ } -+ -+ fbp->fbp_module = mp; -+ fbp->fbp_primary = 1; /* FIXME */ -+ fbp->fbp_roffset = off; -+ fbp->fbp_patchpoint = addr; -+ fbt_provide_probe_arch(fbp, probetype, stype); -+ -+ fbp->fbp_hashnext = fbt_probetab[FBT_ADDR2NDX(fbp->fbp_patchpoint)]; -+ fbt_probetab[FBT_ADDR2NDX(fbp->fbp_patchpoint)] = fbp; -+ -+ PDATA(mp)->fbt_probe_cnt++; -+ -+ return fbp; -+ default: -+ pr_info("FBT: Invalid probe type %d (%d) for %s\n", -+ probetype, stype, func); -+ -+ return NULL; -+ } -+ -+err_name: -+ kfree(fbp->fbp_name); -+err_probe: -+ kfree(fbp); -+ (*skipped)++; -+ -+ return NULL; -+} -+ -+void fbt_provide_module(void *arg, struct module *mp) -+{ -+ struct module_use *use; -+ int probes_skipped = 0; -+ -+ /* If module setup has failed then do not provide anything. */ -+ if (PDATA(mp) == NULL) -+ return; -+ -+ /* -+ * Nothing to do if the module FBT probes were already created. -+ */ -+ if (PDATA(mp)->fbt_probe_cnt != 0) -+ return; -+ -+ /* -+ * Do not try to instrument DTrace itself and its modules: -+ * - dtrace module -+ * - all modules depending on dtrace -+ */ -+ if (!strncmp(mp->name, "dtrace", 7)) -+ return; -+ -+ list_for_each_entry(use, &mp->target_list, target_list) { -+ if (!strncmp(use->target->name, "dtrace", 7)) -+ return; -+ } -+ -+ /* -+ * Provide probes. -+ */ -+ if (!fbt_provide_module_arch(arg, mp)) -+ return; -+ -+ dtrace_fbt_init((fbt_add_probe_fn)fbt_provide_probe, mp, -+ &probes_skipped); -+ -+ if (probes_skipped != 0) -+ pr_warn("fbt: Failed to provide %d probes in %s (out of memory)\n", -+ probes_skipped, mp->name); -+} -+ -+int fbt_enable(void *arg, dtrace_id_t id, void *parg) -+{ -+ struct fbt_probe *fbp = parg; -+ struct fbt_probe *curr; -+ -+ /* -+ * Ensure that we have a reference to the module. -+ */ -+ if (!try_module_get(fbp->fbp_module)) -+ return -EAGAIN; -+ -+ /* -+ * If at least one other enabled probe exists for this module, drop the -+ * reference we took above, because we only need one to prevent the -+ * module from being unloaded. -+ */ -+ PDATA(fbp->fbp_module)->enabled_cnt++; -+ if (PDATA(fbp->fbp_module)->enabled_cnt > 1) -+ module_put(fbp->fbp_module); -+ -+ for (curr = fbp; curr != NULL; curr = curr->fbp_next) -+ fbt_enable_arch(curr, id, arg); -+ -+ return 0; -+} -+ -+void fbt_disable(void *arg, dtrace_id_t id, void *parg) -+{ -+ struct fbt_probe *fbp = parg; -+ struct fbt_probe *curr; -+ -+ for (curr = fbp; curr != NULL; curr = curr->fbp_next) -+ fbt_disable_arch(curr, id, arg); -+ -+ /* -+ * If we are disabling a probe, we know it was enabled, and therefore -+ * we know that we have a reference on the module to prevent it from -+ * being unloaded. If we disable the last probe on the module, we can -+ * drop the reference. -+ */ -+ PDATA(fbp->fbp_module)->enabled_cnt--; -+ if (PDATA(fbp->fbp_module)->enabled_cnt == 0) -+ module_put(fbp->fbp_module); -+} -+ -+void fbt_destroy(void *arg, dtrace_id_t id, void *parg) -+{ -+ struct fbt_probe *fbp = parg; -+ struct fbt_probe *hbp, *lst, *nxt; -+ int ndx; -+ struct module *mp = fbp->fbp_module; -+ -+ do { -+ nxt = fbp->fbp_next; -+ -+ ndx = FBT_ADDR2NDX(fbp->fbp_patchpoint); -+ lst = NULL; -+ hbp = fbt_probetab[ndx]; -+ -+ while (hbp != fbp) { -+ ASSERT(hbp != NULL); -+ -+ lst = hbp; -+ hbp = hbp->fbp_hashnext; -+ } -+ -+ if (lst != NULL) -+ lst->fbp_hashnext = fbp->fbp_hashnext; -+ else -+ fbt_probetab[ndx] = fbp->fbp_hashnext; -+ -+ kfree(fbp->fbp_name); -+ kfree(fbp); -+ -+ PDATA(mp)->fbt_probe_cnt--; -+ -+ fbp = nxt; -+ } while (fbp != NULL); -+} -+ -+static int fbt_open(struct inode *inode, struct file *file) -+{ -+ return -EAGAIN; -+} -+ -+static int fbt_close(struct inode *inode, struct file *file) -+{ -+ return 0; -+} -+ -+static const struct file_operations fbt_fops = { -+ .owner = THIS_MODULE, -+ .open = fbt_open, -+ .release = fbt_close, -+}; -+ -+static struct miscdevice fbt_dev = { -+ .minor = DT_DEV_FBT_MINOR, -+ .name = "fbt", -+ .nodename = "dtrace/provider/fbt", -+ .fops = &fbt_fops, -+}; -+ -+int fbt_dev_init(void) -+{ -+ int ret = 0; -+ -+ ret = misc_register(&fbt_dev); -+ if (ret) -+ pr_err("%s: Can't register misc device %d\n", -+ fbt_dev.name, fbt_dev.minor); -+ -+ return fbt_dev_init_arch(); -+} -+ -+void fbt_dev_exit(void) -+{ -+ fbt_dev_exit_arch(); -+ -+ misc_deregister(&fbt_dev); -+} -diff --git a/dtrace/fbt_impl.h b/dtrace/fbt_impl.h -new file mode 100644 -index 000000000000..85f83e704988 ---- /dev/null -+++ b/dtrace/fbt_impl.h -@@ -0,0 +1,52 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Dynamic Tracing for Linux - Function Boundary Tracing provider -+ * -+ * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#ifndef _FBT_H_ -+#define _FBT_H_ -+ -+#include <asm/dtrace_arch.h> -+#include <dtrace/fbt_arch.h> -+ -+#define FBT_ADDR2NDX(addr) ((((uintptr_t)(addr)) >> 4) & \ -+ fbt_probetab_mask) -+ -+extern struct fbt_probe **fbt_probetab; -+extern int fbt_probetab_size; -+extern int fbt_probetab_mask; -+ -+extern void fbt_provide_probe_arch(struct fbt_probe *, int, int); -+extern void fbt_enable_arch(struct fbt_probe *, dtrace_id_t, void *); -+extern void fbt_disable_arch(struct fbt_probe *, dtrace_id_t, void *); -+extern int fbt_can_patch_return_arch(asm_instr_t *); -+ -+extern int fbt_provide_module_arch(void *, struct module *); -+extern void fbt_provide_module(void *, struct module *); -+extern void fbt_destroy_module(void *, struct module *); -+extern int fbt_enable(void *, dtrace_id_t, void *); -+extern void fbt_disable(void *, dtrace_id_t, void *); -+extern uint64_t fbt_getarg(void *, dtrace_id_t, void *, int, int); -+extern void fbt_destroy(void *, dtrace_id_t, void *); -+ -+extern dtrace_provider_id_t fbt_id; -+ -+extern int fbt_dev_init_arch(void); -+extern void fbt_dev_exit_arch(void); -+ -+extern int fbt_dev_init(void); -+extern void fbt_dev_exit(void); -+ -+#endif /* _FBT_H_ */ -diff --git a/dtrace/fbt_mod.c b/dtrace/fbt_mod.c -new file mode 100644 -index 000000000000..3da13d71809d ---- /dev/null -+++ b/dtrace/fbt_mod.c -@@ -0,0 +1,56 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: fbt_mod.c -+ * DESCRIPTION: DTrace - FBT provider kernel module -+ * -+ * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/module.h> -+ -+#include "dtrace.h" -+#include "dtrace_dev.h" -+#include "fbt_impl.h" -+ -+MODULE_AUTHOR("Kris Van Hees (kris.van.hees@oracle.com)"); -+MODULE_DESCRIPTION("Function Boundary Tracing"); -+MODULE_VERSION("v0.1"); -+MODULE_LICENSE("GPL"); -+ -+static const struct dtrace_pattr fbt_attr = { -+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA }, -+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA }, -+}; -+ -+static struct dtrace_pops fbt_pops = { -+ .dtps_provide = NULL, -+ .dtps_provide_module = fbt_provide_module, -+ .dtps_destroy_module = fbt_destroy_module, -+ .dtps_enable = fbt_enable, -+ .dtps_disable = fbt_disable, -+ .dtps_suspend = NULL, -+ .dtps_resume = NULL, -+ .dtps_getargdesc = NULL, -+#ifdef CONFIG_X86_64 -+ .dtps_getargval = fbt_getarg, -+#else -+ .dtps_getargval = NULL, -+#endif -+ .dtps_usermode = NULL, -+ .dtps_destroy = fbt_destroy -+}; -+ -+DT_PROVIDER_MODULE(fbt, DTRACE_PRIV_KERNEL) --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/dtrace-patches/0016-dtrace-arm-arm64-port.patch b/sys-kernel/cairn-sources/files/5.10.13/dtrace-patches/0016-dtrace-arm-arm64-port.patch deleted file mode 100644 index a0e8ded1a459..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/dtrace-patches/0016-dtrace-arm-arm64-port.patch +++ /dev/null @@ -1,2667 +0,0 @@ -From 7448665d4354efd9fafea1149cc2adc31dc98c64 Mon Sep 17 00:00:00 2001 -From: Kris Van Hees <kris.van.hees@oracle.com> -Date: Thu, 8 Nov 2018 18:57:33 +0000 -Subject: [PATCH 16/19] dtrace, arm: arm64 port - -This provides an arm64 implementation of DTrace. - -Signed-off-by: Nick Alcock <nick.alcock@oracle.com> -Signed-off-by: Kris Van Hees <kris.van.hees@oracle.com> -Signed-off-by: Tomas Jedlicka <tomas.jedlicka@oracle.com> -Signed-off-by: Eugene Loh <eugene.loh@oracle.com> -Signed-off-by: David Mc Lean <david.mclean@oracle.com> -Signed-off-by: Vincent Lim <vincent.lim@oracle.com> ---- - arch/arm64/Kconfig | 3 + - arch/arm64/dtrace/Makefile.arch | 17 + - arch/arm64/dtrace/dtrace_asm_arm64.S | 51 +++ - arch/arm64/dtrace/dtrace_isa_arm64.c | 164 +++++++ - arch/arm64/dtrace/fasttrap_arm64.c | 282 ++++++++++++ - arch/arm64/dtrace/fbt_arm64.c | 152 +++++++ - .../dtrace/include/dtrace/fasttrap_arch.h | 30 ++ - arch/arm64/dtrace/include/dtrace/fbt_arch.h | 53 +++ - arch/arm64/dtrace/include/dtrace/sdt_arch.h | 28 ++ - arch/arm64/dtrace/sdt_arm64.c | 122 +++++ - arch/arm64/include/asm/brk-imm.h | 6 + - arch/arm64/include/asm/cpu.h | 1 + - arch/arm64/include/asm/debug-monitors.h | 4 + - arch/arm64/include/asm/dtrace_arch.h | 31 ++ - arch/arm64/include/asm/dtrace_cpuinfo.h | 13 + - arch/arm64/include/asm/dtrace_sdt_arch.h | 15 + - arch/arm64/include/asm/dtrace_syscall.h | 3 + - arch/arm64/include/asm/dtrace_syscall_types.h | 11 + - arch/arm64/include/asm/dtrace_util.h | 14 + - arch/arm64/include/asm/kdebug.h | 11 + - arch/arm64/include/asm/syscall.h | 8 +- - arch/arm64/kernel/dtrace_fbt.c | 187 ++++++++ - arch/arm64/kernel/dtrace_sdt.c | 25 ++ - arch/arm64/kernel/dtrace_syscall.c | 89 ++++ - arch/arm64/kernel/dtrace_syscall_stubs.S | 0 - arch/arm64/kernel/dtrace_util.c | 292 ++++++++++++ - arch/arm64/kernel/entry-common.c | 6 +- - arch/arm64/kernel/entry.S | 53 ++- - arch/arm64/kernel/fbt_blacklist.h | 91 ++++ - arch/arm64/kernel/probes/uprobes.c | 3 +- - arch/arm64/kernel/sys.c | 2 +- - arch/arm64/mm/fault.c | 18 + - include/linux/uprobes.h | 1 + - kernel/events/uprobes.c | 10 + - scripts/dtrace_sdt_arm64.sh | 425 ++++++++++++++++++ - scripts/link-vmlinux.sh | 15 +- - 36 files changed, 2221 insertions(+), 15 deletions(-) - create mode 100644 arch/arm64/dtrace/Makefile.arch - create mode 100644 arch/arm64/dtrace/dtrace_asm_arm64.S - create mode 100644 arch/arm64/dtrace/dtrace_isa_arm64.c - create mode 100644 arch/arm64/dtrace/fasttrap_arm64.c - create mode 100644 arch/arm64/dtrace/fbt_arm64.c - create mode 100644 arch/arm64/dtrace/include/dtrace/fasttrap_arch.h - create mode 100644 arch/arm64/dtrace/include/dtrace/fbt_arch.h - create mode 100644 arch/arm64/dtrace/include/dtrace/sdt_arch.h - create mode 100644 arch/arm64/dtrace/sdt_arm64.c - create mode 100644 arch/arm64/include/asm/dtrace_arch.h - create mode 100644 arch/arm64/include/asm/dtrace_cpuinfo.h - create mode 100644 arch/arm64/include/asm/dtrace_sdt_arch.h - create mode 100644 arch/arm64/include/asm/dtrace_syscall.h - create mode 100644 arch/arm64/include/asm/dtrace_syscall_types.h - create mode 100644 arch/arm64/include/asm/dtrace_util.h - create mode 100644 arch/arm64/include/asm/kdebug.h - create mode 100644 arch/arm64/kernel/dtrace_fbt.c - create mode 100644 arch/arm64/kernel/dtrace_sdt.c - create mode 100644 arch/arm64/kernel/dtrace_syscall.c - create mode 100644 arch/arm64/kernel/dtrace_syscall_stubs.S - create mode 100644 arch/arm64/kernel/dtrace_util.c - create mode 100644 arch/arm64/kernel/fbt_blacklist.h - create mode 100755 scripts/dtrace_sdt_arm64.sh - -diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig -index a6b5b7ef40ae..72a0be5f1717 100644 ---- a/arch/arm64/Kconfig -+++ b/arch/arm64/Kconfig -@@ -323,6 +323,9 @@ config PGTABLE_LEVELS - config ARCH_SUPPORTS_UPROBES - def_bool y - -+config ARCH_SUPPORTS_DTRACE -+ def_bool y -+ - config ARCH_PROC_KCORE_TEXT - def_bool y - -diff --git a/arch/arm64/dtrace/Makefile.arch b/arch/arm64/dtrace/Makefile.arch -new file mode 100644 -index 000000000000..393b5cea3f7c ---- /dev/null -+++ b/arch/arm64/dtrace/Makefile.arch -@@ -0,0 +1,17 @@ -+# -+# Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. -+# -+ -+DTARCHDIR = ../arch/arm64/dtrace -+ -+ccflags-y += -I$(srctree)/arch/arm64/dtrace/include -Idtrace -+ -+dtrace-obj += dtrace_asm_arm64.o dtrace_isa_arm64.o -+fasttrap-obj += fasttrap_arm64.o -+fbt-obj += fbt_arm64.o -+sdt-obj += sdt_arm64.o -+ -+dtrace-y += $(addprefix $(DTARCHDIR)/, $(dtrace-obj)) -+fasttrap-y += $(addprefix $(DTARCHDIR)/, $(fasttrap-obj)) -+fbt-y += $(addprefix $(DTARCHDIR)/, $(fbt-obj)) -+sdt-y += $(addprefix $(DTARCHDIR)/, $(sdt-obj)) -diff --git a/arch/arm64/dtrace/dtrace_asm_arm64.S b/arch/arm64/dtrace/dtrace_asm_arm64.S -new file mode 100644 -index 000000000000..d0f7bad5fb0b ---- /dev/null -+++ b/arch/arm64/dtrace/dtrace_asm_arm64.S -@@ -0,0 +1,51 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Dynamic Tracing for Linux - ARM64 specific assembly -+ * -+ * Copyright (c) 2017 Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/linkage.h> -+ -+SYM_CODE_START(dtrace_caller) -+ mov x0, #-1 -+ ret -+SYM_CODE_END(dtrace_caller) -+ -+SYM_CODE_START(dtrace_copy) -+ ret -+SYM_CODE_END(dtrace_copy) -+ -+SYM_CODE_START(dtrace_copystr) -+ ret -+SYM_CODE_END(dtrace_copystr) -+ -+SYM_CODE_START(dtrace_fuword8_nocheck) -+ ldrb w0, [x0] -+ ret -+SYM_CODE_END(dtrace_fuword8_nocheck) -+ -+SYM_CODE_START(dtrace_fuword16_nocheck) -+ ldrh w0, [x0] -+ ret -+SYM_CODE_END(dtrace_fuword16_nocheck) -+ -+SYM_CODE_START(dtrace_fuword32_nocheck) -+ ldr w0, [x0] -+ ret -+SYM_CODE_END(dtrace_fuword32_nocheck) -+ -+SYM_CODE_START(dtrace_fuword64_nocheck) -+ ldr x0, [x0] -+ ret -+SYM_CODE_END(dtrace_fuword64_nocheck) -diff --git a/arch/arm64/dtrace/dtrace_isa_arm64.c b/arch/arm64/dtrace/dtrace_isa_arm64.c -new file mode 100644 -index 000000000000..2eb530149c5b ---- /dev/null -+++ b/arch/arm64/dtrace/dtrace_isa_arm64.c -@@ -0,0 +1,164 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_isa_arm64.c -+ * DESCRIPTION: DTrace - arm64 architecture specific support functions -+ * -+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <asm/stacktrace.h> -+#include <linux/ptrace.h> -+ -+#include "dtrace.h" -+ -+uintptr_t _userlimit = 0x0000ffffffffffffLL; -+ -+void dtrace_copyin_arch(uintptr_t uaddr, uintptr_t kaddr, size_t size, -+ volatile uint16_t *flags) -+{ -+} -+ -+void dtrace_copyinstr_arch(uintptr_t uaddr, uintptr_t kaddr, size_t size, -+ volatile uint16_t *flags) -+{ -+} -+ -+void dtrace_copyout(uintptr_t uaddr, uintptr_t kaddr, size_t size, -+ volatile uint16_t *flags) -+{ -+} -+ -+void dtrace_copyoutstr(uintptr_t uaddr, uintptr_t kaddr, size_t size, -+ volatile uint16_t *flags) -+{ -+} -+ -+#define DTRACE_FUWORD(bits) \ -+ uint##bits##_t dtrace_fuword##bits(void *uaddr) \ -+ { \ -+ extern uint##bits##_t dtrace_fuword##bits##_nocheck(void *);\ -+ \ -+ if ((uintptr_t)uaddr > _userlimit) { \ -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); \ -+ this_cpu_core->cpuc_dtrace_illval = (uintptr_t)uaddr; \ -+ } \ -+ \ -+ return dtrace_fuword##bits##_nocheck(uaddr); \ -+ } -+ -+DTRACE_FUWORD(8) -+DTRACE_FUWORD(16) -+DTRACE_FUWORD(32) -+DTRACE_FUWORD(64) -+ -+static int dtrace_unwind_frame(struct task_struct *task, -+ struct stackframe *frame) -+{ -+ unsigned long fp = frame->fp; -+ -+ if (fp & 0xf) -+ return -EINVAL; -+ -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); -+ frame->fp = READ_ONCE_NOCHECK(*(unsigned long *)(fp)); -+ frame->pc = READ_ONCE_NOCHECK(*(unsigned long *)(fp + 8)); -+ DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); -+ -+ if (!frame->fp && !frame->pc) -+ return -EINVAL; -+ -+ return 0; -+} -+ -+uint64_t dtrace_getarg(int argno, int aframes) -+{ -+ uint64_t *st; -+ uint64_t val; -+ int i; -+ struct stackframe frame; -+ struct task_struct *task = current; -+ -+ if (argno < 7) -+ return 0; -+ -+ if (this_cpu_core->cpu_dtrace_regs) -+ st = (uint64_t *)this_cpu_core->cpu_dtrace_regs->regs[29]; -+ else { -+ frame.fp = (unsigned long)__builtin_frame_address(0); -+ frame.pc = (unsigned long)dtrace_getarg; -+ -+ aframes += 1; /* Count this function. */ -+ for (i = 0; i < aframes; i++) { -+ if (dtrace_unwind_frame(task, &frame) < 0) -+ break; -+ } -+ -+ /* -+ * If we cannot traverse the expected number of stack frames, -+ * there is something wrong with the stack. -+ */ -+ if (i < aframes) { -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_BADSTACK); -+ -+ return 0; -+ } -+ -+ st = (uint64_t *)frame.fp; -+ } -+ -+ /* -+ * The first 7 arguments (arg0 through arg6) are passed in registers -+ * to dtrace_probe(). The remaining arguments (arg7 through arg9) are -+ * passed on the stack. -+ * -+ * Stack layout: -+ * bp[0] = pushed fp from caller -+ * bp[1] = return address -+ * bp[2] = 8th argument (arg7 -> argno = 7) -+ * bp[3] = 9th argument (arg8 -> argno = 8) -+ * ... -+ */ -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); -+ val = READ_ONCE_NOCHECK(st[2 + (argno - 7)]); -+ DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); -+ -+ return val; -+} -+ -+ulong_t dtrace_getreg(struct task_struct *task, uint_t reg) -+{ -+ struct pt_regs *rp = task_pt_regs(task); -+ -+ return regs_get_register(rp, reg * sizeof(uint64_t)); -+} -+ -+void pdata_init(struct dtrace_module *pdata, struct module *mp) -+{ -+ /* -+ * Throw away existing data as we don't support reusal at -+ * the moment. -+ */ -+ if (mp->pdata != NULL) -+ pdata_cleanup(pdata, mp); -+ -+ pdata->sdt_tab = NULL; -+ pdata->fbt_tab = NULL; -+} -+ -+void pdata_cleanup(struct dtrace_module *pdata, struct module *mp) -+{ -+ if (pdata->sdt_tab != NULL) -+ dtrace_free_text(pdata->sdt_tab); -+ if (pdata->fbt_tab != NULL) -+ dtrace_free_text(pdata->fbt_tab); -+} -diff --git a/arch/arm64/dtrace/fasttrap_arm64.c b/arch/arm64/dtrace/fasttrap_arm64.c -new file mode 100644 -index 000000000000..cc970a11412c ---- /dev/null -+++ b/arch/arm64/dtrace/fasttrap_arm64.c -@@ -0,0 +1,282 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: fasttrap_arm64.c -+ * DESCRIPTION: DTrace - fasttrap provider implementation for arm64 -+ * -+ * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <asm/insn.h> -+#include <linux/kernel.h> -+#include <linux/slab.h> -+#include <linux/uaccess.h> -+ -+#include "dtrace.h" -+#include "dtrace_dev.h" -+#include "fasttrap_impl.h" -+ -+static int has_jump_table(const asm_instr_t *addr, size_t size) -+{ -+ const asm_instr_t *end = addr + size; -+ -+ while (addr < end) { -+ /* -+ * If we encounter a branch-to-register instruction, we assume -+ * it is part of a jump table implementation. -+ */ -+ if (aarch64_insn_is_br(addr[0])) -+ return 1; -+ -+ addr++; -+ } -+ -+ return 0; -+} -+ -+static uint64_t *fasttrap_all_offsets(asm_instr_t *text, size_t size, -+ uint64_t *np) -+{ -+ uint64_t *offs = NULL; -+ uint64_t noffs; -+ asm_instr_t *instr; -+ asm_instr_t *end; -+ -+ /* -+ * Two passes are taken through this section of code. The first time -+ * around we merely count the number of probe points. The second time, -+ * we actually record their locations. -+ */ -+again: -+ noffs = 0; -+ instr = text; -+ end = text + size; -+ -+ while (instr < end) { -+ if (offs) -+ offs[noffs] = (uint64_t) -+ ((uintptr_t)instr - (uintptr_t)text); -+ noffs++; -+ -+ instr++; -+ } -+ -+ if (offs == NULL) { -+ /* -+ * No matching offsets found - we are done. -+ */ -+ if (noffs == 0) -+ goto fail; -+ -+ /* -+ * We know how many tracepoint locations there are for this -+ * probe, so allocate a member to record them, and kick off the -+ * second pass. -+ */ -+ offs = kmalloc(sizeof(uint64_t) * noffs, GFP_KERNEL); -+ if (!offs) -+ goto fail; -+ -+ goto again; -+ } -+ -+ *np = noffs; -+ -+ return offs; -+ -+fail: -+ *np = 0; -+ kfree(offs); -+ -+ return NULL; -+} -+ -+uint64_t *fasttrap_glob_offsets(struct fasttrap_probe_spec *probe, -+ uint64_t *np) -+{ -+ size_t size = probe->ftps_size; -+ asm_instr_t *text = NULL; -+ asm_instr_t *instr; -+ asm_instr_t *end; -+ uint64_t *offs = NULL; -+ uint64_t noffs; -+ int ret = 0; -+ char ostr[sizeof(instr) * 2 + 1]; /* 2 chars / byte + 1 */ -+ -+ if (!IS_ALIGNED(size, sizeof(instr[0]))) -+ goto fail; -+ -+ text = kmalloc(size, GFP_KERNEL); -+ if (!text) -+ goto fail; -+ -+ ret = dtrace_copy_code(probe->ftps_pid, (uint8_t *)text, -+ probe->ftps_pc, size); -+ if (ret != 0) -+ goto fail; -+ -+ /* -+ * From this point on, size will be a count of instructions rather than -+ * a byte count. We already verified earlier on that it is a multiple -+ * of the instruction size. -+ */ -+ size /= sizeof(instr[0]); -+ -+ if (has_jump_table(text, size)) -+ goto fail; -+ -+ if (probe->ftps_glen == 1 && probe->ftps_gstr[0] == '*') { -+ offs = fasttrap_all_offsets(text, size, &noffs); -+ goto out; -+ } -+ -+ /* -+ * Two passes are taken through this section of code. The first time -+ * around we merely count the number of probe points. The second time, -+ * we actually record their locations. -+ */ -+again: -+ noffs = 0; -+ instr = text; -+ end = text + size; -+ -+ while (instr < end) { -+ uint64_t off = (uint64_t) -+ ((uintptr_t)instr - (uintptr_t)text); -+ -+ snprintf(ostr, sizeof(ostr), "%llx", off); -+ if (dtrace_gmatch(ostr, probe->ftps_gstr)) { -+ if (offs) -+ offs[noffs] = off; -+ noffs++; -+ } -+ -+ instr++; -+ } -+ -+ if (offs == NULL) { -+ /* -+ * No matching offsets found - we are done. -+ */ -+ if (noffs == 0) -+ goto fail; -+ -+ /* -+ * We know how many tracepoint locations there are for this -+ * probe, so allocate member to record them, and kick off the -+ * second pass. -+ */ -+ offs = kmalloc(sizeof(uint64_t) * noffs, GFP_KERNEL); -+ if (!offs) -+ goto fail; -+ -+ goto again; -+ } -+ -+out: -+ kfree(text); -+ -+ *np = noffs; -+ -+ return offs; -+ -+fail: -+ kfree(offs); -+ kfree(text); -+ -+ *np = 0; -+ return NULL; -+} -+ -+uint64_t fasttrap_pid_getarg(void *arg, dtrace_id_t id, void *parg, int argno, -+ int aframes) -+{ -+ struct pt_regs *regs = this_cpu_core->cpu_dtrace_regs; -+ uint64_t *st; -+ uint64_t val; -+ -+ if (regs == NULL) -+ return 0; -+ -+ if (argno < 8) -+ return regs->regs[argno]; -+ -+ pagefault_disable(); -+ st = (uint64_t *)regs->sp; -+ __copy_from_user_inatomic_nocache(&val, (void *)&st[argno - 8], -+ sizeof(st[0])); -+ pagefault_enable(); -+ -+ return val; -+} -+ -+uint64_t fasttrap_usdt_getarg(void *arg, dtrace_id_t id, void *parg, -+ int argno, int aframes) -+{ -+ return fasttrap_pid_getarg(arg, id, parg, argno, aframes); -+} -+ -+static void fasttrap_map_args(struct fasttrap_probe *probe, -+ struct pt_regs *regs, int argc, uintptr_t *argv) -+{ -+ int i, x, cap = min(argc, (int)probe->ftp_nargs); -+ uintptr_t *st = (uintptr_t *)regs->sp; -+ -+ for (i = 0; i < cap; i++) { -+ x = probe->ftp_argmap[i]; -+ -+ if (x < 8) -+ argv[i] = regs->regs[x]; -+ else { -+ pagefault_disable(); -+ __copy_from_user_inatomic_nocache(&argv[i], -+ (void *)&st[x - 8], -+ sizeof(st[0])); -+ pagefault_enable(); -+ } -+ } -+ -+ while (i < argc) -+ argv[i++] = 0; -+} -+ -+void fasttrap_pid_probe_arch(struct fasttrap_probe *ftp, struct pt_regs *regs) -+{ -+ if (ftp->ftp_argmap == NULL) { -+ dtrace_probe(ftp->ftp_id, regs->regs[0], regs->regs[1], -+ regs->regs[2], regs->regs[3], -+ regs->regs[4], regs->regs[5], -+ regs->regs[6]); -+ } else { -+ uintptr_t t[7]; -+ -+ fasttrap_map_args(ftp, regs, sizeof(t) / sizeof(t[0]), t); -+ dtrace_probe(ftp->ftp_id, t[0], t[1], t[2], t[3], -+ t[4], t[5], t[6]); -+ } -+} -+ -+void fasttrap_pid_retprobe_arch(struct fasttrap_probe *ftp, -+ struct pt_regs *regs) -+{ -+ /* -+ * FIXME: The first argument to the probe should be the offset in the -+ * function that the return occurred at, but uprobes doesn't give -+ * us that information (or so it seems). -+ */ -+ dtrace_probe(ftp->ftp_id, 0, regs->regs[0], regs->regs[1], 0, 0, 0, 0); -+} -+ -+void fasttrap_set_enabled(struct pt_regs *regs) -+{ -+ regs->regs[0] = 1; -+} -diff --git a/arch/arm64/dtrace/fbt_arm64.c b/arch/arm64/dtrace/fbt_arm64.c -new file mode 100644 -index 000000000000..be9dcaf8db28 ---- /dev/null -+++ b/arch/arm64/dtrace/fbt_arm64.c -@@ -0,0 +1,152 @@ -+/* -+ * FILE: fbt_arm64.c -+ * DESCRIPTION: DTrace - FBT provider implementation for arm64 -+ * -+ * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/dtrace_fbt.h> -+#include <linux/ptrace.h> -+#include <linux/vmalloc.h> -+#include <asm/dtrace_util.h> -+#include <asm/debug-monitors.h> -+ -+#include "dtrace.h" -+#include "dtrace_dev.h" -+#include "fbt_impl.h" -+ -+static int fbt_brk_hook(struct pt_regs *regs, unsigned int esr) -+{ -+ uintptr_t ip = instruction_pointer(regs); -+ struct fbt_probe *fbp = fbt_probetab[FBT_ADDR2NDX(ip)]; -+ -+ for (; fbp != NULL; fbp = fbp->fbp_hashnext) { -+ if ((uintptr_t)fbp->fbp_patchpoint == ip) { -+ struct pt_regs *oregs; -+ -+ oregs = this_cpu_core->cpu_dtrace_regs; -+ this_cpu_core->cpu_dtrace_regs = regs; -+ -+ if (fbp->fbp_roffset == 0) { -+ dtrace_probe(fbp->fbp_id, regs->regs[0], -+ regs->regs[1], regs->regs[2], -+ regs->regs[3], regs->regs[4], -+ regs->regs[5], regs->regs[6]); -+ } else { -+ dtrace_probe(fbp->fbp_id, fbp->fbp_roffset, -+ regs->regs[0], 0, 0, 0, 0, 0); -+ } -+ -+ this_cpu_core->cpu_dtrace_regs = oregs; -+ -+ return DBG_HOOK_HANDLED; -+ } -+ } -+ -+ return DBG_HOOK_ERROR; -+} -+ -+uint64_t fbt_getarg(void *arg, dtrace_id_t id, void *parg, int argno, -+ int aframes) -+{ -+ struct pt_regs *regs = this_cpu_core->cpu_dtrace_regs; -+ uint64_t *st; -+ uint64_t val; -+ -+ if (regs == NULL) -+ regs = current_pt_regs(); -+ -+ if (argno < 8) -+ return regs->regs[argno]; -+ -+ /* -+ * Arguments are passed by register for the first 8 arguments, and the -+ * rest is placed on the stack. The frame pointer (fp) points at the -+ * beginning of the current frame, and the stack pointer (sp) will -+ * point to the end of the frame. Arguments passed by stack are placed -+ * in stack slots at the end of the frame, so at (sp), (sp + 1), etc... -+ */ -+ st = (uint64_t *)regs->sp; -+ -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); -+ val = READ_ONCE_NOCHECK(st[argno - 8]); -+ DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); -+ -+ return 0; -+} -+ -+void fbt_provide_probe_arch(struct fbt_probe *fbp, int type, int stype) -+{ -+ fbp->fbp_patchval = type == FBT_ENTRY ? BRK64_OPCODE_DPROBE_FBE -+ : BRK64_OPCODE_DPROBE_FBR; -+ fbp->fbp_savedval = dtrace_text_peek(fbp->fbp_patchpoint); -+} -+ -+int fbt_can_patch_return_arch(asm_instr_t *addr) -+{ -+ return 1; -+} -+ -+int fbt_provide_module_arch(void *arg, struct module *mp) -+{ -+ return 1; -+} -+ -+void fbt_destroy_module(void *arg, struct module *mp) -+{ -+} -+ -+void fbt_enable_arch(struct fbt_probe *fbp, dtrace_id_t id, void *arg) -+{ -+ dtrace_text_poke(fbp->fbp_patchpoint, fbp->fbp_patchval); -+} -+ -+void fbt_disable_arch(struct fbt_probe *fbp, dtrace_id_t id, void *arg) -+{ -+ dtrace_text_poke(fbp->fbp_patchpoint, fbp->fbp_savedval); -+} -+ -+static struct break_hook dtrace_fbe_break_hook = { -+ .imm = DPROBES_FBE_BRK_IMM, -+ .fn = fbt_brk_hook, -+}; -+ -+static struct break_hook dtrace_fbr_break_hook = { -+ .imm = DPROBES_FBR_BRK_IMM, -+ .fn = fbt_brk_hook, -+}; -+ -+int fbt_dev_init_arch(void) -+{ -+ fbt_probetab_mask = fbt_probetab_size - 1; -+ fbt_probetab = dtrace_vzalloc_try(fbt_probetab_size * -+ sizeof(struct fbt_probe *)); -+ -+ if (fbt_probetab == NULL) -+ return -ENOMEM; -+ -+ dtrace_kernel_brk_start(&dtrace_fbe_break_hook); -+ dtrace_kernel_brk_start(&dtrace_fbr_break_hook); -+ -+ return 0; -+} -+ -+void fbt_dev_exit_arch(void) -+{ -+ dtrace_kernel_brk_stop(&dtrace_fbr_break_hook); -+ dtrace_kernel_brk_stop(&dtrace_fbe_break_hook); -+ -+ vfree(fbt_probetab); -+ fbt_probetab_mask = 0; -+ fbt_probetab_size = 0; -+} -diff --git a/arch/arm64/dtrace/include/dtrace/fasttrap_arch.h b/arch/arm64/dtrace/include/dtrace/fasttrap_arch.h -new file mode 100644 -index 000000000000..d5ffa6e711db ---- /dev/null -+++ b/arch/arm64/dtrace/include/dtrace/fasttrap_arch.h -@@ -0,0 +1,30 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Dynamic Tracing for Linux - Fasttrap provider implementation defines -+ * -+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _ARM64_FASTTRAP_ARCH_H -+#define _ARM64_FASTTRAP_ARCH_H -+ -+#define FASTTRAP_ENTRY_AFRAMES 8 -+#define FASTTRAP_RETURN_AFRAMES 8 -+#define FASTTRAP_OFFSET_AFRAMES 8 -+ -+#endif /* _ARM64_FASTTRAP_ARCH_H */ -diff --git a/arch/arm64/dtrace/include/dtrace/fbt_arch.h b/arch/arm64/dtrace/include/dtrace/fbt_arch.h -new file mode 100644 -index 000000000000..ed1cd785b3ba ---- /dev/null -+++ b/arch/arm64/dtrace/include/dtrace/fbt_arch.h -@@ -0,0 +1,53 @@ -+/* -+ * Dynamic Tracing for Linux - FBT Implementation defines -+ * -+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _ARM64_FBT_ARCH_H -+#define _ARM64_FBT_ARCH_H -+ -+/* -+ * FBT entry probes are triggered from a breakpoint. The following stack trace -+ * illustrates the frames that are involved in the call sequence prior to the -+ * actual FBT provider handler. -+ * -+ * vmlinux`brk_handler+0x70 <- to be skipped -+ * vmlinux`do_debug_exception+0x9c <- to be skipped -+ * vmlinux`el1_sync+0x1d8 <- to be skipped -+ * vmlinux`SyS_read+0x4 -+ * -+ * Therefore, 3 frames need to be skipped. -+ */ -+#define FBT_AFRAMES 3 -+ -+struct fbt_probe { -+ char *fbp_name; /* name of probe */ -+ dtrace_id_t fbp_id; /* probe ID */ -+ struct module *fbp_module; /* defining module */ -+ int fbp_primary; /* non-zero if primary mod */ -+ asm_instr_t *fbp_patchpoint;/* patch point */ -+ asm_instr_t fbp_patchval; /* instruction to patch */ -+ asm_instr_t fbp_savedval; /* saved instruction value */ -+ uint64_t fbp_roffset; /* relative offset */ -+ struct fbt_probe *fbp_next; /* next probe */ -+ struct fbt_probe *fbp_hashnext; /* next on hash */ -+ int fbp_isret; -+}; -+ -+#endif /* _ARM64_FBT_ARCH_H */ -diff --git a/arch/arm64/dtrace/include/dtrace/sdt_arch.h b/arch/arm64/dtrace/include/dtrace/sdt_arch.h -new file mode 100644 -index 000000000000..237922a77495 ---- /dev/null -+++ b/arch/arm64/dtrace/include/dtrace/sdt_arch.h -@@ -0,0 +1,28 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Dynamic Tracing for Linux - SDT Implementation defines -+ * -+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _ARM64_SDT_ARCH_H -+#define _ARM64_SDT_ARCH_H -+ -+#define SDT_AFRAMES 1 -+ -+#endif /* _ARM64_SDT_ARCH_H */ -diff --git a/arch/arm64/dtrace/sdt_arm64.c b/arch/arm64/dtrace/sdt_arm64.c -new file mode 100644 -index 000000000000..ba25824e413e ---- /dev/null -+++ b/arch/arm64/dtrace/sdt_arm64.c -@@ -0,0 +1,122 @@ -+/* -+ * FILE: sdt_arm64.c -+ * DESCRIPTION: DTrace - SDT provider implementation for arm64 -+ * -+ * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/ptrace.h> -+#include <linux/sdt.h> -+#include <asm/debug-monitors.h> -+ -+#include "dtrace.h" -+#include "dtrace_dev.h" -+#include "sdt_impl.h" -+ -+static int sdt_brk_hook(struct pt_regs *regs, unsigned int esr) -+{ -+ uintptr_t ip = instruction_pointer(regs); -+ struct sdt_probe *sdt = sdt_probetab[SDT_ADDR2NDX(ip)]; -+ -+ for (; sdt != NULL; sdt = sdt->sdp_hashnext) { -+ if ((uintptr_t)sdt->sdp_patchpoint == ip) { -+ if (sdt->sdp_ptype == SDTPT_IS_ENABLED) -+ regs->regs[0] = 1; -+ else { -+ this_cpu_core->cpu_dtrace_regs = regs; -+ dtrace_probe(sdt->sdp_id, regs->regs[0], -+ regs->regs[1], regs->regs[2], -+ regs->regs[3], regs->regs[4], -+ regs->regs[5], regs->regs[6]); -+ this_cpu_core->cpu_dtrace_regs = NULL; -+ } -+ -+ instruction_pointer_set(regs, -+ instruction_pointer(regs) + 4); -+ -+ return DBG_HOOK_HANDLED; -+ } -+ } -+ -+ return DBG_HOOK_ERROR; -+} -+ -+void sdt_provide_probe_arch(struct sdt_probe *sdp, struct module *mp, int idx) -+{ -+ sdp->sdp_patchval = BRK64_OPCODE_DPROBE_SDT; -+ sdp->sdp_savedval = dtrace_text_peek(sdp->sdp_patchpoint); -+} -+ -+int sdt_provide_module_arch(void *arg, struct module *mp) -+{ -+ return 1; -+} -+ -+void sdt_destroy_module(void *arg, struct module *mp) -+{ -+} -+ -+void sdt_enable_arch(struct sdt_probe *sdp, dtrace_id_t id, void *arg) -+{ -+ dtrace_text_poke(sdp->sdp_patchpoint, sdp->sdp_patchval); -+} -+ -+void sdt_disable_arch(struct sdt_probe *sdp, dtrace_id_t id, void *arg) -+{ -+ dtrace_text_poke(sdp->sdp_patchpoint, sdp->sdp_savedval); -+} -+ -+static struct break_hook dtrace_sdt_break_hook = { -+ .imm = DPROBES_SDT_BRK_IMM, -+ .fn = sdt_brk_hook, -+}; -+ -+int sdt_dev_init_arch(void) -+{ -+ dtrace_kernel_brk_start(&dtrace_sdt_break_hook); -+ return 0; -+} -+ -+void sdt_dev_exit_arch(void) -+{ -+ dtrace_kernel_brk_stop(&dtrace_sdt_break_hook); -+} -+ -+uint64_t sdt_getarg(void *arg, dtrace_id_t id, void *parg, int argno, -+ int aframes) -+{ -+ struct pt_regs *regs = this_cpu_core->cpu_dtrace_regs; -+ uint64_t *st; -+ uint64_t val; -+ -+ if (regs == NULL) -+ regs = current_pt_regs(); -+ -+ if (argno < 8) -+ return regs->regs[argno]; -+ -+ /* -+ * Arguments are passed by register for the first 8 arguments, and the -+ * rest is placed on the stack. The frame pointer (fp) points at the -+ * beginning of the current frame, and the stack pointer (sp) will -+ * point to the end of the frame. Arguments passed by stack are placed -+ * in stack slots at the end of the frame, so at (sp), (sp + 1), etc... -+ */ -+ st = (uint64_t *)regs->sp; -+ -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); -+ val = READ_ONCE_NOCHECK(st[argno - 8]); -+ DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); -+ -+ return val; -+} -diff --git a/arch/arm64/include/asm/brk-imm.h b/arch/arm64/include/asm/brk-imm.h -index ec7720dbe2c8..405cfb7da5ea 100644 ---- a/arch/arm64/include/asm/brk-imm.h -+++ b/arch/arm64/include/asm/brk-imm.h -@@ -11,6 +11,9 @@ - * 0x004: for installing kprobes - * 0x005: for installing uprobes - * 0x006: for kprobe software single-step -+ * 0x007: for installing DTrace SDT probes -+ * 0x008: for installing DTrace function-boundary tracing entry probes -+ * 0x009: for installing DTrace function-boundary tracing return probes - * Allowed values for kgdb are 0x400 - 0x7ff - * 0x100: for triggering a fault on purpose (reserved) - * 0x400: for dynamic BRK instruction -@@ -21,6 +24,9 @@ - #define KPROBES_BRK_IMM 0x004 - #define UPROBES_BRK_IMM 0x005 - #define KPROBES_BRK_SS_IMM 0x006 -+#define DPROBES_SDT_BRK_IMM 0x007 -+#define DPROBES_FBE_BRK_IMM 0x008 -+#define DPROBES_FBR_BRK_IMM 0x009 - #define FAULT_BRK_IMM 0x100 - #define KGDB_DYN_DBG_BRK_IMM 0x400 - #define KGDB_COMPILED_DBG_BRK_IMM 0x401 -diff --git a/arch/arm64/include/asm/cpu.h b/arch/arm64/include/asm/cpu.h -index 7faae6ff3ab4..496e8df36b56 100644 ---- a/arch/arm64/include/asm/cpu.h -+++ b/arch/arm64/include/asm/cpu.h -@@ -60,6 +60,7 @@ struct cpuinfo_arm64 { - }; - - DECLARE_PER_CPU(struct cpuinfo_arm64, cpu_data); -+#define cpu_data(cpu) per_cpu(cpu_data, (cpu)) - - void cpuinfo_store_cpu(void); - void __init cpuinfo_store_boot_cpu(void); -diff --git a/arch/arm64/include/asm/debug-monitors.h b/arch/arm64/include/asm/debug-monitors.h -index 657c921fd784..030756b7e008 100644 ---- a/arch/arm64/include/asm/debug-monitors.h -+++ b/arch/arm64/include/asm/debug-monitors.h -@@ -56,6 +56,10 @@ - #define BRK64_OPCODE_KPROBES_SS (AARCH64_BREAK_MON | (KPROBES_BRK_SS_IMM << 5)) - /* uprobes BRK opcodes with ESR encoding */ - #define BRK64_OPCODE_UPROBES (AARCH64_BREAK_MON | (UPROBES_BRK_IMM << 5)) -+/* DTrace probes BRK opcodes with ESR encoding */ -+#define BRK64_OPCODE_DPROBE_SDT (AARCH64_BREAK_MON | (DPROBES_SDT_BRK_IMM << 5)) -+#define BRK64_OPCODE_DPROBE_FBE (AARCH64_BREAK_MON | (DPROBES_FBE_BRK_IMM << 5)) -+#define BRK64_OPCODE_DPROBE_FBR (AARCH64_BREAK_MON | (DPROBES_FBR_BRK_IMM << 5)) - - /* AArch32 */ - #define DBG_ESR_EVT_BKPT 0x4 -diff --git a/arch/arm64/include/asm/dtrace_arch.h b/arch/arm64/include/asm/dtrace_arch.h -new file mode 100644 -index 000000000000..89f883e20aa7 ---- /dev/null -+++ b/arch/arm64/include/asm/dtrace_arch.h -@@ -0,0 +1,31 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. */ -+ -+#ifndef _ASM_ARM64_DTRACE_ARCH_H -+#define _ASM_ARM64_DTRACE_ARCH_H -+ -+/* Number of argumens stored inside the mstate. */ -+#define DTRACE_MSTATE_ARGS_MAX 7 -+ -+typedef uint32_t asm_instr_t; -+ -+typedef int (*prov_exit_f)(void); -+ -+/* -+ * Structure to hold DTrace specific information about modules (including the -+ * core kernel module). Note that each module (and the main kernel) already -+ * has three fields that relate to probing: -+ * - sdt_probes: description of SDT probes in the module -+ * - sdt_probec: number of SDT probes in the module -+ * - pdata: pointer to a dtrace_module struct (for DTrace) -+ */ -+struct dtrace_module { -+ int enabled_cnt; -+ size_t sdt_probe_cnt; -+ asm_instr_t *sdt_tab; -+ size_t fbt_probe_cnt; -+ asm_instr_t *fbt_tab; -+ prov_exit_f prov_exit; /* Called with module_mutex held */ -+}; -+ -+#endif /* _ASM_ARM64_DTRACE_ARCH_H */ -diff --git a/arch/arm64/include/asm/dtrace_cpuinfo.h b/arch/arm64/include/asm/dtrace_cpuinfo.h -new file mode 100644 -index 000000000000..4e0ab793c92c ---- /dev/null -+++ b/arch/arm64/include/asm/dtrace_cpuinfo.h -@@ -0,0 +1,13 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* Copyright (C) 2018 Oracle, Inc. */ -+ -+#ifndef _ASM_ARM64_DTRACE_CPUINFO_H_ -+#define _ASM_ARM64_DTRACE_CPUINFO_H_ -+ -+#include <asm/cpu.h> -+ -+typedef struct cpuinfo_arm64 cpuinfo_arch_t; -+ -+#define dtrace_cpuinfo_chip(ci) ((ci)->cpu.node_id) -+ -+#endif /* _ASM_ARM64_DTRACE_CPUINFO_H_ */ -diff --git a/arch/arm64/include/asm/dtrace_sdt_arch.h b/arch/arm64/include/asm/dtrace_sdt_arch.h -new file mode 100644 -index 000000000000..b93a03c215b3 ---- /dev/null -+++ b/arch/arm64/include/asm/dtrace_sdt_arch.h -@@ -0,0 +1,15 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* Copyright (C) 2018 Oracle, Inc. */ -+ -+#ifndef _ASM_ARM64_DTRACE_SDT_ARCH_H -+#define _ASM_ARM64_DTRACE_SDT_ARCH_H -+ -+#include <asm/dtrace_arch.h> -+ -+#define NOP_INSTR 0xd503201f -+#define MOV_INSTR 0xd2800000 /* mov x0, #0x0 - default = false */ -+ -+#define __DTRACE_SDT_ISENABLED_PROTO void -+#define __DTRACE_SDT_ISENABLED_ARGS -+ -+#endif /* _ASM_ARM64_DTRACE_SDT_ARCH_H */ -diff --git a/arch/arm64/include/asm/dtrace_syscall.h b/arch/arm64/include/asm/dtrace_syscall.h -new file mode 100644 -index 000000000000..402826562478 ---- /dev/null -+++ b/arch/arm64/include/asm/dtrace_syscall.h -@@ -0,0 +1,3 @@ -+/* -+ * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. -+ */ -diff --git a/arch/arm64/include/asm/dtrace_syscall_types.h b/arch/arm64/include/asm/dtrace_syscall_types.h -new file mode 100644 -index 000000000000..88e6eca6e169 ---- /dev/null -+++ b/arch/arm64/include/asm/dtrace_syscall_types.h -@@ -0,0 +1,11 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+#include <linux/types.h> -+#include <linux/dtrace_types.h> -+ -+typedef asmlinkage long (*dt_sys_call_t)(const struct pt_regs *regs); -+ -+#define DTRACE_SYSCALL_WRAP_PREFIX "__arm64_" -diff --git a/arch/arm64/include/asm/dtrace_util.h b/arch/arm64/include/asm/dtrace_util.h -new file mode 100644 -index 000000000000..003bd34524d6 ---- /dev/null -+++ b/arch/arm64/include/asm/dtrace_util.h -@@ -0,0 +1,14 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* Copyright (C) 2019, Oracle and/or its affiliates. All rights reserved. */ -+ -+#ifndef _ASM_ARM64_DTRACE_UTIL_H -+#define _ASM_ARM64_DTRACE_UTIL_H -+ -+#include <asm/dtrace_arch.h> -+ -+extern asm_instr_t dtrace_text_peek(asm_instr_t *addr); -+extern void dtrace_text_poke(asm_instr_t *addr, asm_instr_t opcode); -+extern void dtrace_kernel_brk_start(void *arg); -+extern void dtrace_kernel_brk_stop(void *arg); -+ -+#endif /* _ASM_ARM64_DTRACE_UTIL_H */ -diff --git a/arch/arm64/include/asm/kdebug.h b/arch/arm64/include/asm/kdebug.h -new file mode 100644 -index 000000000000..66c884086d04 ---- /dev/null -+++ b/arch/arm64/include/asm/kdebug.h -@@ -0,0 +1,11 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+#ifndef _ARM64_KDEBUG_H -+#define _ARM64_KDEBUG_H -+ -+/* Grossly misnamed. */ -+enum die_val { -+ DIE_OOPS = 1, -+ DIE_PAGE_FAULT, -+}; -+ -+#endif /* _ARM64_KDEBUG_H */ -diff --git a/arch/arm64/include/asm/syscall.h b/arch/arm64/include/asm/syscall.h -index cfc0672013f6..1ab1fc22cb8b 100644 ---- a/arch/arm64/include/asm/syscall.h -+++ b/arch/arm64/include/asm/syscall.h -@@ -11,7 +11,13 @@ - - typedef long (*syscall_fn_t)(const struct pt_regs *regs); - --extern const syscall_fn_t sys_call_table[]; -+#if IS_ENABLED(CONFIG_DT_SYSTRACE) -+#define CONST_SYS_CALL_TABLE -+#else -+#define CONST_SYS_CALL_TABLE const -+#endif -+ -+extern CONST_SYS_CALL_TABLE syscall_fn_t sys_call_table[]; - - #ifdef CONFIG_COMPAT - extern const syscall_fn_t compat_sys_call_table[]; -diff --git a/arch/arm64/kernel/dtrace_fbt.c b/arch/arm64/kernel/dtrace_fbt.c -new file mode 100644 -index 000000000000..3761e8aa4550 ---- /dev/null -+++ b/arch/arm64/kernel/dtrace_fbt.c -@@ -0,0 +1,187 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_fbt.c -+ * DESCRIPTION: Dynamic Tracing: FBT registration code (arch-specific) -+ * -+ * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/kallsyms.h> -+#include <linux/dtrace_os.h> -+#include <linux/dtrace_fbt.h> -+#include <linux/dtrace_task_impl.h> -+#include <linux/slab.h> -+#include <linux/sort.h> -+#include <asm/insn.h> -+#include <asm/sections.h> -+ -+#define FBT_REG_FP 0x1d /* fp is regiater 29 */ -+#define FBT_REG_LR 0x1e /* lr is regiater 30 */ -+#define FBT_REG_SP 0x1f /* sp is register 31 */ -+#define FBT_MOV_FP_SP 0x910003fd /* "mov x29, sp" */ -+ -+#define BL_SENTRY(tp, nm) extern tp nm; -+#define BL_DENTRY(tp, nm) -+#include "fbt_blacklist.h" -+#undef BL_DENTRY -+#undef BL_SENTRY -+ -+static void -+dtrace_fbt_populate_bl(void) -+{ -+#define BL_SENTRY(tp, nm) dtrace_fbt_bl_add((unsigned long)&nm, \ -+ __stringify(nm)); -+#define BL_DENTRY(tp, nm) dtrace_fbt_bl_add(0, __stringify(nm)); -+#include "fbt_blacklist.h" -+#undef BL_SENTRY -+#undef BL_DENTRY -+} -+ -+void dtrace_fbt_init(fbt_add_probe_fn fbt_add_probe, struct module *mp, -+ void *arg) -+{ -+ loff_t pos; -+ struct kallsym_iter sym; -+ asm_instr_t *paddr = NULL; -+ struct dt_fbt_bl_entry *blent = NULL; -+ -+ /* -+ * Look up any unresolved symbols in the blacklist, and sort the list -+ * by ascending address. -+ */ -+ dtrace_fbt_populate_bl(); -+ -+ blent = dtrace_fbt_bl_first(); -+ -+ pos = 0; -+ kallsyms_iter_reset(&sym, 0); -+ while (kallsyms_iter_update(&sym, pos++)) { -+ asm_instr_t *addr, *end; -+ asm_instr_t instr; -+ void *fbtp = NULL; -+ -+ /* -+ * There is no point considering non-function symbols for FBT, -+ * or symbols that have a zero size. We could consider weak -+ * symbols but that gets quite complicated and there is no -+ * demands for that (so far). -+ */ -+ if (sym.type != 'T' && sym.type != 't') -+ continue; -+ if (!sym.size) -+ continue; -+ -+ /* -+ * The symbol must be at a properly aligned text address. -+ */ -+ if (!IS_ALIGNED(sym.value, sizeof(asm_instr_t))) -+ continue; -+ -+ /* -+ * Handle only symbols that belong to the module we have been -+ * asked for. -+ */ -+ if (mp == dtrace_kmod && !core_kernel_text(sym.value)) -+ continue; -+ -+ /* -+ * Ensure we have not been given .init symbol from kallsyms -+ * interface. This could lead to memory corruption once DTrace -+ * tries to enable probe in already freed memory. -+ */ -+ if (mp != dtrace_kmod && !within_module_core(sym.value, mp)) -+ continue; -+ -+ /* -+ * See if the symbol is on the FBT's blacklist. Since both -+ * iterators are workng in sort order by ascending address we -+ * can use concurrent traversal. -+ */ -+ while (blent != NULL && -+ dtrace_fbt_bl_entry_addr(blent) < sym.value) { -+ blent = dtrace_fbt_bl_next(blent); -+ } -+ if (dtrace_fbt_bl_entry_addr(blent) == sym.value) -+ continue; -+ -+ /* -+ * No FBT tracing for DTrace functions, and functions that are -+ * crucial to probe processing. -+ * Also weed out symbols that are not relevant here. -+ */ -+ if (strncmp(sym.name, "dtrace_", 7) == 0) -+ continue; -+ if (strncmp(sym.name, "insn_", 5) == 0) -+ continue; -+ if (strncmp(sym.name, "inat_", 5) == 0) -+ continue; -+ if (strncmp(sym.name, "_GLOBAL_", 8) == 0) -+ continue; -+ if (strncmp(sym.name, "do_", 3) == 0) -+ continue; -+ if (strncmp(sym.name, "xen_", 4) == 0) -+ continue; -+ -+ addr = (asm_instr_t *)sym.value; -+ end = (asm_instr_t *)(sym.value + sym.size); -+ -+ /* -+ * FIXME: -+ * When there are multiple symbols for the same address, we -+ * should link them together as probes associated with the -+ * same function. When a probe for that function is triggered -+ * all associated probes should fire. -+ * -+ * For now, we ignore duplicates. -+ */ -+ if (addr == paddr) -+ continue; -+ paddr = addr; -+ -+ instr = le32_to_cpu(*addr); -+ -+ /* -+ * We can only instrument functions that begin with a proper -+ * frame set-up sequence: -+ * stp x29, x30, [sp,#-80]! -+ * mov x29, sp -+ * So, a STP instruction storing the FP (x29) and LR (x30) -+ * registers as a pair in a location relative to the SP -+ * register value. And then a MOV instruction that sets the -+ * FP (x29) register to the current SP value (effectively -+ * establishing the new stack frame). -+ * -+ * We will place our breakpoint on the MOV instruction. -+ */ -+ if (!aarch64_insn_is_stp_pre(instr) || -+ aarch64_insn_decode_register( -+ AARCH64_INSN_REGTYPE_RN, instr) != FBT_REG_SP || -+ aarch64_insn_decode_register( -+ AARCH64_INSN_REGTYPE_RT, instr) != FBT_REG_FP || -+ aarch64_insn_decode_register( -+ AARCH64_INSN_REGTYPE_RT2, instr) != FBT_REG_LR) -+ continue; -+ -+ addr++; -+ instr = le32_to_cpu(*addr); -+ if (instr != FBT_MOV_FP_SP) -+ continue; -+ -+ fbt_add_probe(mp, sym.name, FBT_ENTRY, instr, addr, 0, NULL, -+ arg); -+ -+ while (++addr < end) { -+ uintptr_t off; -+ -+ instr = le32_to_cpu(*addr); -+ if (!aarch64_insn_is_ret(instr)) -+ continue; -+ -+ off = (uintptr_t)addr - sym.value; -+ fbtp = fbt_add_probe(mp, sym.name, FBT_RETURN, instr, -+ addr, off, fbtp, arg); -+ } -+ } -+} -+EXPORT_SYMBOL(dtrace_fbt_init); -diff --git a/arch/arm64/kernel/dtrace_sdt.c b/arch/arm64/kernel/dtrace_sdt.c -new file mode 100644 -index 000000000000..d5a6a9d398b3 ---- /dev/null -+++ b/arch/arm64/kernel/dtrace_sdt.c -@@ -0,0 +1,25 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_sdt.c -+ * DESCRIPTION: Dynamic Tracing: SDT registration code (arch-specific) -+ * -+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+#include <linux/module.h> -+#include <asm/insn.h> -+#include <asm/dtrace_arch.h> -+#include <asm/dtrace_sdt_arch.h> -+ -+void __init_or_module dtrace_sdt_nop_multi(asm_instr_t **addrs, -+ int *is_enabled, int cnt) -+{ -+ int i; -+ -+ for (i = 0; i < cnt; i++) { -+ if (likely(!is_enabled[i])) -+ aarch64_insn_patch_text_nosync(addrs[i], NOP_INSTR); -+ else -+ aarch64_insn_patch_text_nosync(addrs[i], MOV_INSTR); -+ } -+} -diff --git a/arch/arm64/kernel/dtrace_syscall.c b/arch/arm64/kernel/dtrace_syscall.c -new file mode 100644 -index 000000000000..73730e42f3b8 ---- /dev/null -+++ b/arch/arm64/kernel/dtrace_syscall.c -@@ -0,0 +1,89 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_syscall.c -+ * DESCRIPTION: Dynamic Tracing: system call tracing support (arch-specific) -+ * -+ * Copyright (C) 2010, 2018 Oracle Corporation -+ */ -+ -+#include <linux/dtrace_syscall.h> -+#include <linux/ptrace.h> -+#include <asm/syscall.h> -+ -+void (*systrace_probe)(dtrace_id_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, -+ uintptr_t, uintptr_t, uintptr_t); -+ -+void systrace_stub(dtrace_id_t id, uintptr_t arg0, uintptr_t arg1, -+ uintptr_t arg2, uintptr_t arg3, uintptr_t arg4, -+ uintptr_t arg5, uintptr_t arg6) -+{ -+} -+ -+asmlinkage long systrace_syscall(const struct pt_regs *regs); -+ -+static struct systrace_info systrace_info = { -+ &systrace_probe, -+ systrace_stub, -+ systrace_syscall, -+ {}, -+ { -+#undef __SYSCALL -+#define __SYSCALL(nr, sym) [nr] { .name = __stringify(sym), }, -+#include <asm/unistd.h> -+#undef __SYSCALL -+ } -+ }; -+ -+ -+asmlinkage long systrace_syscall(const struct pt_regs *regs) -+{ -+ long rc = 0; -+ unsigned long sysnum; -+ dtrace_id_t id; -+ struct dtrace_syscalls *sc; -+ -+ sysnum = syscall_get_nr(current, (struct pt_regs *) regs); -+ sc = &systrace_info.sysent[sysnum]; -+ -+ id = sc->stsy_entry; -+ /* TODO: arg 6. */ -+ if (id != DTRACE_IDNONE) -+ (*systrace_probe)(id, regs->regs[0], regs->regs[1], -+ regs->regs[2], regs->regs[3], regs->regs[4], -+ regs->regs[5], 0); -+ -+ /* -+ * FIXME: Add stop functionality for DTrace. -+ */ -+ -+ if (sc->stsy_underlying != NULL) -+ rc = (*sc->stsy_underlying)(regs); -+ -+ id = sc->stsy_return; -+ if (id != DTRACE_IDNONE) -+ (*systrace_probe)(id, (uintptr_t)rc, (uintptr_t)rc, -+ (uintptr_t)((uint64_t)rc >> 32), 0, 0, 0, 0); -+ -+ return rc; -+} -+ -+struct systrace_info *dtrace_syscalls_init() -+{ -+ int i; -+ -+ /* -+ * Only initialize this stuff once... -+ */ -+ if (systrace_info.sysent[0].stsy_tblent != NULL) -+ return &systrace_info; -+ -+ for (i = 0; i < NR_syscalls; i++) { -+ systrace_info.sysent[i].stsy_tblent = -+ (dt_sys_call_t *)&sys_call_table[i]; -+ systrace_info.sysent[i].stsy_underlying = -+ (dt_sys_call_t)sys_call_table[i]; -+ } -+ -+ return &systrace_info; -+} -+EXPORT_SYMBOL(dtrace_syscalls_init); -diff --git a/arch/arm64/kernel/dtrace_syscall_stubs.S b/arch/arm64/kernel/dtrace_syscall_stubs.S -new file mode 100644 -index 000000000000..e69de29bb2d1 -diff --git a/arch/arm64/kernel/dtrace_util.c b/arch/arm64/kernel/dtrace_util.c -new file mode 100644 -index 000000000000..8142cf0459c2 ---- /dev/null -+++ b/arch/arm64/kernel/dtrace_util.c -@@ -0,0 +1,292 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_util.c -+ * DESCRIPTION: Dynamic Tracing: Architecture utility functions -+ * -+ * Copyright (c) 2010, 2019, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+#include <linux/dtrace_cpu.h> -+#include <linux/dtrace_os.h> -+#include <linux/dtrace_task_impl.h> -+#include <linux/kdebug.h> -+#include <linux/notifier.h> -+#include <linux/ptrace.h> -+#include <linux/uaccess.h> -+#include <linux/uprobes.h> -+#include <asm/debug-monitors.h> -+#include <asm/insn.h> -+ -+void dtrace_skip_instruction(struct pt_regs *regs) -+{ -+ instruction_pointer_set(regs, instruction_pointer(regs) + 4); -+} -+ -+void dtrace_handle_badaddr(struct pt_regs *regs) -+{ -+ unsigned long addr = current->thread.fault_address; -+ -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); -+ this_cpu_core->cpuc_dtrace_illval = addr; -+ -+ dtrace_skip_instruction(regs); -+} -+ -+int dtrace_die_notifier(struct notifier_block *nb, unsigned long val, -+ void *args) -+{ -+ struct die_args *dargs = args; -+ -+ switch (val) { -+ case DIE_PAGE_FAULT: { -+ if (!DTRACE_CPUFLAG_ISSET(CPU_DTRACE_NOFAULT)) -+ return NOTIFY_DONE; -+ -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); -+ this_cpu_core->cpuc_dtrace_illval = dargs->err; -+ -+ dtrace_skip_instruction(dargs->regs); -+ -+ return NOTIFY_OK | NOTIFY_STOP_MASK; -+ } -+ case DIE_OOPS: { -+ pr_info("DTrace: last probe %u\n", -+ this_cpu_core->cpuc_current_probe); -+ return NOTIFY_DONE; -+ } -+ default: -+ return NOTIFY_DONE; -+ } -+} -+ -+struct user_stackframe { -+ struct user_stackframe __user *fp; -+ unsigned long lr; -+} __packed; -+ -+static int dtrace_unwind_frame(struct user_stackframe *frame) -+{ -+ struct user_stackframe __user *ofp = frame->fp; -+ unsigned long ret; -+ -+ /* Verify alignment. */ -+ if ((unsigned long)ofp & 0xf) -+ return -EINVAL; -+ -+ /* Verify read access. */ -+ if (!access_ok(ofp, sizeof(struct user_stackframe))) -+ return -EINVAL; -+ -+ pagefault_disable(); -+ ret = __copy_from_user_inatomic(frame, ofp, -+ sizeof(struct user_stackframe)); -+ pagefault_enable(); -+ -+ /* Make sure the read worked. */ -+ if (ret) { -+ frame->fp = ofp; -+ return -EINVAL; -+ } -+ -+ /* -+ * If the frame pointer in the current frame is NULL, we have reached -+ * the end of the call chain. -+ */ -+ if (frame->fp == NULL) -+ return 0; -+ -+ /* -+ * In older glibc versions, the call chain did not end with an initial -+ * frame with NULL frame pointer. Instead, the initial frame stored -+ * the beginning of the stack as frame pointer. We look for that here -+ * as a special case, and return a frame where the frame pointer is -+ * set to NULL (as it ought to be). -+ * -+ * If we do not know the beginning of the stack, we are out of luck. -+ */ -+ if (current->dt_task && current->dt_task->dt_ustack == frame->fp) { -+ frame->fp = NULL; -+ return 0; -+ } -+ -+ /* -+ * Verify strictly increasing consecutive values. Since the stack -+ * grows downward, walking the call chain in reverse must yield ever -+ * increasing frame pointers. -+ */ -+ if (ofp >= frame->fp) -+ return -EINVAL; -+ -+ return 0; -+} -+ -+void dtrace_user_stacktrace(struct stacktrace_state *st) -+{ -+ struct pt_regs *regs = current_pt_regs(); -+ uint64_t *pcs = st->pcs; -+ int limit = st->limit; -+ int fixups, patches, skip; -+ struct user_stackframe frame0, frame; -+ struct user_stackframe *bos = current->dt_task -+ ? current->dt_task->dt_ustack -+ : NULL; -+ struct return_instance *rilist = current->utask -+ ? current->utask->return_instances -+ : NULL; -+ struct return_instance *ri; -+ -+ /* -+ * If we do not have user-mode registers, or if there is no known -+ * bottom of stack, we cannot collect a call chain. -+ */ -+ if (!user_mode(regs)) -+ goto out; -+ if (!bos) -+ goto out; -+ if (!limit) -+ goto out; -+ -+ frame0.fp = (struct user_stackframe __user *)regs->regs[29]; -+ frame0.lr = regs->regs[30]; -+ -+ /* -+ * The first special situation we need to deal with here is the rare -+ * case of tracing the instruction after a call, when the current -+ * program counter just got loaded from the link register, i.e. they -+ * will be the same. In that case, we don't want to record both pc -+ * and lr in the trace. -+ * -+ * Uretprobes are also tricky because if we are asked to provide a -+ * ustack() while processing a uretprobe firing, we are still in the -+ * middle of handling the probe. Things are not back to normal yet. -+ */ -+ if (regs->pc != frame0.lr) { -+ ri = rilist; -+ if (pcs) { -+ if (uprobe_return_addr_is_hijacked(frame0.lr) && -+ ri && ri->orig_ret_vaddr == regs->pc) -+ *pcs++ = ri->func; -+ else -+ *pcs++ = regs->pc; -+ } -+ -+ limit--; -+ st->depth++; -+ -+ if (!limit) -+ goto out; -+ } -+ -+ /* -+ * First pass: determine how many return addresses need to be fixed up, -+ * and how many return instances we have. -+ */ -+ frame = frame0; -+ fixups = 0; -+ do { -+ if (uprobe_return_addr_is_hijacked(frame.lr)) -+ fixups++; -+ -+ if (frame.fp == NULL) -+ break; -+ -+ if (dtrace_unwind_frame(&frame) < 0) { -+ this_cpu_core->cpuc_dtrace_illval = (uintptr_t)frame.fp; -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_BADSTACK); -+ break; -+ } -+ } while (frame.lr); -+ -+ patches = 0; -+ for (ri = rilist; ri != NULL; ri = ri->next) -+ patches++; -+ -+ /* -+ * It is possible that we think we need one more fixup than we can -+ * satisfy with the return instances. This is because we cannot quite -+ * determine whether the first one is actually needed or not (due to -+ * lack of proper state when the uretprobe implementation interferes -+ * with frame chain walking). -+ */ -+ skip = fixups - patches; -+ if (skip > 1) { -+ this_cpu_core->cpuc_dtrace_illval = 0; -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_BADSTACK); -+ goto out; -+ } -+ -+ /* -+ * Second pass: fill in the actual stack trace. -+ */ -+ frame = frame0; -+ ri = rilist; -+ do { -+ if (uprobe_return_addr_is_hijacked(frame.lr)) { -+ if (skip) { -+ skip = 0; -+ goto skip_frame; -+ } -+ -+ frame.lr = ri->orig_ret_vaddr; -+ ri = ri->next; -+ } -+ -+ if (pcs) -+ *pcs++ = frame.lr; -+ -+ limit--; -+ st->depth++; -+ -+skip_frame: -+ if (frame.fp == NULL) -+ break; -+ -+ if (dtrace_unwind_frame(&frame) < 0) { -+ this_cpu_core->cpuc_dtrace_illval = (uintptr_t)frame.fp; -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_BADSTACK); -+ break; -+ } -+ } while (limit); -+ -+out: -+ if (pcs) { -+ while (limit--) -+ *pcs++ = 0; -+ } -+} -+ -+asm_instr_t dtrace_text_peek(asm_instr_t *addr) -+{ -+ asm_instr_t opcode; -+ -+ aarch64_insn_read(addr, &opcode); -+ -+ return opcode; -+} -+EXPORT_SYMBOL(dtrace_text_peek); -+ -+void dtrace_text_poke(asm_instr_t *addr, asm_instr_t opcode) -+{ -+ aarch64_insn_patch_text_nosync(addr, opcode); -+} -+EXPORT_SYMBOL(dtrace_text_poke); -+ -+void dtrace_kernel_brk_start(void *arg) -+{ -+ register_kernel_break_hook((struct break_hook *)arg); -+} -+EXPORT_SYMBOL(dtrace_kernel_brk_start); -+ -+void dtrace_kernel_brk_stop(void *arg) -+{ -+ unregister_kernel_break_hook((struct break_hook *)arg); -+} -+EXPORT_SYMBOL(dtrace_kernel_brk_stop); -+ -+void dtrace_mod_pdata_init(struct dtrace_module *pdata) -+{ -+} -+ -+void dtrace_mod_pdata_cleanup(struct dtrace_module *pdata) -+{ -+} -diff --git a/arch/arm64/kernel/entry-common.c b/arch/arm64/kernel/entry-common.c -index 70e0a7591245..b4f8280d9ce3 100644 ---- a/arch/arm64/kernel/entry-common.c -+++ b/arch/arm64/kernel/entry-common.c -@@ -199,8 +199,7 @@ static void noinstr el1_fpac(struct pt_regs *regs, unsigned long esr) - local_daif_mask(); - exit_to_kernel_mode(regs); - } -- --asmlinkage void noinstr el1_sync_handler(struct pt_regs *regs) -+asmlinkage int noinstr el1_sync_handler(struct pt_regs *regs) - { - unsigned long esr = read_sysreg(esr_el1); - -@@ -225,13 +224,14 @@ asmlinkage void noinstr el1_sync_handler(struct pt_regs *regs) - case ESR_ELx_EC_WATCHPT_CUR: - case ESR_ELx_EC_BRK64: - el1_dbg(regs, esr); -- break; -+ return 1; - case ESR_ELx_EC_FPAC: - el1_fpac(regs, esr); - break; - default: - el1_inv(regs, esr); - } -+ return 0; - } - - asmlinkage void noinstr enter_from_user_mode(void) -diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S -index d72c818b019c..6ac1846a645e 100644 ---- a/arch/arm64/kernel/entry.S -+++ b/arch/arm64/kernel/entry.S -@@ -28,6 +28,7 @@ - #include <asm/thread_info.h> - #include <asm/asm-uaccess.h> - #include <asm/unistd.h> -+#include <asm/debug-monitors.h> - - /* - * Context tracking and irqflag tracing need to instrument transitions between -@@ -276,7 +277,7 @@ alternative_else_nop_endif - */ - .endm - -- .macro kernel_exit, el -+ .macro kernel_exit, el, fbt_emu = 0 - .if \el != 0 - disable_daif - -@@ -332,7 +333,11 @@ alternative_else_nop_endif - - msr elr_el1, x21 // set up the return data - msr spsr_el1, x22 -- ldp x0, x1, [sp, #16 * 0] -+ -+ /* -+ * No need to restore x0 and x1 - we may still clobber them. We will -+ * restore them right before we return. -+ */ - ldp x2, x3, [sp, #16 * 1] - ldp x4, x5, [sp, #16 * 2] - ldp x6, x7, [sp, #16 * 3] -@@ -348,7 +353,44 @@ alternative_else_nop_endif - ldp x26, x27, [sp, #16 * 13] - ldp x28, x29, [sp, #16 * 14] - ldr lr, [sp, #S_LR] -+ -+ .if \fbt_emu != 0 // FBT emulation needed? -+ mrs x0, esr_el1 // check if ESR is FBT probe -+ and x0, x0, #0x1f // ... mask code -+ cmp x0, #DPROBES_FBE_BRK_IMM // ... compare with FBE code -+ beq 6f // FBT entry -> emulate instr. -+ cmp x0, #DPROBES_FBR_BRK_IMM // ... compare with FBR code -+ beq 7f // FBT return -> emulate instr. -+ b 8f // not FBT -> skip next section -+ -+6: -+ mrs x0, elr_el1 // retrieve xeceptionx link reg -+ add x0, x0, #0x4 // advance to next instr -+ msr elr_el1, x0 // set exception link reg -+ -+ ldp x0, x1, [sp, #16 * 0] // done with x0, restore orig - add sp, sp, #S_FRAME_SIZE // restore sp -+ mov x29, sp // instr we put probe on -+ b 9f // FBT done -> branch to eret -+ -+7: -+ msr elr_el1, lr // set exception link reg to -+ // link register value, to -+ // simulate the 'ret' instr. -+ -+ ldp x0, x1, [sp, #16 * 0] // done with x0, restore orig -+ add sp, sp, #S_FRAME_SIZE // restore sp -+ b 9f // FBT done -> branch to eret -+ -+8: -+ ldp x0, x1, [sp, #16 * 0] // done with x0, restore orig -+ add sp, sp, #S_FRAME_SIZE // restore sp -+9: -+ .else -+ ldp x0, x1, [sp, #16 * 0] // done with x0, restore orig -+ add sp, sp, #S_FRAME_SIZE // restore sp -+ -+ .endif - - .if \el == 0 - alternative_insn eret, nop, ARM64_UNMAP_KERNEL_AT_EL0 -@@ -625,7 +667,12 @@ SYM_CODE_START_LOCAL_NOALIGN(el1_sync) - kernel_entry 1 - mov x0, sp - bl el1_sync_handler -- kernel_exit 1 -+#if IS_ENABLED(CONFIG_DT_FBT) -+ cmp x0, 1 -+ b.ne 1020f -+ kernel_exit 1, 1 -+#endif -+1020: kernel_exit 1 - SYM_CODE_END(el1_sync) - - .align 6 -diff --git a/arch/arm64/kernel/fbt_blacklist.h b/arch/arm64/kernel/fbt_blacklist.h -new file mode 100644 -index 000000000000..7ad327515c8f ---- /dev/null -+++ b/arch/arm64/kernel/fbt_blacklist.h -@@ -0,0 +1,91 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Functions used in die notifier chain calling. -+ */ -+BL_SENTRY(void *, notify_die) -+BL_DENTRY(void *, notifier_call_chain) -+BL_SENTRY(typeof(atomic_notifier_call_chain_robust), atomic_notifier_call_chain_robust) -+BL_SENTRY(typeof(atomic_notifier_call_chain), atomic_notifier_call_chain) -+BL_SENTRY(typeof(raw_notifier_call_chain_robust), raw_notifier_call_chain_robust) -+BL_SENTRY(typeof(raw_notifier_call_chain), raw_notifier_call_chain) -+BL_DENTRY(void *, hw_breakpoint_exceptions_notify) -+BL_DENTRY(void *, kprobe_exceptions_notify) -+ -+/* -+ * Functions used to update vtime in probe context. -+ */ -+BL_SENTRY(typeof(ktime_get_raw_fast_ns), ktime_get_raw_fast_ns) -+BL_DENTRY(void *, raw_read_seqcount) -+BL_DENTRY(void *, read_seqcount_retry) -+BL_DENTRY(void *, __read_seqcount_retry) -+ -+/* xen_clocksource */ -+BL_DENTRY(void *, xen_clocksource_get_cycles) -+BL_DENTRY(void *, xen_clocksource_read) -+BL_DENTRY(void *, pvclock_clocksource_read) -+BL_DENTRY(void *, pvclock_touch_watchdogs) -+BL_DENTRY(void *, touch_softlockup_watchdog_sync) -+BL_DENTRY(void *, clocksource_touch_watchdog) -+BL_DENTRY(void *, clocksource_resume_watchdog) -+BL_DENTRY(void *, reset_hung_task_detector) -+/* clocksource_tsc */ -+BL_DENTRY(void *, read_tsc) -+BL_DENTRY(void *, get_cycles) -+/* clocksource_hpet */ -+BL_DENTRY(void *, read_hpet) -+BL_DENTRY(void *, hpet_readl) -+/* kvm_clock */ -+BL_DENTRY(void *, kvm_clock_get_cycles) -+BL_DENTRY(void *, kvm_clock_read) -+/* arm_arch */ -+BL_DENTRY(void *, arch_counter_get_cntvct); -+BL_DENTRY(void *, arch_counter_get_cntvct_mem); -+BL_DENTRY(void *, arch_counter_get_cntpct); -+BL_DENTRY(void *, arch_counter_read); -+ -+/* -+ * Functions used in trap handling. -+ */ -+BL_DENTRY(void *, fixup_exception) -+BL_DENTRY(void *, paranoid_entry) -+BL_DENTRY(void *, kgdb_ll_trap) -+BL_DENTRY(void *, error_entry) -+BL_DENTRY(void *, xen_int3) -+BL_DENTRY(void *, ftrace_int3_handler) -+BL_DENTRY(typeof(poke_int3_handler), poke_int3_handler) -+BL_DENTRY(void *, fixup_bad_iret) -+BL_DENTRY(void *, xen_adjust_exception_frame) -+BL_DENTRY(void *, paravirt_nop) -+BL_DENTRY(void *, ist_enter) -+BL_DENTRY(void *, rcu_nmi_enter) -+BL_DENTRY(void *, rcu_dynticks_curr_cpu_in_eqs) -+BL_DENTRY(void *, rcu_dynticks_eqs_exit) -+BL_DENTRY(void *, rcu_nmi_exit) -+BL_DENTRY(void *, rcu_dynticks_eqs_enter) -+BL_DENTRY(void *, ist_exit) -+ -+/* -+ * Functions used in page fault handling. -+ */ -+BL_DENTRY(void *, do_page_fault) -+BL_DENTRY(void *, __do_page_fault) -+BL_DENTRY(void *, down_read_trylock) -+BL_DENTRY(void *, __get_user_pages_fast) -+BL_DENTRY(void *, gup_pud_range) -+BL_DENTRY(void *, gup_huge_pud) -+BL_DENTRY(void *, gup_pmd_range) -+BL_DENTRY(void *, gup_huge_pmd) -+BL_DENTRY(void *, gup_pte_range) -+BL_DENTRY(void *, pte_mfn_to_pfn) -+ -+/* -+ * Functions used under 4.19 idr_find -+ */ -+BL_DENTRY(void *, idr_find) -+BL_DENTRY(void *, find_next_bit) -+BL_DENTRY(void *, _find_next_bit) -+BL_DENTRY(void *, radix_tree_lookup) -+BL_DENTRY(void *, __radix_tree_lookup) -+BL_DENTRY(void *, radix_tree_load_root) -+BL_DENTRY(void *, radix_tree_descend) -+BL_DENTRY(void *, is_sibling_entry) -diff --git a/arch/arm64/kernel/probes/uprobes.c b/arch/arm64/kernel/probes/uprobes.c -index a412d8edbcd2..49482af77b9f 100644 ---- a/arch/arm64/kernel/probes/uprobes.c -+++ b/arch/arm64/kernel/probes/uprobes.c -@@ -179,7 +179,8 @@ static int uprobe_single_step_handler(struct pt_regs *regs, - { - struct uprobe_task *utask = current->utask; - -- WARN_ON(utask && (instruction_pointer(regs) != utask->xol_vaddr + 4)); -+ WARN_ON(utask && utask->active_uprobe && -+ (instruction_pointer(regs) != utask->xol_vaddr + 4)); - if (uprobe_post_sstep_notifier(regs)) - return DBG_HOOK_HANDLED; - -diff --git a/arch/arm64/kernel/sys.c b/arch/arm64/kernel/sys.c -index d5ffaaab31a7..4563f0a4d0db 100644 ---- a/arch/arm64/kernel/sys.c -+++ b/arch/arm64/kernel/sys.c -@@ -55,7 +55,7 @@ asmlinkage long __arm64_sys_ni_syscall(const struct pt_regs *__unused) - #undef __SYSCALL - #define __SYSCALL(nr, sym) [nr] = __arm64_##sym, - --const syscall_fn_t sys_call_table[__NR_syscalls] = { -+CONST_SYS_CALL_TABLE syscall_fn_t sys_call_table[__NR_syscalls] = { - [0 ... __NR_syscalls - 1] = __arm64_sys_ni_syscall, - #include <asm/unistd.h> - }; -diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c -index 795d224f184f..d2725a8ac9f3 100644 ---- a/arch/arm64/mm/fault.c -+++ b/arch/arm64/mm/fault.c -@@ -14,6 +14,7 @@ - #include <linux/mm.h> - #include <linux/hardirq.h> - #include <linux/init.h> -+#include <linux/kdebug.h> - #include <linux/kprobes.h> - #include <linux/uaccess.h> - #include <linux/page-flags.h> -@@ -60,6 +61,19 @@ static inline const struct fault_info *esr_to_debug_fault_info(unsigned int esr) - return debug_fault_info + DBG_ESR_EVT(esr); - } - -+#ifdef CONFIG_DTRACE -+static int dtrace_fault(struct pt_regs *regs, unsigned long addr) -+{ -+ preempt_disable(); -+ if (notify_die(DIE_PAGE_FAULT, "page fault", regs, addr, 14, -+ SIGKILL) == NOTIFY_STOP) -+ return 1; -+ preempt_enable(); -+ -+ return 0; -+} -+#endif -+ - static void data_abort_decode(unsigned int esr) - { - pr_alert("Data abort info:\n"); -@@ -459,6 +473,10 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr, - - if (kprobe_page_fault(regs, esr)) - return 0; -+#ifdef CONFIG_DTRACE -+ if (dtrace_fault(regs, addr)) -+ return 0; -+#endif - - /* - * If we're in an interrupt or have no user context, we must not take -diff --git a/include/linux/uprobes.h b/include/linux/uprobes.h -index f46e0ca0169c..b27885982066 100644 ---- a/include/linux/uprobes.h -+++ b/include/linux/uprobes.h -@@ -124,6 +124,7 @@ extern void uprobe_copy_process(struct task_struct *t, unsigned long flags); - extern int uprobe_post_sstep_notifier(struct pt_regs *regs); - extern int uprobe_pre_sstep_notifier(struct pt_regs *regs); - extern void uprobe_notify_resume(struct pt_regs *regs); -+extern bool uprobe_return_addr_is_hijacked(unsigned long addr); - extern bool uprobe_deny_signal(void); - extern bool arch_uprobe_skip_sstep(struct arch_uprobe *aup, struct pt_regs *regs); - extern void uprobe_clear_state(struct mm_struct *mm); -diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c -index 00b0358739ab..5a7a1c019870 100644 ---- a/kernel/events/uprobes.c -+++ b/kernel/events/uprobes.c -@@ -1845,6 +1845,16 @@ static unsigned long get_trampoline_vaddr(void) - return trampoline_vaddr; - } - -+/* -+ * Verify whether a return address is a trampoline address or a regular return -+ * address. This is used by stack unwinders to determine whether a return -+ * address in a stack trace needs to be adjusted. -+ */ -+bool uprobe_return_addr_is_hijacked(unsigned long addr) -+{ -+ return addr == get_trampoline_vaddr(); -+} -+ - static void cleanup_return_instances(struct uprobe_task *utask, bool chained, - struct pt_regs *regs) - { -diff --git a/scripts/dtrace_sdt_arm64.sh b/scripts/dtrace_sdt_arm64.sh -new file mode 100755 -index 000000000000..a8fdc4ae0bc4 ---- /dev/null -+++ b/scripts/dtrace_sdt_arm64.sh -@@ -0,0 +1,425 @@ -+#!/bin/sh -+ -+LANG=C -+export LANG -+ -+# -+# Syntax: -+# dtrace_sdt_arm64.sh sdtinfo <S-file> <l-file> <o-file> -+# This is used to generate DTrace SDT probe definitions for a -+# linked kernel image file <l-file>, based on relocation info -+# from the kernel object file <o-file>. The output is written -+# to <S-file>. -+# -+ -+opr="$1" -+shift -+if [ -z "$opr" ]; then -+ echo "ERROR: Missing operation" > /dev/stderr -+ exit 1 -+elif [ "$opr" != "sdtinfo" ]; then -+ echo "ERROR: Invalid operation: ${opr}" > /dev/stderr -+ exit 1 -+fi -+ -+tfn="$1" -+shift -+if [ -z "$tfn" ]; then -+ echo "ERROR: Missing target filename" > /dev/stderr -+ exit 1 -+fi -+ -+lfn="$1" -+ofn="$2" -+ -+if [ -z "$lfn" ]; then -+ echo "ERROR: Missing linked kernel file argument" > /dev/stderr -+ exit 1 -+elif [ -z "$ofn" ]; then -+ echo "ERROR: Missing kernel object file argument" > /dev/stderr -+ exit 1 -+fi -+ -+# For arm64, the kernel is built using "-ffunction-sections -fdata-sections" -+# which due to the linked bug conflicts with "--emit-relocs". Probe discovery -+# therefore is a bit more complicated. -+# -+# First we collect the VMA address of all the code sections in the linked -+# kernel image. -+# -+# Subsequently, we go through the list of symbols in the linked kernel image, -+# and write out records for some select symbols that are used in the processing -+# of probe locations: -+# -+# <section> <address> B <name> -+# Named identifier at a specific address (global variable). -+# -+# We also process any function symbols, and build a lookup map for section-name -+# pairs and just name. Due to the possibility of having symbols with identical -+# names (in the same section, e.g. global and/or one or more local), we append -+# -<n> to every 2nd and later copy of the same symbol name in the current -+# section. -+# section and name -+# name -+# (If multiple symbols map to any of the above combinations, that specific -+# combination is omitted from the mapping.) -+# -+# Next, we process the list of function symbols, and for any function that -+# is not located in a section that starts with .exit.text, .init.text, or -+# .meminit.text) we determine its in-section offset and output a record: -+# -+# <section> <offset> F <name> <address> <section-base-address> -+# Named function at a specific address. -+# -+# Finally, each relocation record from a non-init or exit section that relates -+# to SDT probes is written to the output stream: -+# -+# <section> <address> R <value> -+# Relocation within a section at a specific address -+# -+# Probes are identified in the relocation records as symbols with either a -+# __dtrace_probe_ or __dtrace_isenabled_ prefix. -+# -+# All these records are sorted by section and offset, and any SDT probe -+# location relocation records (R) result in writing out an entry that records -+# its offset relative to the _stext symbol, along with the name of the function -+# it was found in, and the probe name. -+ -+( -+ objdump -ht ${lfn} -+ objdump -tr ${ofn} -+) | \ -+ gawk 'function subl(v0, v1, v0h, v0l, v1h, v1l, d, tmp) { -+ tmp = $0; -+ if (length(v0) > 8) { -+ d = length(v0); -+ v0h = strtonum("0x"substr(v0, 1, d - 8)); -+ v0l = strtonum("0x"substr(v0, d - 8 + 1)); -+ d = length(v1); -+ v1h = strtonum("0x"substr(v1, 1, d - 8)); -+ v1l = strtonum("0x"substr(v1, d - 8 + 1)); -+ -+ if (v0l >= v1l) { -+ if (v0h >= v1h) { -+ d = sprintf("%08x%08x", v0h - v1h, v0l - v1l); -+ } else { -+ printf "ERROR: [stage 1.a] Invalid addresses: %s - %s\n", v0, v1; -+ d = 0; -+ errc++; -+ } -+ } else { -+ if (v0h > v1h) { -+ v0h--; -+ v0l += 4294967296; -+ d = sprintf("%08x%08x", v0h - v1h, v0l - v1l); -+ } else { -+ printf "ERROR: [stage 1.b] Invalid addresses: %s - %s\n", v0, v1; -+ d = 0; -+ errc++; -+ } -+ } -+ } else { -+ v0 = strtonum("0x"v0); -+ v1 = strtonum("0x"v1); -+ d = sprintf("%016x", v0 - v1); -+ } -+ $0 = tmp; -+ -+ return d; -+ } -+ -+ BEGIN { -+ phase = 0; -+ } -+ -+ /^SYMBOL / { -+ phase++; -+ delete scnt; -+ next; -+ } -+ -+ phase == 0 && /^ *[1-9][0-9]* / { -+ snam = $2; -+ addr = $4; -+ getline; -+ if (/CODE/) -+ secs[snam] = addr; -+ -+ next; -+ } -+ -+ phase == 1 && $NF ~ /_(stext|_init_(begin|end))$/ { -+ print ". " $1 " B " $NF; -+ next; -+ } -+ -+ phase == 1 && / F / { -+ if ($4 ~ /^\.(exit|init|meminit)\.text/) -+ next; -+ -+ off = subl($1, secs[$4]); -+ -+ sym = $NF; -+ scnt[sym]++; -+ if (scnt[sym] > 1) -+ sym = sym"-"(scnt[sym] - 1); -+ -+ # section and name -+ id = $4 " " sym; -+ if (id in smap) { -+ if (smap[id] != $1) -+ smap[id] = 0; -+ } else -+ smap[id] = $1; -+ -+ # name -+ id = sym; -+ if (id in smap) { -+ if (smap[id] != $1) -+ smap[id] = 0; -+ } else -+ smap[id] = $1; -+ -+ next; -+ } -+ -+ phase == 2 && / F / { -+ if ($4 ~ /^\.(exit|init|meminit)\.text/) -+ next; -+ -+ sym = $NF; -+ scnt[sym]++; -+ if (scnt[sym] > 1) -+ sym = sym"-"(scnt[sym] - 1); -+ -+ # section and name -+ id = $4 " " sym; -+ if (!(id in smap)) -+ id = sym; -+ # name -+ if (id in smap) { -+ addr = smap[id]; -+ if (!addr) -+ print "ERROR: Non-unique symbol: " $4 " " $6 " " $1 " ["sym"]"; -+ } else { -+ print "ERROR: Could not find " $4 " " $6 " " $1 " ["sym"]"; -+ addr = 0; -+ } -+ -+ print $4 " " $1 " F " $6 " " addr " " secs[$4]; -+ next; -+ } -+ -+ /^RELOC/ { -+ sect = substr($4, 2, length($4) - 3); -+ next; -+ } -+ -+ sect ~ /^\.(exit|init|meminit)\.text/ { -+ next; -+ } -+ -+ sect && /__dtrace_probe_/ { -+ $3 = substr($3, 16); -+ sub(/[\-+].*$/, "", $3); -+ print sect " " $1 " R " $3; -+ next; -+ } -+ -+ sect && /__dtrace_isenabled_/ { -+ $3 = substr($3, 20); -+ sub(/[\-+].*$/, "", $3); -+ print sect " " $1 " R ?" $3; -+ next; -+ }' | \ -+ sort -u | \ -+ gawk 'function addl(v0, v1, v0h, v0l, v1h, v1l, d, tmp) { -+ tmp = $0; -+ if (length(v0) > 8 || length(v1) > 8) { -+ d = length(v0); -+ v0h = strtonum("0x"substr(v0, 1, d - 8)); -+ v0l = strtonum("0x"substr(v0, d - 8 + 1)); -+ d = length(v1); -+ v1h = strtonum("0x"substr(v1, 1, d - 8)); -+ v1l = strtonum("0x"substr(v1, d - 8 + 1)); -+ -+ v0l += v1l; -+ v0h += v1h; -+ d = sprintf("%x", v0l); -+ if (length(d) > 8) { -+ v0h++; -+ v0l -= 4294967296; -+ } -+ d = sprintf("%x", v0h); -+ if (length(d) <= 8) { -+ d = sprintf("%08x%08x", v0h, v0l); -+ } else { -+ printf "#error [stage 2.a] Invalid addresses: %s + %s\n", v0, v1 \ -+ >"/dev/stderr"; -+ errc++; -+ } -+ } else { -+ v0 = strtonum("0x"v0); -+ v1 = strtonum("0x"v1); -+ d = sprintf("%016x", v0 + v1); -+ } -+ $0 = tmp; -+ -+ return d; -+ } -+ -+ function subl(v0, v1, v0h, v0l, v1h, v1l, d, tmp) { -+ tmp = $0; -+ if (length(v0) > 8) { -+ d = length(v0); -+ v0h = strtonum("0x"substr(v0, 1, d - 8)); -+ v0l = strtonum("0x"substr(v0, d - 8 + 1)); -+ d = length(v1); -+ v1h = strtonum("0x"substr(v1, 1, d - 8)); -+ v1l = strtonum("0x"substr(v1, d - 8 + 1)); -+ -+ if (v0l >= v1l) { -+ if (v0h >= v1h) { -+ d = sprintf("%08x%08x", v0h - v1h, v0l - v1l); -+ } else { -+ printf "#error [stage 2.b] Invalid addresses: %s - %s\n", v0, v1 \ -+ >"/dev/stderr"; -+ errc++; -+ } -+ } else { -+ if (v0h > v1h) { -+ v0h--; -+ v0l += 4294967296; -+ d = sprintf("%08x%08x", v0h - v1h, v0l - v1l); -+ } else { -+ printf "#error [stage 2.c] Invalid addresses: %s - %s\n", v0, v1 \ -+ >"/dev/stderr"; -+ errc++; -+ } -+ } -+ } else { -+ v0 = strtonum("0x"v0); -+ v1 = strtonum("0x"v1); -+ d = sprintf("%016x", v0 - v1); -+ } -+ $0 = tmp; -+ -+ return d; -+ } -+ -+ function map_string(str, off) { -+ if (str in strmap) -+ off = strmap[str]; -+ else { -+ off = strsz; -+ strmap[str] = strsz; -+ strv[strc++] = str; -+ strsz += length(str) + 1; -+ } -+ -+ return off; -+ } -+ -+ BEGIN { -+ print "#include <asm/types.h>"; -+ print "#if BITS_PER_LONG == 64"; -+ print "# define PTR .quad"; -+ if (arch == "aarch64") -+ print "# define ALGN .align 3"; -+ else -+ print "# define ALGN .align 8"; -+ print "#else"; -+ print "# define PTR .long"; -+ if (arch == "aarch64") -+ print "# define ALGN .align 2"; -+ else -+ print "# define ALGN .align 4"; -+ print "#endif"; -+ -+ print "\t.section .rodata, \042a\042"; -+ print ""; -+ -+ print ".globl dtrace_sdt_probes"; -+ print "\tALGN"; -+ print "dtrace_sdt_probes:"; -+ -+ probec = 0; -+ stroff = 0; -+ strc = 0; -+ } -+ -+ $1 == "ERROR:" { -+ next; -+ } -+ -+ $4 == "_stext" { -+ stext = $2; -+ next; -+ } -+ -+ $4 == "__init_begin" { -+ init_beg = $2; -+ next; -+ } -+ -+ $4 == "__init_end" { -+ init_end = $2; -+ next; -+ } -+ -+ $3 == "F" { -+ fnam = $4; -+ sub(/\..*$/, "", fnam); -+ foff = $2; -+ fadr = $5; -+ -+ if (fadr != padr) -+ funcc++; -+ padr = fadr; -+ -+ next; -+ } -+ -+ $3 == "R" { -+ addr = addl(fadr, subl($2, foff)); -+ if (addr >= init_beg && addr <= init_end) -+ next; -+ addr = subl(addr, stext); -+ -+ print "/*"; -+ print " * " $1 " " foff " F " fnam " " fadr; -+ print " * " $0; -+ print " * (" fadr " + (" $2 " - " foff ")) - " stext; -+ print " */"; -+ printf "\tPTR\t_stext + 0x%s\n", addr; -+ printf "\tPTR\t%d\n", map_string($4); -+ printf "\tPTR\t%d\n", map_string(fnam); -+ -+ probec++; -+ -+ next; -+ } -+ -+ END { -+ print ""; -+ print ".globl dtrace_sdt_strings"; -+ print "\tALGN"; -+ print "dtrace_sdt_strings:"; -+ -+ -+ for (i = 0; i < strc; i++) -+ printf "\t.asciz\t\042%s\042\n", strv[i]; -+ -+ print ""; -+ print ".globl dtrace_sdt_nprobes"; -+ print ".globl dtrace_fbt_nfuncs"; -+ print "\tALGN"; -+ print "dtrace_sdt_nprobes:"; -+ printf "\tPTR\t%d\n", probec; -+ print "dtrace_fbt_nfuncs:"; -+ printf "\tPTR\t%d\n", funcc; -+ -+ exit(errc == 0 ? 0 : 1); -+ }' > ${tfn} -+ -+exit $? -diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh -index 0b2f3bb60936..aa4c70504d8c 100755 ---- a/scripts/link-vmlinux.sh -+++ b/scripts/link-vmlinux.sh -@@ -63,7 +63,12 @@ sdtinfo() - { - info SDTINF ${2} - -- ${srctree}/scripts/dtrace_sdt.sh sdtinfo .tmp_sdtinfo.S ${1} -+ if [ -n "${CONFIG_ARM64}" ]; then -+ ${srctree}/scripts/dtrace_sdt_arm64.sh sdtinfo .tmp_sdtinfo.S \ -+ ${1} ${3} -+ else -+ ${srctree}/scripts/dtrace_sdt.sh sdtinfo .tmp_sdtinfo.S ${1} -+ fi - - local aflags="${KBUILD_AFLAGS} ${KBUILD_AFLAGS_KERNEL} \ - ${NOSTDINC_FLAGS} ${LINUXINCLUDE} ${KBUILD_CPPFLAGS}" -@@ -389,16 +394,14 @@ if [ -n "${CONFIG_KALLSYMS}" ]; then - - # step 1 - if [ -n "${CONFIG_DTRACE}" ]; then -- sdtinfo vmlinux.o ${sdtinfoo} -+ sdtinfo vmlinux.o ${sdtinfoo} vmlinux.o - fi - - kallsyms_step 1 - - if [ -n "${CONFIG_DTRACE}" ]; then -- if [ -n "${CONFIG_ARM64}" ]; then -- kallsyms_step 1 -- else -- kallsyms_step 1 -r -+ if [ -n "${CONFIG_X86_64}" ]; then -+ kallsyms_step 1 --emit-relocs - fi - sdtinfo ${kallsyms_vmlinux} ${sdtinfoo} vmlinux.o - fi --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/dtrace-patches/0017-dtrace-add-SDT-probes.patch b/sys-kernel/cairn-sources/files/5.10.13/dtrace-patches/0017-dtrace-add-SDT-probes.patch deleted file mode 100644 index c0d71f7e0b63..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/dtrace-patches/0017-dtrace-add-SDT-probes.patch +++ /dev/null @@ -1,3306 +0,0 @@ -From 5694e5386d32e8fe708a76177b44244d18bd8f7b Mon Sep 17 00:00:00 2001 -From: Kris Van Hees <kris.van.hees@oracle.com> -Date: Thu, 8 Nov 2018 18:59:39 +0000 -Subject: [PATCH 17/19] dtrace: add SDT probes - -This adds a variety of SDT probes. - -XXX add documentation here from the commit messages - -Signed-off-by: Nick Alcock <nick.alcock@oracle.com> -Signed-off-by: Kris Van Hees <kris.van.hees@oracle.com> -Signed-off-by: Tomas Jedlicka <tomas.jedlicka@oracle.com> -Signed-off-by: Eugene Loh <eugene.loh@oracle.com> -Signed-off-by: Alan Maguire <alan.maguire@oracle.com> -Signed-off-by: David Mc Lean <david.mclean@oracle.com> -Signed-off-by: Vincent Lim <vincent.lim@oracle.com> ---- - block/bio.c | 7 ++ - block/blk-core.c | 4 + - fs/exec.c | 8 ++ - fs/nfs/internal.h | 13 +++ - fs/nfs/read.c | 3 + - fs/nfs/write.c | 2 + - fs/xfs/xfs_buf.c | 19 ++++ - include/linux/rwlock_api_smp.h | 38 +++++++ - include/linux/spinlock_api_smp.h | 12 ++ - kernel/exit.c | 5 + - kernel/fork.c | 3 + - kernel/locking/mutex.c | 52 ++++++++- - kernel/locking/qrwlock.c | 24 +++- - kernel/locking/qspinlock.c | 20 +++- - kernel/sched/core.c | 31 +++++- - kernel/signal.c | 31 +++++- - kernel/time/timer.c | 3 + - net/ipv4/ip_input.c | 66 +++++++++-- - net/ipv4/ip_output.c | 71 +++++++++++- - net/ipv4/raw.c | 49 ++++++-- - net/ipv4/tcp.c | 26 +++++ - net/ipv4/tcp_input.c | 43 +++++++ - net/ipv4/tcp_ipv4.c | 114 ++++++++++++++++++- - net/ipv4/tcp_minisocks.c | 15 +++ - net/ipv4/tcp_output.c | 29 +++++ - net/ipv4/udp.c | 26 ++++- - net/ipv6/ip6_input.c | 103 ++++++++++++++--- - net/ipv6/ip6_output.c | 186 ++++++++++++++++++++++++++----- - net/ipv6/mcast.c | 72 +++++++++--- - net/ipv6/ndisc.c | 9 ++ - net/ipv6/output_core.c | 9 ++ - net/ipv6/raw.c | 38 ++++++- - net/ipv6/tcp_ipv6.c | 107 +++++++++++++++++- - net/ipv6/udp.c | 26 ++++- - 34 files changed, 1153 insertions(+), 111 deletions(-) - -diff --git a/block/bio.c b/block/bio.c -index fa01bef35bb1..f2cde8dc402c 100644 ---- a/block/bio.c -+++ b/block/bio.c -@@ -1153,6 +1153,8 @@ int submit_bio_wait(struct bio *bio) - bio->bi_opf |= REQ_SYNC; - submit_bio(bio); - -+ DTRACE_IO(wait__start, struct bio * : (bufinfo_t *, devinfo_t *), bio, -+ struct file * : fileinfo_t *, NULL); - /* Prevent hang_check timer from firing at us during very long I/O */ - hang_check = sysctl_hung_task_timeout_secs; - if (hang_check) -@@ -1161,6 +1163,8 @@ int submit_bio_wait(struct bio *bio) - ; - else - wait_for_completion_io(&done); -+ DTRACE_IO(wait__done, struct bio * : (bufinfo_t *, devinfo_t *), bio, -+ struct file * : fileinfo_t *, NULL); - - return blk_status_to_errno(bio->bi_status); - } -@@ -1444,6 +1448,9 @@ void bio_endio(struct bio *bio) - } - - blk_throtl_bio_endio(bio); -+ DTRACE_IO(done, struct bio * : -+ (bufinfo_t *, devinfo_t *), bio, -+ struct file * : fileinfo_t *, NULL); - /* release cgroup info */ - bio_uninit(bio); - if (bio->bi_end_io) -diff --git a/block/blk-core.c b/block/blk-core.c -index 2d53e2ff48ff..67523a6729fb 100644 ---- a/block/blk-core.c -+++ b/block/blk-core.c -@@ -913,11 +913,15 @@ static noinline_for_stack bool submit_bio_checks(struct bio *bio) - */ - bio_set_flag(bio, BIO_TRACE_COMPLETION); - } -+ DTRACE_IO(start, struct bio * : (bufinfo_t *, devinfo_t *), bio, -+ struct file * : fileinfo_t *, NULL); - return true; - - not_supported: - status = BLK_STS_NOTSUPP; - end_io: -+ DTRACE_IO(start, struct bio * : (bufinfo_t *, devinfo_t *), bio, -+ struct file * : fileinfo_t *, NULL); - bio->bi_status = status; - bio_endio(bio); - return false; -diff --git a/fs/exec.c b/fs/exec.c -index 4340b2803004..acd96c0e0e5f 100644 ---- a/fs/exec.c -+++ b/fs/exec.c -@@ -64,6 +64,7 @@ - #include <linux/compat.h> - #include <linux/vmalloc.h> - #include <linux/io_uring.h> -+#include <linux/sdt.h> - #include <linux/dtrace_os.h> - - #include <linux/uaccess.h> -@@ -1797,6 +1798,7 @@ static int bprm_execve(struct linux_binprm *bprm, - current->in_execve = 1; - - file = do_open_execat(fd, filename, flags); -+ DTRACE_PROC(exec, char *, filename->name); - retval = PTR_ERR(file); - if (IS_ERR(file)) - goto out_unmark; -@@ -1834,6 +1836,8 @@ static int bprm_execve(struct linux_binprm *bprm, - task_numa_free(current, false); - if (displaced) - put_files_struct(displaced); -+ -+ DTRACE_PROC(exec__success); - return retval; - - out: -@@ -1923,6 +1927,8 @@ static int do_execveat_common(int fd, struct filename *filename, - - out_ret: - putname(filename); -+ if (retval < 0) -+ DTRACE_PROC(exec__failure, int, retval); - return retval; - } - -@@ -1976,6 +1982,8 @@ int kernel_execve(const char *kernel_filename, - free_bprm(bprm); - out_ret: - putname(filename); -+ if (retval < 0) -+ DTRACE_PROC(exec__failure, int, retval); - return retval; - } - -diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h -index 98554dd18a71..1e13fb97d642 100644 ---- a/fs/nfs/internal.h -+++ b/fs/nfs/internal.h -@@ -10,6 +10,7 @@ - #include <linux/sunrpc/addr.h> - #include <linux/nfs_page.h> - #include <linux/wait_bit.h> -+#include <linux/sdt.h> - - #define NFS_SB_MASK (SB_RDONLY|SB_NOSUID|SB_NODEV|SB_NOEXEC|SB_SYNCHRONOUS) - -@@ -832,3 +833,15 @@ static inline void nfs_set_port(struct sockaddr *sap, int *port, - - rpc_set_port(sap, *port); - } -+ -+#define DTRACE_IO_NFS(name, rw, size, inode) \ -+ if (DTRACE_IO_ENABLED(name)) { \ -+ struct bio bio __maybe_unused = { \ -+ .bi_opf = rw, \ -+ .bi_iter.bi_size = size, \ -+ .bi_iter.bi_sector = NFS_FILEID(inode), \ -+ }; \ -+ DTRACE_IO(name, struct bio * : (bufinfo_t *, \ -+ devinfo_t *), &bio, \ -+ struct file * : fileinfo_t *, NULL); \ -+} -diff --git a/fs/nfs/read.c b/fs/nfs/read.c -index eb854f1f86e2..7049b4540f94 100644 ---- a/fs/nfs/read.c -+++ b/fs/nfs/read.c -@@ -212,6 +212,8 @@ static void nfs_initiate_read(struct nfs_pgio_header *hdr, - struct inode *inode = hdr->inode; - int swap_flags = IS_SWAPFILE(inode) ? NFS_RPC_SWAPFLAGS : 0; - -+ DTRACE_IO_NFS(start, REQ_OP_READ, hdr->args.count, hdr->inode); -+ - task_setup_data->flags |= swap_flags; - rpc_ops->read_setup(hdr, msg); - trace_nfs_initiate_read(hdr); -@@ -243,6 +245,7 @@ static int nfs_readpage_done(struct rpc_task *task, - struct inode *inode) - { - int status = NFS_PROTO(inode)->read_done(task, hdr); -+ DTRACE_IO_NFS(done, REQ_OP_READ, hdr->res.count, hdr->inode); - if (status != 0) - return status; - -diff --git a/fs/nfs/write.c b/fs/nfs/write.c -index 639c34fec04a..8bd0bd4e5b76 100644 ---- a/fs/nfs/write.c -+++ b/fs/nfs/write.c -@@ -1403,6 +1403,7 @@ static void nfs_initiate_write(struct nfs_pgio_header *hdr, - task_setup_data->priority = priority; - rpc_ops->write_setup(hdr, msg, &task_setup_data->rpc_client); - trace_nfs_initiate_write(hdr); -+ DTRACE_IO_NFS(start, REQ_OP_WRITE, hdr->args.count, hdr->inode); - } - - /* If a nfs_flush_* function fails, it should remove reqs from @head and -@@ -1562,6 +1563,7 @@ static int nfs_writeback_done(struct rpc_task *task, - * depend on tighter cache coherency when writing. - */ - status = NFS_PROTO(inode)->write_done(task, hdr); -+ DTRACE_IO_NFS(done, REQ_OP_WRITE, hdr->res.count, hdr->inode); - if (status != 0) - return status; - -diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c -index 4e4cf91f4f9f..6550a3447816 100644 ---- a/fs/xfs/xfs_buf.c -+++ b/fs/xfs/xfs_buf.c -@@ -52,6 +52,21 @@ static kmem_zone_t *xfs_buf_zone; - * b_lock (trylock due to inversion) - */ - -+#define DTRACE_IO_XFS_WAIT(name, bp, is_write) \ -+ if (DTRACE_IO_ENABLED(name)) { \ -+ struct bio bio __maybe_unused = { \ -+ .bi_iter.bi_sector = (bp)->b_bn, \ -+ .bi_iter.bi_size = (bp)->b_length, \ -+ .bi_opf = is_write ? \ -+ REQ_OP_WRITE : REQ_OP_READ, \ -+ .bi_disk = (bp)->b_target->bt_bdev->bd_disk, \ -+ .bi_partno = (bp)->b_target->bt_bdev->bd_partno,\ -+ }; \ -+ DTRACE_IO(name, struct bio * : (bufinfo_t *, \ -+ devinfo_t *), &bio, \ -+ struct file * : fileinfo_t *, NULL); \ -+ } -+ - static int __xfs_buf_submit(struct xfs_buf *bp, bool wait); - - static inline int -@@ -1633,10 +1648,14 @@ static int - xfs_buf_iowait( - struct xfs_buf *bp) - { -+ int orig_flags __attribute__((unused)) = bp->b_flags; -+ - ASSERT(!(bp->b_flags & XBF_ASYNC)); - - trace_xfs_buf_iowait(bp, _RET_IP_); -+ DTRACE_IO_XFS_WAIT(wait__start, bp, orig_flags & XBF_WRITE); - wait_for_completion(&bp->b_iowait); -+ DTRACE_IO_XFS_WAIT(wait__done, bp, orig_flags & XBF_WRITE); - trace_xfs_buf_iowait_done(bp, _RET_IP_); - - return bp->b_error; -diff --git a/include/linux/rwlock_api_smp.h b/include/linux/rwlock_api_smp.h -index abfb53ab11be..2531929ccb58 100644 ---- a/include/linux/rwlock_api_smp.h -+++ b/include/linux/rwlock_api_smp.h -@@ -5,6 +5,8 @@ - # error "please don't include this file directly" - #endif - -+#include <linux/sdt.h> -+ - /* - * include/linux/rwlock_api_smp.h - * -@@ -119,6 +121,8 @@ static inline int __raw_read_trylock(rwlock_t *lock) - preempt_disable(); - if (do_raw_read_trylock(lock)) { - rwlock_acquire_read(&lock->dep_map, 0, 1, _RET_IP_); -+ DTRACE_LOCKSTAT(rw__acquire, struct rwlock *, lock, int, -+ DTRACE_LOCKSTAT_RW_READER); - return 1; - } - preempt_enable(); -@@ -130,6 +134,8 @@ static inline int __raw_write_trylock(rwlock_t *lock) - preempt_disable(); - if (do_raw_write_trylock(lock)) { - rwlock_acquire(&lock->dep_map, 0, 1, _RET_IP_); -+ DTRACE_LOCKSTAT(rw__acquire, struct rwlock *, lock, int, -+ DTRACE_LOCKSTAT_RW_WRITER); - return 1; - } - preempt_enable(); -@@ -148,6 +154,8 @@ static inline void __raw_read_lock(rwlock_t *lock) - preempt_disable(); - rwlock_acquire_read(&lock->dep_map, 0, 0, _RET_IP_); - LOCK_CONTENDED(lock, do_raw_read_trylock, do_raw_read_lock); -+ DTRACE_LOCKSTAT(rw__acquire, struct rwlock *, lock, int, -+ DTRACE_LOCKSTAT_RW_READER); - } - - static inline unsigned long __raw_read_lock_irqsave(rwlock_t *lock) -@@ -159,6 +167,8 @@ static inline unsigned long __raw_read_lock_irqsave(rwlock_t *lock) - rwlock_acquire_read(&lock->dep_map, 0, 0, _RET_IP_); - LOCK_CONTENDED_FLAGS(lock, do_raw_read_trylock, do_raw_read_lock, - do_raw_read_lock_flags, &flags); -+ DTRACE_LOCKSTAT(rw__acquire, struct rwlock *, lock, int, -+ DTRACE_LOCKSTAT_RW_READER); - return flags; - } - -@@ -168,6 +178,8 @@ static inline void __raw_read_lock_irq(rwlock_t *lock) - preempt_disable(); - rwlock_acquire_read(&lock->dep_map, 0, 0, _RET_IP_); - LOCK_CONTENDED(lock, do_raw_read_trylock, do_raw_read_lock); -+ DTRACE_LOCKSTAT(rw__acquire, struct rwlock *, lock, int, -+ DTRACE_LOCKSTAT_RW_READER); - } - - static inline void __raw_read_lock_bh(rwlock_t *lock) -@@ -175,6 +187,8 @@ static inline void __raw_read_lock_bh(rwlock_t *lock) - __local_bh_disable_ip(_RET_IP_, SOFTIRQ_LOCK_OFFSET); - rwlock_acquire_read(&lock->dep_map, 0, 0, _RET_IP_); - LOCK_CONTENDED(lock, do_raw_read_trylock, do_raw_read_lock); -+ DTRACE_LOCKSTAT(rw__acquire, struct rwlock *, lock, int, -+ DTRACE_LOCKSTAT_RW_READER); - } - - static inline unsigned long __raw_write_lock_irqsave(rwlock_t *lock) -@@ -186,6 +200,8 @@ static inline unsigned long __raw_write_lock_irqsave(rwlock_t *lock) - rwlock_acquire(&lock->dep_map, 0, 0, _RET_IP_); - LOCK_CONTENDED_FLAGS(lock, do_raw_write_trylock, do_raw_write_lock, - do_raw_write_lock_flags, &flags); -+ DTRACE_LOCKSTAT(rw__acquire, struct rwlock *, lock, int, -+ DTRACE_LOCKSTAT_RW_WRITER); - return flags; - } - -@@ -195,6 +211,8 @@ static inline void __raw_write_lock_irq(rwlock_t *lock) - preempt_disable(); - rwlock_acquire(&lock->dep_map, 0, 0, _RET_IP_); - LOCK_CONTENDED(lock, do_raw_write_trylock, do_raw_write_lock); -+ DTRACE_LOCKSTAT(rw__acquire, struct rwlock *, lock, int, -+ DTRACE_LOCKSTAT_RW_WRITER); - } - - static inline void __raw_write_lock_bh(rwlock_t *lock) -@@ -202,6 +220,8 @@ static inline void __raw_write_lock_bh(rwlock_t *lock) - __local_bh_disable_ip(_RET_IP_, SOFTIRQ_LOCK_OFFSET); - rwlock_acquire(&lock->dep_map, 0, 0, _RET_IP_); - LOCK_CONTENDED(lock, do_raw_write_trylock, do_raw_write_lock); -+ DTRACE_LOCKSTAT(rw__acquire, struct rwlock *, lock, int, -+ DTRACE_LOCKSTAT_RW_WRITER); - } - - static inline void __raw_write_lock(rwlock_t *lock) -@@ -209,6 +229,8 @@ static inline void __raw_write_lock(rwlock_t *lock) - preempt_disable(); - rwlock_acquire(&lock->dep_map, 0, 0, _RET_IP_); - LOCK_CONTENDED(lock, do_raw_write_trylock, do_raw_write_lock); -+ DTRACE_LOCKSTAT(rw__acquire, struct rwlock *, lock, int, -+ DTRACE_LOCKSTAT_RW_WRITER); - } - - #endif /* !CONFIG_GENERIC_LOCKBREAK || CONFIG_DEBUG_LOCK_ALLOC */ -@@ -217,6 +239,8 @@ static inline void __raw_write_unlock(rwlock_t *lock) - { - rwlock_release(&lock->dep_map, _RET_IP_); - do_raw_write_unlock(lock); -+ DTRACE_LOCKSTAT(rw__release, struct rwlock *, lock, int, -+ DTRACE_LOCKSTAT_RW_WRITER); - preempt_enable(); - } - -@@ -224,6 +248,8 @@ static inline void __raw_read_unlock(rwlock_t *lock) - { - rwlock_release(&lock->dep_map, _RET_IP_); - do_raw_read_unlock(lock); -+ DTRACE_LOCKSTAT(rw__release, struct rwlock *, lock, int, -+ DTRACE_LOCKSTAT_RW_READER); - preempt_enable(); - } - -@@ -232,6 +258,8 @@ __raw_read_unlock_irqrestore(rwlock_t *lock, unsigned long flags) - { - rwlock_release(&lock->dep_map, _RET_IP_); - do_raw_read_unlock(lock); -+ DTRACE_LOCKSTAT(rw__release, struct rwlock *, lock, int, -+ DTRACE_LOCKSTAT_RW_READER); - local_irq_restore(flags); - preempt_enable(); - } -@@ -240,6 +268,8 @@ static inline void __raw_read_unlock_irq(rwlock_t *lock) - { - rwlock_release(&lock->dep_map, _RET_IP_); - do_raw_read_unlock(lock); -+ DTRACE_LOCKSTAT(rw__release, struct rwlock *, lock, int, -+ DTRACE_LOCKSTAT_RW_READER); - local_irq_enable(); - preempt_enable(); - } -@@ -248,6 +278,8 @@ static inline void __raw_read_unlock_bh(rwlock_t *lock) - { - rwlock_release(&lock->dep_map, _RET_IP_); - do_raw_read_unlock(lock); -+ DTRACE_LOCKSTAT(rw__release, struct rwlock *, lock, int, -+ DTRACE_LOCKSTAT_RW_READER); - __local_bh_enable_ip(_RET_IP_, SOFTIRQ_LOCK_OFFSET); - } - -@@ -256,6 +288,8 @@ static inline void __raw_write_unlock_irqrestore(rwlock_t *lock, - { - rwlock_release(&lock->dep_map, _RET_IP_); - do_raw_write_unlock(lock); -+ DTRACE_LOCKSTAT(rw__release, struct rwlock *, lock, int, -+ DTRACE_LOCKSTAT_RW_WRITER); - local_irq_restore(flags); - preempt_enable(); - } -@@ -264,6 +298,8 @@ static inline void __raw_write_unlock_irq(rwlock_t *lock) - { - rwlock_release(&lock->dep_map, _RET_IP_); - do_raw_write_unlock(lock); -+ DTRACE_LOCKSTAT(rw__release, struct rwlock *, lock, int, -+ DTRACE_LOCKSTAT_RW_WRITER); - local_irq_enable(); - preempt_enable(); - } -@@ -272,6 +308,8 @@ static inline void __raw_write_unlock_bh(rwlock_t *lock) - { - rwlock_release(&lock->dep_map, _RET_IP_); - do_raw_write_unlock(lock); -+ DTRACE_LOCKSTAT(rw__release, struct rwlock *, lock, int, -+ DTRACE_LOCKSTAT_RW_WRITER); - __local_bh_enable_ip(_RET_IP_, SOFTIRQ_LOCK_OFFSET); - } - -diff --git a/include/linux/spinlock_api_smp.h b/include/linux/spinlock_api_smp.h -index 19a9be9d97ee..e7601d01b87d 100644 ---- a/include/linux/spinlock_api_smp.h -+++ b/include/linux/spinlock_api_smp.h -@@ -5,6 +5,8 @@ - # error "please don't include this file directly" - #endif - -+#include <linux/sdt.h> -+ - /* - * include/linux/spinlock_api_smp.h - * -@@ -88,6 +90,7 @@ static inline int __raw_spin_trylock(raw_spinlock_t *lock) - preempt_disable(); - if (do_raw_spin_trylock(lock)) { - spin_acquire(&lock->dep_map, 0, 1, _RET_IP_); -+ DTRACE_LOCKSTAT(spin__acquire, spinlock_t *, lock); - return 1; - } - preempt_enable(); -@@ -118,6 +121,7 @@ static inline unsigned long __raw_spin_lock_irqsave(raw_spinlock_t *lock) - #else - do_raw_spin_lock_flags(lock, &flags); - #endif -+ DTRACE_LOCKSTAT(spin__acquire, spinlock_t *, lock); - return flags; - } - -@@ -127,6 +131,7 @@ static inline void __raw_spin_lock_irq(raw_spinlock_t *lock) - preempt_disable(); - spin_acquire(&lock->dep_map, 0, 0, _RET_IP_); - LOCK_CONTENDED(lock, do_raw_spin_trylock, do_raw_spin_lock); -+ DTRACE_LOCKSTAT(spin__acquire, spinlock_t *, lock); - } - - static inline void __raw_spin_lock_bh(raw_spinlock_t *lock) -@@ -134,6 +139,7 @@ static inline void __raw_spin_lock_bh(raw_spinlock_t *lock) - __local_bh_disable_ip(_RET_IP_, SOFTIRQ_LOCK_OFFSET); - spin_acquire(&lock->dep_map, 0, 0, _RET_IP_); - LOCK_CONTENDED(lock, do_raw_spin_trylock, do_raw_spin_lock); -+ DTRACE_LOCKSTAT(spin__acquire, spinlock_t *, lock); - } - - static inline void __raw_spin_lock(raw_spinlock_t *lock) -@@ -141,6 +147,7 @@ static inline void __raw_spin_lock(raw_spinlock_t *lock) - preempt_disable(); - spin_acquire(&lock->dep_map, 0, 0, _RET_IP_); - LOCK_CONTENDED(lock, do_raw_spin_trylock, do_raw_spin_lock); -+ DTRACE_LOCKSTAT(spin__acquire, spinlock_t *, lock); - } - - #endif /* !CONFIG_GENERIC_LOCKBREAK || CONFIG_DEBUG_LOCK_ALLOC */ -@@ -149,6 +156,7 @@ static inline void __raw_spin_unlock(raw_spinlock_t *lock) - { - spin_release(&lock->dep_map, _RET_IP_); - do_raw_spin_unlock(lock); -+ DTRACE_LOCKSTAT(spin__release, spinlock_t *, lock); - preempt_enable(); - } - -@@ -157,6 +165,7 @@ static inline void __raw_spin_unlock_irqrestore(raw_spinlock_t *lock, - { - spin_release(&lock->dep_map, _RET_IP_); - do_raw_spin_unlock(lock); -+ DTRACE_LOCKSTAT(spin__release, spinlock_t *, lock); - local_irq_restore(flags); - preempt_enable(); - } -@@ -165,6 +174,7 @@ static inline void __raw_spin_unlock_irq(raw_spinlock_t *lock) - { - spin_release(&lock->dep_map, _RET_IP_); - do_raw_spin_unlock(lock); -+ DTRACE_LOCKSTAT(spin__release, spinlock_t *, lock); - local_irq_enable(); - preempt_enable(); - } -@@ -173,6 +183,7 @@ static inline void __raw_spin_unlock_bh(raw_spinlock_t *lock) - { - spin_release(&lock->dep_map, _RET_IP_); - do_raw_spin_unlock(lock); -+ DTRACE_LOCKSTAT(spin__release, spinlock_t *, lock); - __local_bh_enable_ip(_RET_IP_, SOFTIRQ_LOCK_OFFSET); - } - -@@ -181,6 +192,7 @@ static inline int __raw_spin_trylock_bh(raw_spinlock_t *lock) - __local_bh_disable_ip(_RET_IP_, SOFTIRQ_LOCK_OFFSET); - if (do_raw_spin_trylock(lock)) { - spin_acquire(&lock->dep_map, 0, 1, _RET_IP_); -+ DTRACE_LOCKSTAT(spin__acquire, spinlock_t *, lock); - return 1; - } - __local_bh_enable_ip(_RET_IP_, SOFTIRQ_LOCK_OFFSET); -diff --git a/kernel/exit.c b/kernel/exit.c -index da498c5f029c..285b0c0ff00d 100644 ---- a/kernel/exit.c -+++ b/kernel/exit.c -@@ -64,6 +64,7 @@ - #include <linux/rcuwait.h> - #include <linux/compat.h> - #include <linux/io_uring.h> -+#include <linux/sdt.h> - #include <linux/dtrace_os.h> - - #include <linux/uaccess.h> -@@ -796,6 +797,10 @@ void __noreturn do_exit(long code) - tsk->exit_code = code; - taskstats_exit(tsk, group_dead); - -+ DTRACE_PROC(lwp__exit); -+ if (group_dead) -+ DTRACE_PROC(exit, int, code & 0x80 ? 3 : code & 0x7f ? 2 : 1); -+ - /* Remove DTrace state for this task */ - dtrace_task_free(tsk); - -diff --git a/kernel/fork.c b/kernel/fork.c -index 0d8a2b12fd90..0729e80e4ad8 100644 ---- a/kernel/fork.c -+++ b/kernel/fork.c -@@ -96,6 +96,7 @@ - #include <linux/kasan.h> - #include <linux/scs.h> - #include <linux/io_uring.h> -+#include <linux/sdt.h> - #include <linux/dtrace_task_impl.h> - - #include <asm/pgalloc.h> -@@ -2513,6 +2514,8 @@ pid_t kernel_clone(struct kernel_clone_args *args) - } - - put_pid(pid); -+ DTRACE_PROC(lwp__create, struct task_struct * : (lwpsinfo_t *, psinfo_t *), p); -+ DTRACE_PROC(create, struct task_struct * : psinfo_t *, p); - return nr; - } - -diff --git a/kernel/locking/mutex.c b/kernel/locking/mutex.c -index 5352ce50a97e..e784dd89d924 100644 ---- a/kernel/locking/mutex.c -+++ b/kernel/locking/mutex.c -@@ -29,6 +29,7 @@ - #include <linux/interrupt.h> - #include <linux/debug_locks.h> - #include <linux/osq_lock.h> -+#include <linux/sdt.h> - - #ifdef CONFIG_DEBUG_MUTEXES - # include "mutex-debug.h" -@@ -282,6 +283,7 @@ void __sched mutex_lock(struct mutex *lock) - - if (!__mutex_trylock_fast(lock)) - __mutex_lock_slowpath(lock); -+ DTRACE_LOCKSTAT(adaptive__acquire, struct mutex *, lock); - } - EXPORT_SYMBOL(mutex_lock); - #endif -@@ -734,10 +736,14 @@ static noinline void __sched __mutex_unlock_slowpath(struct mutex *lock, unsigne - void __sched mutex_unlock(struct mutex *lock) - { - #ifndef CONFIG_DEBUG_LOCK_ALLOC -- if (__mutex_unlock_fast(lock)) -+ if (__mutex_unlock_fast(lock)) { -+ DTRACE_LOCKSTAT(adaptive__release, struct mutex *, lock); - return; -+ } - #endif -+ - __mutex_unlock_slowpath(lock, _RET_IP_); -+ DTRACE_LOCKSTAT(adaptive__release, struct mutex *, lock); - } - EXPORT_SYMBOL(mutex_unlock); - -@@ -927,6 +933,8 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass, - struct lockdep_map *nest_lock, unsigned long ip, - struct ww_acquire_ctx *ww_ctx, const bool use_ww_ctx) - { -+ u64 spinstart = 0, spinend, spintotal = 0; -+ u64 waitstart, waitend, waittotal = 0; - struct mutex_waiter waiter; - bool first = false; - struct ww_mutex *ww; -@@ -958,9 +966,11 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass, - if (__mutex_trylock(lock) || - mutex_optimistic_spin(lock, ww_ctx, use_ww_ctx, NULL)) { - /* got the lock, yay! */ -+ - lock_acquired(&lock->dep_map, ip); - if (use_ww_ctx && ww_ctx) - ww_mutex_set_context_fastpath(ww, ww_ctx); -+ DTRACE_LOCKSTAT(adaptive__acquire, struct mutex *, lock); - preempt_enable(); - return 0; - } -@@ -1003,6 +1013,9 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass, - waiter.task = current; - - set_current_state(state); -+ if (DTRACE_LOCKSTAT_ENABLED(adaptive__spin)) -+ spinstart = dtrace_gethrtime_ns(); -+ - for (;;) { - /* - * Once we hold wait_lock, we're serialized against -@@ -1030,7 +1043,15 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass, - } - - spin_unlock(&lock->wait_lock); -- schedule_preempt_disabled(); -+ -+ if (DTRACE_LOCKSTAT_ENABLED(adaptive__block)) { -+ waitstart = dtrace_gethrtime_ns(); -+ schedule_preempt_disabled(); -+ waitend = dtrace_gethrtime_ns(); -+ if (waitend > waitstart) -+ waittotal += waitend - waitstart; -+ } else -+ schedule_preempt_disabled(); - - /* - * ww_mutex needs to always recheck its position since its waiter -@@ -1082,6 +1103,19 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass, - ww_mutex_lock_acquired(ww, ww_ctx); - - spin_unlock(&lock->wait_lock); -+ -+ if (DTRACE_LOCKSTAT_ENABLED(adaptive__spin) && spinstart) { -+ spinend = dtrace_gethrtime_ns(); -+ spintotal = (spinend > spinstart) ? (spinend - spinstart) : 0; -+ spintotal = (spintotal > waittotal) ? -+ (spintotal - waittotal) : 0; -+ DTRACE_LOCKSTAT(adaptive__spin, struct mutex *, lock, -+ uint64_t, spintotal); -+ } -+ if (DTRACE_LOCKSTAT_ENABLED(adaptive__block) && waittotal) -+ DTRACE_LOCKSTAT(adaptive__block, struct mutex *, lock, -+ uint64_t, waittotal); -+ DTRACE_LOCKSTAT(adaptive__acquire, struct mutex *, lock); - preempt_enable(); - return 0; - -@@ -1092,6 +1126,8 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass, - spin_unlock(&lock->wait_lock); - debug_mutex_free_waiter(&waiter); - mutex_release(&lock->dep_map, ip); -+ DTRACE_LOCKSTAT(adaptive__acquire__error, struct mutex *, lock, -+ int, ret); - preempt_enable(); - return ret; - } -@@ -1307,8 +1343,10 @@ int __sched mutex_lock_interruptible(struct mutex *lock) - { - might_sleep(); - -- if (__mutex_trylock_fast(lock)) -+ if (__mutex_trylock_fast(lock)) { -+ DTRACE_LOCKSTAT(adaptive__acquire, struct mutex *, lock); - return 0; -+ } - - return __mutex_lock_interruptible_slowpath(lock); - } -@@ -1331,8 +1369,10 @@ int __sched mutex_lock_killable(struct mutex *lock) - { - might_sleep(); - -- if (__mutex_trylock_fast(lock)) -+ if (__mutex_trylock_fast(lock)) { -+ DTRACE_LOCKSTAT(adaptive__acquire, struct mutex *, lock); - return 0; -+ } - - return __mutex_lock_killable_slowpath(lock); - } -@@ -1416,8 +1456,10 @@ int __sched mutex_trylock(struct mutex *lock) - #endif - - locked = __mutex_trylock(lock); -- if (locked) -+ if (locked) { - mutex_acquire(&lock->dep_map, 0, 1, _RET_IP_); -+ DTRACE_LOCKSTAT(adaptive__acquire, struct mutex *, lock); -+ } - - return locked; - } -diff --git a/kernel/locking/qrwlock.c b/kernel/locking/qrwlock.c -index fe9ca92faa2a..6b1511be7805 100644 ---- a/kernel/locking/qrwlock.c -+++ b/kernel/locking/qrwlock.c -@@ -11,6 +11,7 @@ - #include <linux/cpumask.h> - #include <linux/percpu.h> - #include <linux/hardirq.h> -+#include <linux/sdt.h> - #include <linux/spinlock.h> - #include <asm/qrwlock.h> - -@@ -20,9 +21,13 @@ - */ - void queued_read_lock_slowpath(struct qrwlock *lock) - { -+ u64 spinstart = 0, spinend, spintime; -+ - /* - * Readers come here when they cannot get the lock without waiting - */ -+ if (DTRACE_LOCKSTAT_ENABLED(rw__spin)) -+ spinstart = dtrace_gethrtime_ns(); - if (unlikely(in_interrupt())) { - /* - * Readers in interrupt context will get the lock immediately -@@ -31,7 +36,7 @@ void queued_read_lock_slowpath(struct qrwlock *lock) - * without waiting in the queue. - */ - atomic_cond_read_acquire(&lock->cnts, !(VAL & _QW_LOCKED)); -- return; -+ goto done; - } - atomic_sub(_QR_BIAS, &lock->cnts); - -@@ -52,6 +57,13 @@ void queued_read_lock_slowpath(struct qrwlock *lock) - * Signal the next one in queue to become queue head - */ - arch_spin_unlock(&lock->wait_lock); -+done: -+ if (DTRACE_LOCKSTAT_ENABLED(rw__spin) && spinstart) { -+ spinend = dtrace_gethrtime_ns(); -+ spintime = spinend > spinstart ? spinend - spinstart : 0; -+ DTRACE_LOCKSTAT(rw__spin, rwlock_t *, lock, uint64_t, spintime, -+ int, DTRACE_LOCKSTAT_RW_READER); -+ } - } - EXPORT_SYMBOL(queued_read_lock_slowpath); - -@@ -61,7 +73,11 @@ EXPORT_SYMBOL(queued_read_lock_slowpath); - */ - void queued_write_lock_slowpath(struct qrwlock *lock) - { -+ u64 spinstart = 0, spinend, spintime; -+ - /* Put the writer into the wait queue */ -+ if (DTRACE_LOCKSTAT_ENABLED(rw__spin)) -+ spinstart = dtrace_gethrtime_ns(); - arch_spin_lock(&lock->wait_lock); - - /* Try to acquire the lock directly if no reader is present */ -@@ -79,5 +95,11 @@ void queued_write_lock_slowpath(struct qrwlock *lock) - _QW_LOCKED) != _QW_WAITING); - unlock: - arch_spin_unlock(&lock->wait_lock); -+ if (DTRACE_LOCKSTAT_ENABLED(rw__spin) && spinstart) { -+ spinend = dtrace_gethrtime_ns(); -+ spintime = spinend > spinstart ? spinend - spinstart : 0; -+ DTRACE_LOCKSTAT(rw__spin, rwlock_t *, lock, uint64_t, spintime, -+ int, DTRACE_LOCKSTAT_RW_WRITER); -+ } - } - EXPORT_SYMBOL(queued_write_lock_slowpath); -diff --git a/kernel/locking/qspinlock.c b/kernel/locking/qspinlock.c -index cbff6ba53d56..44853c2b0183 100644 ---- a/kernel/locking/qspinlock.c -+++ b/kernel/locking/qspinlock.c -@@ -20,6 +20,7 @@ - #include <linux/hardirq.h> - #include <linux/mutex.h> - #include <linux/prefetch.h> -+#include <linux/sdt.h> - #include <asm/byteorder.h> - #include <asm/qspinlock.h> - -@@ -315,16 +316,20 @@ static __always_inline u32 __pv_wait_head_or_lock(struct qspinlock *lock, - void queued_spin_lock_slowpath(struct qspinlock *lock, u32 val) - { - struct mcs_spinlock *prev, *next, *node; -+ u64 spinstart = 0, spinend, spintime; - u32 old, tail; - int idx; - - BUILD_BUG_ON(CONFIG_NR_CPUS >= (1U << _Q_TAIL_CPU_BITS)); - -+ if (DTRACE_LOCKSTAT_ENABLED(spin__spin)) -+ spinstart = dtrace_gethrtime_ns(); -+ - if (pv_enabled()) - goto pv_queue; - - if (virt_spin_lock(lock)) -- return; -+ goto out; - - /* - * Wait for in-progress pending->locked hand-overs with a bounded -@@ -388,7 +393,7 @@ void queued_spin_lock_slowpath(struct qspinlock *lock, u32 val) - */ - clear_pending_set_locked(lock); - lockevent_inc(lock_pending); -- return; -+ goto out; - - /* - * End of pending bit optimistic spinning and beginning of MCS -@@ -558,6 +563,17 @@ void queued_spin_lock_slowpath(struct qspinlock *lock, u32 val) - * release the node - */ - __this_cpu_dec(qnodes[0].mcs.count); -+ -+ /* -+ * Fire spin-spin probe to note time waiting for a lock. -+ */ -+out: -+ if (DTRACE_LOCKSTAT_ENABLED(spin__spin)) { -+ spinend = dtrace_gethrtime_ns(); -+ spintime = spinend > spinstart ? spinend - spinstart : 0; -+ DTRACE_LOCKSTAT(spin__spin, spinlock_t *, lock, -+ uint64_t, spintime); -+ } - } - EXPORT_SYMBOL(queued_spin_lock_slowpath); - -diff --git a/kernel/sched/core.c b/kernel/sched/core.c -index db893818f3ea..f035f9859ae7 100644 ---- a/kernel/sched/core.c -+++ b/kernel/sched/core.c -@@ -1561,6 +1561,9 @@ static inline void init_uclamp(void) { } - - static inline void enqueue_task(struct rq *rq, struct task_struct *p, int flags) - { -+ DTRACE_SCHED(enqueue, struct task_struct * : (lwpsinfo_t *, -+ psinfo_t *), p, -+ cpuinfo_t *, rq->dtrace_cpu_info); - if (!(flags & ENQUEUE_NOCLOCK)) - update_rq_clock(rq); - -@@ -1575,6 +1578,10 @@ static inline void enqueue_task(struct rq *rq, struct task_struct *p, int flags) - - static inline void dequeue_task(struct rq *rq, struct task_struct *p, int flags) - { -+ DTRACE_SCHED(dequeue, struct task_struct * : (lwpsinfo_t *, -+ psinfo_t *), p, -+ cpuinfo_t *, rq->dtrace_cpu_info, -+ int, 0); - if (!(flags & DEQUEUE_NOCLOCK)) - update_rq_clock(rq); - -@@ -2864,6 +2871,8 @@ try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags) - goto unlock; - - trace_sched_waking(p); -+ DTRACE_SCHED(wakeup, struct task_struct * : (lwpsinfo_t *, -+ psinfo_t *), p); - - /* We're going to change ->state: */ - success = 1; -@@ -3552,6 +3561,8 @@ prepare_task_switch(struct rq *rq, struct task_struct *prev, - sched_info_switch(rq, prev, next); - perf_event_task_sched_out(prev, next); - rseq_preempt(prev); -+ DTRACE_SCHED(off__cpu, struct task_struct * : (lwpsinfo_t *, -+ psinfo_t *), next); - fire_sched_out_preempt_notifiers(prev, next); - prepare_task(next); - prepare_arch_switch(next); -@@ -3625,6 +3636,7 @@ static struct rq *finish_task_switch(struct task_struct *prev) - finish_arch_post_lock_switch(); - kcov_finish_switch(current); - -+ DTRACE_SCHED(on__cpu); - fire_sched_in_preempt_notifiers(current); - /* - * When switching through a kernel thread, the loop in -@@ -3725,6 +3737,8 @@ asmlinkage __visible void schedule_tail(struct task_struct *prev) - put_user(task_pid_vnr(current), current->set_child_tid); - - calculate_sigpending(); -+ DTRACE_PROC(start); -+ DTRACE_PROC(lwp__start); - } - - /* -@@ -4467,6 +4481,7 @@ static void __sched notrace __schedule(bool preempt) - */ - prev_state = prev->state; - if (!preempt && prev_state) { -+ DTRACE_SCHED(sleep); - if (signal_pending_state(prev_state, prev)) { - prev->state = TASK_RUNNING; - } else { -@@ -4497,7 +4512,8 @@ static void __sched notrace __schedule(bool preempt) - } - } - switch_count = &prev->nvcsw; -- } -+ } else -+ DTRACE_SCHED(preempt); - - next = pick_next_task(rq, prev, &rf); - clear_tsk_need_resched(prev); -@@ -4534,6 +4550,7 @@ static void __sched notrace __schedule(bool preempt) - rq = context_switch(rq, prev, next, &rf); - } else { - rq->clock_update_flags &= ~(RQCF_ACT_SKIP|RQCF_REQ_SKIP); -+ DTRACE_SCHED(remain__cpu); - rq_unlock_irq(rq, &rf); - } - -@@ -4999,6 +5016,9 @@ void set_user_nice(struct task_struct *p, long nice) - old_prio = p->prio; - p->prio = effective_prio(p); - -+ DTRACE_SCHED(change__pri, struct task_struct * : (lwpsinfo_t *, -+ psinfo_t *), p, -+ int, old_prio); - if (queued) - enqueue_task(rq, p, ENQUEUE_RESTORE | ENQUEUE_NOCLOCK); - if (running) -@@ -6110,6 +6130,9 @@ static void do_sched_yield(void) - rq_unlock_irq(rq, &rf); - sched_preempt_enable_no_resched(); - -+ DTRACE_SCHED(surrender, -+ struct task_struct * : (lwpsinfo_t *, psinfo_t *), -+ current); - schedule(); - } - -@@ -6256,8 +6279,12 @@ int __sched yield_to(struct task_struct *p, bool preempt) - out_irq: - local_irq_restore(flags); - -- if (yielded > 0) -+ if (yielded > 0) { -+ DTRACE_SCHED(surrender, -+ struct task_struct * : (lwpsinfo_t *, psinfo_t *), -+ curr); - schedule(); -+ } - - return yielded; - } -diff --git a/kernel/signal.c b/kernel/signal.c -index ef8f2a28d37c..23cefab66287 100644 ---- a/kernel/signal.c -+++ b/kernel/signal.c -@@ -49,6 +49,7 @@ - - #define CREATE_TRACE_POINTS - #include <trace/events/signal.h> -+#include <linux/sdt.h> - - #include <asm/param.h> - #include <linux/uaccess.h> -@@ -1079,8 +1080,12 @@ static int __send_signal(int sig, struct kernel_siginfo *info, struct task_struc - assert_spin_locked(&t->sighand->siglock); - - result = TRACE_SIGNAL_IGNORED; -- if (!prepare_signal(sig, t, force)) -+ if (!prepare_signal(sig, t, force)) { -+ DTRACE_PROC(signal__discard, -+ struct task_struct * : (lwpsinfo_t *, psinfo_t *), t, -+ int, sig); - goto ret; -+ } - - pending = (type != PIDTYPE_PID) ? &t->signal->shared_pending : &t->pending; - /* -@@ -1179,6 +1184,9 @@ static int __send_signal(int sig, struct kernel_siginfo *info, struct task_struc - } - - complete_signal(sig, t, type); -+ DTRACE_PROC(signal__send, -+ struct task_struct * : (lwpsinfo_t *, psinfo_t *), t, -+ int, sig); - ret: - trace_signal_generate(sig, info, t, type != PIDTYPE_PID, result); - return ret; -@@ -1879,6 +1887,9 @@ int send_sigqueue(struct sigqueue *q, struct pid *pid, enum pid_type type) - list_add_tail(&q->list, &pending->list); - sigaddset(&pending->signal, sig); - complete_signal(sig, t, type); -+ DTRACE_PROC(signal__send, -+ struct task_struct * : (lwpsinfo_t *, psinfo_t *), t, -+ int, sig); - result = TRACE_SIGNAL_DELIVERED; - out: - trace_signal_generate(sig, &q->info, t, type != PIDTYPE_PID, result); -@@ -2601,6 +2612,11 @@ bool get_signal(struct ksignal *ksig) - - /* Has this task already been marked for death? */ - if (signal_group_exit(signal)) { -+ DTRACE_PROC(signal__handle, -+ int, signal->group_exit_code -+ ? signal->group_exit_code -+ : signr, -+ siginfo_t *, NULL, void (*)(void), NULL); - ksig->info.si_signo = signr = SIGKILL; - sigdelset(¤t->pending.signal, SIGKILL); - trace_signal_deliver(SIGKILL, SEND_SIG_NOINFO, -@@ -2658,6 +2674,15 @@ bool get_signal(struct ksignal *ksig) - - ka = &sighand->action[signr-1]; - -+ DTRACE_PROC(signal__handle, -+ int, signal->group_exit_code -+ ? signal->group_exit_code -+ : signr, -+ siginfo_t *, ksig->ka.sa.sa_handler != SIG_DFL -+ ? NULL -+ : &ksig->info, -+ void (*)(void), ksig->ka.sa.sa_handler); -+ - /* Trace actually delivered signals. */ - trace_signal_deliver(signr, &ksig->info, ka); - -@@ -3498,8 +3523,10 @@ static int do_sigtimedwait(const sigset_t *which, kernel_siginfo_t *info, - } - spin_unlock_irq(&tsk->sighand->siglock); - -- if (sig) -+ if (sig) { -+ DTRACE_PROC(signal__clear, int, sig); - return sig; -+ } - return ret ? -EINTR : -EAGAIN; - } - -diff --git a/kernel/time/timer.c b/kernel/time/timer.c -index c3ad64fb9d8b..a1b822cbdb80 100644 ---- a/kernel/time/timer.c -+++ b/kernel/time/timer.c -@@ -44,6 +44,7 @@ - #include <linux/slab.h> - #include <linux/compat.h> - #include <linux/random.h> -+#include <linux/sdt.h> - - #include <linux/uaccess.h> - #include <asm/unistd.h> -@@ -1702,6 +1703,8 @@ void update_process_times(int user_tick) - struct task_struct *p = current; - - PRANDOM_ADD_NOISE(jiffies, user_tick, p, 0); -+ DTRACE_SCHED(tick, struct task_struct * : (lwpsinfo_t *, psinfo_t *), -+ p); - - /* Note: this timer irq context must be accounted for as well. */ - account_process_tick(p, user_tick); -diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c -index b0c244af1e4d..038868b61cd8 100644 ---- a/net/ipv4/ip_input.c -+++ b/net/ipv4/ip_input.c -@@ -141,6 +141,7 @@ - #include <linux/mroute.h> - #include <linux/netlink.h> - #include <net/dst_metadata.h> -+#include <linux/sdt.h> - - /* - * Process Router Attention IP option (RFC 2113) -@@ -239,16 +240,26 @@ static int ip_local_deliver_finish(struct net *net, struct sock *sk, struct sk_b - */ - int ip_local_deliver(struct sk_buff *skb) - { -+ struct iphdr *iph = ip_hdr(skb); -+ - /* - * Reassemble IP fragments. - */ - struct net *net = dev_net(skb->dev); - -- if (ip_is_fragment(ip_hdr(skb))) { -+ if (ip_is_fragment(iph)) { - if (ip_defrag(net, skb, IP_DEFRAG_LOCAL_DELIVER)) - return 0; - } - -+ DTRACE_IP(receive, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, skb->sk, -+ void_ip_t * : ipinfo_t *, iph, -+ struct net_device * : ifinfo_t *, skb->dev, -+ struct iphdr * : ipv4info_t *, iph, -+ struct ipv6hdr * : ipv6info_t *, NULL); -+ - return NF_HOOK(NFPROTO_IPV4, NF_INET_LOCAL_IN, - net, NULL, skb, skb->dev, NULL, - ip_local_deliver_finish); -@@ -257,7 +268,8 @@ int ip_local_deliver(struct sk_buff *skb) - static inline bool ip_rcv_options(struct sk_buff *skb, struct net_device *dev) - { - struct ip_options *opt; -- const struct iphdr *iph; -+ const struct iphdr *iph = NULL; -+ const char *dropreason; - - /* It looks as overkill, because not all - IP options require packet mangling. -@@ -267,6 +279,7 @@ static inline bool ip_rcv_options(struct sk_buff *skb, struct net_device *dev) - --ANK (980813) - */ - if (skb_cow(skb, skb_headroom(skb))) { -+ dropreason = "copy-on-write failed"; - __IP_INC_STATS(dev_net(dev), IPSTATS_MIB_INDISCARDS); - goto drop; - } -@@ -276,6 +289,7 @@ static inline bool ip_rcv_options(struct sk_buff *skb, struct net_device *dev) - opt->optlen = iph->ihl*4 - sizeof(struct iphdr); - - if (ip_options_compile(dev_net(dev), opt, skb)) { -+ dropreason = "invalid options"; - __IP_INC_STATS(dev_net(dev), IPSTATS_MIB_INHDRERRORS); - goto drop; - } -@@ -289,16 +303,28 @@ static inline bool ip_rcv_options(struct sk_buff *skb, struct net_device *dev) - net_info_ratelimited("source route option %pI4 -> %pI4\n", - &iph->saddr, - &iph->daddr); -+ dropreason = "invalid source route options"; - goto drop; - } - } - -- if (ip_options_rcv_srr(skb, dev)) -+ if (ip_options_rcv_srr(skb, dev)) { -+ dropreason = "invalid options"; - goto drop; -+ } - } - - return false; - drop: -+ DTRACE_IP(drop__in, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, skb->sk, -+ void_ip_t * : ipinfo_t *, iph, -+ struct net_device * : ifinfo_t *, skb->dev, -+ struct iphdr * : ipv4info_t *, iph, -+ struct ipv6hdr * : ipv6info_t *, NULL, -+ const char * : string, dropreason); -+ - return true; - } - -@@ -432,27 +458,35 @@ static int ip_rcv_finish(struct net *net, struct sock *sk, struct sk_buff *skb) - /* - * Main IP Receive routine. - */ --static struct sk_buff *ip_rcv_core(struct sk_buff *skb, struct net *net) -+static struct sk_buff *ip_rcv_core(struct sk_buff *skb, struct net *net, -+ struct net_device *dev -+ __attribute__((__unused__))) - { -- const struct iphdr *iph; -+ const struct iphdr *iph = NULL; - u32 len; -+ const char *dropreason = "header invalid"; - - /* When the interface is in promisc. mode, drop all the crap - * that it receives, do not try to analyse it. - */ -- if (skb->pkt_type == PACKET_OTHERHOST) -+ if (skb->pkt_type == PACKET_OTHERHOST) { -+ dropreason = "for other host"; - goto drop; -+ } - - __IP_UPD_PO_STATS(net, IPSTATS_MIB_IN, skb->len); - - skb = skb_share_check(skb, GFP_ATOMIC); - if (!skb) { -+ dropreason = "could not clone shared buffer"; - __IP_INC_STATS(net, IPSTATS_MIB_INDISCARDS); -- goto out; -+ goto drop; - } - -- if (!pskb_may_pull(skb, sizeof(struct iphdr))) -+ if (!pskb_may_pull(skb, sizeof(struct iphdr))) { -+ dropreason = "could not pull skb"; - goto inhdr_error; -+ } - - iph = ip_hdr(skb); - -@@ -487,6 +521,7 @@ static struct sk_buff *ip_rcv_core(struct sk_buff *skb, struct net *net) - - len = ntohs(iph->tot_len); - if (skb->len < len) { -+ dropreason = "packet too short"; - __IP_INC_STATS(net, IPSTATS_MIB_INTRUNCATEDPKTS); - goto drop; - } else if (len < (iph->ihl*4)) -@@ -497,6 +532,7 @@ static struct sk_buff *ip_rcv_core(struct sk_buff *skb, struct net *net) - * Note this now means skb->len holds ntohs(iph->tot_len). - */ - if (pskb_trim_rcsum(skb, len)) { -+ dropreason = "could not trim buffer"; - __IP_INC_STATS(net, IPSTATS_MIB_INDISCARDS); - goto drop; - } -@@ -516,11 +552,19 @@ static struct sk_buff *ip_rcv_core(struct sk_buff *skb, struct net *net) - - csum_error: - __IP_INC_STATS(net, IPSTATS_MIB_CSUMERRORS); -+ dropreason = "checksum error"; - inhdr_error: - __IP_INC_STATS(net, IPSTATS_MIB_INHDRERRORS); - drop: -+ DTRACE_IP(drop__in, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, skb ? skb->sk : NULL, -+ void_ip_t * : ipinfo_t *, iph, -+ struct net_device * : ifinfo_t *, dev, -+ struct iphdr * : ipv4info_t *, iph, -+ void * : ipv6info_t *, NULL, -+ const char * : string, dropreason); - kfree_skb(skb); --out: - return NULL; - } - -@@ -532,7 +576,7 @@ int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, - { - struct net *net = dev_net(dev); - -- skb = ip_rcv_core(skb, net); -+ skb = ip_rcv_core(skb, net, dev); - if (skb == NULL) - return NET_RX_DROP; - -@@ -623,7 +667,7 @@ void ip_list_rcv(struct list_head *head, struct packet_type *pt, - struct net *net = dev_net(dev); - - skb_list_del_init(skb); -- skb = ip_rcv_core(skb, net); -+ skb = ip_rcv_core(skb, net, dev); - if (skb == NULL) - continue; - -diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c -index 97975bed491a..9e194f4e2050 100644 ---- a/net/ipv4/ip_output.c -+++ b/net/ipv4/ip_output.c -@@ -82,6 +82,7 @@ - #include <linux/netfilter_bridge.h> - #include <linux/netlink.h> - #include <linux/tcp.h> -+#include <linux/sdt.h> - - static int - ip_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, -@@ -112,6 +113,14 @@ int __ip_local_out(struct net *net, struct sock *sk, struct sk_buff *skb) - - skb->protocol = htons(ETH_P_IP); - -+ DTRACE_IP(send, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, sk, -+ void_ip_t * : ipinfo_t *, iph, -+ struct net_device * : ifinfo_t *, skb->dev, -+ struct iphdr * : ipv4info_t *, iph, -+ struct ipv6hdr * : ipv6info_t *, NULL); -+ - return nf_hook(NFPROTO_IPV4, NF_INET_LOCAL_OUT, - net, sk, skb, NULL, skb_dst(skb)->dev, - dst_output); -@@ -983,6 +992,7 @@ static int __ip_append_data(struct sock *sk, - unsigned int wmem_alloc_delta = 0; - bool paged, extra_uref = false; - u32 tskey = 0; -+ const char *dropreason; - - skb = skb_peek_tail(queue); - -@@ -1001,9 +1011,13 @@ static int __ip_append_data(struct sock *sk, - maxnonfragsize = ip_sk_ignore_df(sk) ? IP_MAX_MTU : mtu; - - if (cork->length + length > maxnonfragsize - fragheaderlen) { -+ struct iphdr *iph __attribute__((unused)) = ip_hdr(skb); -+ - ip_local_error(sk, EMSGSIZE, fl4->daddr, inet->inet_dport, - mtu - (opt ? opt->optlen : 0)); -- return -EMSGSIZE; -+ dropreason = "packet too big"; -+ err = -EMSGSIZE; -+ goto error2; - } - - /* -@@ -1103,8 +1117,10 @@ static int __ip_append_data(struct sock *sk, - 2 * sk->sk_sndbuf) - skb = alloc_skb(alloclen + hh_len + 15, - sk->sk_allocation); -- if (unlikely(!skb)) -+ if (unlikely(!skb)) { -+ dropreason = "no buffers"; - err = -ENOBUFS; -+ } - } - if (!skb) - goto error; -@@ -1138,7 +1154,9 @@ static int __ip_append_data(struct sock *sk, - copy = datalen - transhdrlen - fraggap - pagedlen; - if (copy > 0 && getfrag(from, data + transhdrlen, offset, copy, fraggap, skb) < 0) { - err = -EFAULT; -+ dropreason = "could not fragment packet"; - kfree_skb(skb); -+ skb = NULL; - goto error; - } - -@@ -1181,6 +1199,7 @@ static int __ip_append_data(struct sock *sk, - if (getfrag(from, skb_put(skb, copy), - offset, copy, off, skb) < 0) { - __skb_trim(skb, off); -+ dropreason = "could not fragment packet"; - err = -EFAULT; - goto error; - } -@@ -1188,14 +1207,18 @@ static int __ip_append_data(struct sock *sk, - int i = skb_shinfo(skb)->nr_frags; - - err = -ENOMEM; -- if (!sk_page_frag_refill(sk, pfrag)) -+ if (!sk_page_frag_refill(sk, pfrag)) { -+ dropreason = "no memory"; - goto error; -+ } - - if (!skb_can_coalesce(skb, i, pfrag->page, - pfrag->offset)) { - err = -EMSGSIZE; -- if (i == MAX_SKB_FRAGS) -+ if (i == MAX_SKB_FRAGS) { -+ dropreason = "too many fragments"; - goto error; -+ } - - __skb_fill_page_desc(skb, i, pfrag->page, - pfrag->offset, 0); -@@ -1205,8 +1228,10 @@ static int __ip_append_data(struct sock *sk, - copy = min_t(int, copy, pfrag->size - pfrag->offset); - if (getfrag(from, - page_address(pfrag->page) + pfrag->offset, -- offset, copy, skb->len, skb) < 0) -+ offset, copy, skb->len, skb) < 0) { -+ dropreason = "could not framgent packet"; - goto error_efault; -+ } - - pfrag->offset += copy; - skb_frag_size_add(&skb_shinfo(skb)->frags[i - 1], copy); -@@ -1235,6 +1260,16 @@ static int __ip_append_data(struct sock *sk, - cork->length -= length; - IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTDISCARDS); - refcount_add(wmem_alloc_delta, &sk->sk_wmem_alloc); -+error2: -+ DTRACE_IP(drop__out, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, skb ? skb->sk : NULL, -+ void_ip_t * : ipinfo_t *, skb ? ip_hdr(skb) : NULL, -+ struct net_device * : ifinfo_t *, skb ? skb->dev : NULL, -+ struct iphdr * : ipv4info_t *, skb ? ip_hdr(skb) : NULL, -+ struct ipv6hdr * : ipv6info_t *, NULL, -+ const char * : string, dropreason); -+ - return err; - } - -@@ -1338,6 +1373,8 @@ ssize_t ip_append_page(struct sock *sk, struct flowi4 *fl4, struct page *page, - int len; - int err; - unsigned int maxfraglen, fragheaderlen, fraggap, maxnonfragsize; -+ struct iphdr *iph; -+ const char *dropreason; - - if (inet->hdrincl) - return -EPERM; -@@ -1391,6 +1428,7 @@ ssize_t ip_append_page(struct sock *sk, struct flowi4 *fl4, struct page *page, - alloclen = fragheaderlen + hh_len + fraggap + 15; - skb = sock_wmalloc(sk, alloclen, 1, sk->sk_allocation); - if (unlikely(!skb)) { -+ dropreason = "no buffers"; - err = -ENOBUFS; - goto error; - } -@@ -1430,6 +1468,7 @@ ssize_t ip_append_page(struct sock *sk, struct flowi4 *fl4, struct page *page, - len = size; - - if (skb_append_pagefrags(skb, page, offset, len)) { -+ dropreason = "packet too big"; - err = -EMSGSIZE; - goto error; - } -@@ -1452,6 +1491,16 @@ ssize_t ip_append_page(struct sock *sk, struct flowi4 *fl4, struct page *page, - error: - cork->length -= size; - IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTDISCARDS); -+ iph = skb ? ip_hdr(skb) : NULL; -+ DTRACE_IP(drop__out, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, skb ? skb->sk : NULL, -+ void_ip_t * : ipinfo_t *, iph, -+ struct net_device * : ifinfo_t *, skb ? skb->dev : NULL, -+ struct iphdr * : ipv4info_t *, iph, -+ struct ipv6hdr * : ipv6info_t *, NULL, -+ const char * : string, dropreason); -+ - return err; - } - -@@ -1569,8 +1618,18 @@ int ip_send_skb(struct net *net, struct sk_buff *skb) - if (err) { - if (err > 0) - err = net_xmit_errno(err); -- if (err) -+ if (err) { - IP_INC_STATS(net, IPSTATS_MIB_OUTDISCARDS); -+ /* skb may have been freed */ -+ DTRACE_IP(drop__out, -+ struct sk_buff * : pktinfo_t *, NULL, -+ struct sock * : csinfo_t *, NULL, -+ void_ip_t * : ipinfo_t *, NULL, -+ struct net_device * : ifinfo_t *, NULL, -+ struct iphdr * : ipv4info_t *, NULL, -+ struct ipv6hdr * : ipv6info_t *, NULL, -+ char * : string, "packet too short"); -+ } - } - - return err; -diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c -index 7d26e0f8bdae..7ae1ad2bad09 100644 ---- a/net/ipv4/raw.c -+++ b/net/ipv4/raw.c -@@ -75,6 +75,7 @@ - #include <linux/netfilter_ipv4.h> - #include <linux/compat.h> - #include <linux/uio.h> -+#include <linux/sdt.h> - - struct raw_frag_vec { - struct msghdr *msg; -@@ -349,19 +350,25 @@ static int raw_send_hdrinc(struct sock *sk, struct flowi4 *fl4, - struct inet_sock *inet = inet_sk(sk); - struct net *net = sock_net(sk); - struct iphdr *iph; -- struct sk_buff *skb; -+ struct sk_buff *skb = NULL; - unsigned int iphlen; - int err; - struct rtable *rt = *rtp; - int hlen, tlen; -+ const char *dropreason; - - if (length > rt->dst.dev->mtu) { - ip_local_error(sk, EMSGSIZE, fl4->daddr, inet->inet_dport, - rt->dst.dev->mtu); -- return -EMSGSIZE; -+ dropreason = "packet too big"; -+ err = -EMSGSIZE; -+ goto trace_drop; -+ } -+ if (length < sizeof(struct iphdr)) { -+ dropreason = "packet too short"; -+ err = -EINVAL; -+ goto trace_drop; - } -- if (length < sizeof(struct iphdr)) -- return -EINVAL; - - if (flags&MSG_PROBE) - goto out; -@@ -371,8 +378,10 @@ static int raw_send_hdrinc(struct sock *sk, struct flowi4 *fl4, - skb = sock_alloc_send_skb(sk, - length + hlen + tlen + 15, - flags & MSG_DONTWAIT, &err); -- if (!skb) -+ if (!skb) { -+ dropreason = "out of memory"; - goto error; -+ } - skb_reserve(skb, hlen); - - skb->priority = sk->sk_priority; -@@ -394,8 +403,10 @@ static int raw_send_hdrinc(struct sock *sk, struct flowi4 *fl4, - - skb->transport_header = skb->network_header; - err = -EFAULT; -- if (memcpy_from_msg(iph, msg, length)) -+ if (memcpy_from_msg(iph, msg, length)) { -+ dropreason = "could not copy msg"; - goto error_free; -+ } - - iphlen = iph->ihl * 4; - -@@ -407,8 +418,10 @@ static int raw_send_hdrinc(struct sock *sk, struct flowi4 *fl4, - * in, reject the frame as invalid - */ - err = -EINVAL; -- if (iphlen > length) -+ if (iphlen > length) { -+ dropreason = "IP header too big"; - goto error_free; -+ } - - if (iphlen >= sizeof(*iph)) { - if (!iph->saddr) -@@ -426,20 +439,40 @@ static int raw_send_hdrinc(struct sock *sk, struct flowi4 *fl4, - skb_transport_header(skb))->type); - } - -+ DTRACE_IP(send, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, sk, -+ void_ip_t * : ipinfo_t *, iph, -+ struct net_device * : ifinfo_t *, skb->dev, -+ struct iphdr * : ipv4info_t *, iph, -+ struct ipv6hdr * : ipv6info_t *, NULL); -+ - err = NF_HOOK(NFPROTO_IPV4, NF_INET_LOCAL_OUT, - net, sk, skb, NULL, rt->dst.dev, - dst_output); - if (err > 0) - err = net_xmit_errno(err); -- if (err) -+ if (err) { -+ dropreason = "device dropping packets of this priority"; - goto error; -+ } - out: - return 0; - - error_free: - kfree_skb(skb); -+ skb = NULL; - error: - IP_INC_STATS(net, IPSTATS_MIB_OUTDISCARDS); -+trace_drop: -+ DTRACE_IP(drop__out, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, skb ? skb->sk : NULL, -+ void_ip_t * : ipinfo_t *, skb ? ip_hdr(skb) : NULL, -+ struct net_device * : ifinfo_t *, skb ? skb->dev : NULL, -+ struct iphdr * : ipv4info_t *, skb ? ip_hdr(skb) : NULL, -+ struct ipv6hdr * : ipv6info_t *, NULL, -+ const char * : string, dropreason); - if (err == -ENOBUFS && !inet->recverr) - err = 0; - return err; -diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c -index 41d03683b13d..197946038626 100644 ---- a/net/ipv4/tcp.c -+++ b/net/ipv4/tcp.c -@@ -267,6 +267,7 @@ - #include <linux/slab.h> - #include <linux/errqueue.h> - #include <linux/static_key.h> -+#include <linux/sdt.h> - - #include <net/icmp.h> - #include <net/inet_common.h> -@@ -2277,6 +2278,19 @@ int tcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int nonblock, - } - EXPORT_SYMBOL(tcp_recvmsg); - -+/* We wish to avoid instrumenting TCP state transitions to SYN_SENT as we trace -+ * those state changes later once the destination address is committed to the -+ * sk. We also need to deal with the fact that separate timewait sockets are -+ * used to handle the TIME_WAIT state. We do not want to trace direct -+ * transitions from CLOSING/FIN_WAIT2 -> CLOSE since they do not represent -+ * connection close, rather a transition to using the timewait socket. -+ * Accordingly skip instrumentation of transitions from CLOSING/FIN_WAIT2 to -+ * CLOSE. -+ */ -+#define REAL_STATE_CHANGE(old, new) \ -+ (old != new && new != TCP_SYN_SENT && \ -+ ((old != TCP_CLOSING && old != TCP_FIN_WAIT2) || new != TCP_CLOSE)) -+ - void tcp_set_state(struct sock *sk, int state) - { - int oldstate = sk->sk_state; -@@ -2329,6 +2343,18 @@ void tcp_set_state(struct sock *sk, int state) - * socket sitting in hash tables. - */ - inet_sk_state_store(sk, state); -+ -+ if (DTRACE_TCP_ENABLED(state__change) && -+ REAL_STATE_CHANGE(oldstate, state)) -+ DTRACE_TCP_NOCHECK(state__change, -+ struct sk_buff * : pktinfo_t *, NULL, -+ struct sock * : csinfo_t *, sk, -+ __dtrace_tcp_void_ip_t * : ipinfo_t *, NULL, -+ struct tcp_sock * : tcpsinfo_t *, tcp_sk(sk), -+ struct tcphdr * : tcpinfo_t *, NULL, -+ int : tcplsinfo_t *, oldstate, -+ int : int, state, -+ int : int, DTRACE_NET_PROBE_OUTBOUND); - } - EXPORT_SYMBOL_GPL(tcp_set_state); - -diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c -index 6bf066f924c1..e29846f27328 100644 ---- a/net/ipv4/tcp_input.c -+++ b/net/ipv4/tcp_input.c -@@ -80,6 +80,7 @@ - #include <linux/jump_label_ratelimit.h> - #include <net/busy_poll.h> - #include <net/mptcp.h> -+#include <linux/sdt.h> - - int sysctl_tcp_max_orphans __read_mostly = NR_FILE; - -@@ -5914,6 +5915,14 @@ void tcp_finish_connect(struct sock *sk, struct sk_buff *skb) - struct tcp_sock *tp = tcp_sk(sk); - struct inet_connection_sock *icsk = inet_csk(sk); - -+ DTRACE_TCP(connect__established, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, sk, -+ __dtrace_tcp_void_ip_t * : ipinfo_t *, ip_hdr(skb), -+ struct tcp_sock * : tcpsinfo_t *, tp, -+ struct tcphdr * : tcpinfo_t *, tcp_hdr(skb), -+ int : tcplsinfo_t *, TCP_ESTABLISHED, -+ int, TCP_ESTABLISHED, int, DTRACE_NET_PROBE_INBOUND); - tcp_set_state(sk, TCP_ESTABLISHED); - icsk->icsk_ack.lrcvtime = tcp_jiffies32; - -@@ -6078,6 +6087,17 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, - */ - - if (th->rst) { -+ DTRACE_TCP(connect__refused, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, sk, -+ __dtrace_tcp_void_ip_t * : ipinfo_t *, -+ ip_hdr(skb), -+ struct tcp_sock * : tcpsinfo_t *, tp, -+ struct tcphdr * : tcpinfo_t *, th, -+ int : tcplsinfo_t *, -+ sk ? sk->sk_state : TCP_CLOSE, -+ int, sk ? sk->sk_state : TCP_CLOSE, -+ int, DTRACE_NET_PROBE_INBOUND); - tcp_reset(sk); - goto discard; - } -@@ -6400,6 +6420,16 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb) - WRITE_ONCE(tp->copied_seq, tp->rcv_nxt); - } - smp_mb(); -+ -+ DTRACE_TCP(accept__established, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, sk, -+ __dtrace_tcp_void_ip_t * : ipinfo_t *, ip_hdr(skb), -+ struct tcp_sock * : tcpsinfo_t *, tp, -+ struct tcphdr * : tcpinfo_t *, tcp_hdr(skb), -+ int : tcplsinfo_t *, TCP_ESTABLISHED, -+ int, TCP_ESTABLISHED, -+ int, DTRACE_NET_PROBE_INBOUND); - tcp_set_state(sk, TCP_ESTABLISHED); - sk->sk_state_change(sk); - -@@ -6873,6 +6903,19 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops, - !want_cookie ? TCP_SYNACK_NORMAL : - TCP_SYNACK_COOKIE, - skb); -+ /* Do not pass in tcp sock as ports/addresses are not yet -+ * populated - instead translators will fill them in from -+ * skb data. -+ */ -+ DTRACE_TCP(state__change, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, sk, -+ __dtrace_tcp_void_ip_t * : ipinfo_t *, ip_hdr(skb), -+ struct tcp_sock * : tcpsinfo_t *, NULL, -+ struct tcphdr * : tcpinfo_t *, tcp_hdr(skb), -+ int : tcplsinfo_t *, TCP_LISTEN, -+ int, TCP_SYN_RECV, int, DTRACE_NET_PROBE_INBOUND); -+ - if (want_cookie) { - reqsk_free(req); - return 0; -diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c -index ab8ed0fc4769..5f76469093a2 100644 ---- a/net/ipv4/tcp_ipv4.c -+++ b/net/ipv4/tcp_ipv4.c -@@ -80,6 +80,7 @@ - - #include <crypto/hash.h> - #include <linux/scatterlist.h> -+#include <linux/sdt.h> - - #include <trace/events/tcp.h> - -@@ -642,6 +643,21 @@ void tcp_v4_send_check(struct sock *sk, struct sk_buff *skb) - } - EXPORT_SYMBOL(tcp_v4_send_check); - -+/* Since we want to trace send events in TCP prior to pushing the segment to -+ * IP - where the IP header is added - we need to construct an argument -+ * containing relevant IP info so that TCP probe consumers can utilize it. -+ */ -+static inline void dtrace_tcp_build_iphdr(__be32 saddr, __be32 daddr, -+ struct iphdr *iph) -+{ -+ iph->version = 4; -+ iph->ihl = 5; -+ iph->tot_len = 5; -+ iph->protocol = IPPROTO_TCP; -+ iph->saddr = saddr; -+ iph->daddr = daddr; -+} -+ - /* - * This routine will send an RST to the other tcp. - * -@@ -800,6 +816,39 @@ static void tcp_v4_send_reset(const struct sock *sk, struct sk_buff *skb) - inet_twsk(sk)->tw_priority : sk->sk_priority; - transmit_time = tcp_transmit_time(sk); - } -+ -+ if (DTRACE_TCP_ENABLED(send) || -+ DTRACE_TCP_ENABLED(accept__refused)) { -+ struct iphdr iph; -+ -+ dtrace_tcp_build_iphdr(ip_hdr(skb)->daddr, ip_hdr(skb)->saddr, -+ &iph); -+ -+ DTRACE_TCP_NOCHECK(send, -+ struct sk_buff * : pktinfo_t *, NULL, -+ struct sock * : csinfo_t *, NULL, -+ __dtrace_tcp_void_ip_t * : ipinfo_t *, &iph, -+ struct tcp_sock * : tcpsinfo_t *, NULL, -+ struct tcphdr * : tcpinfo_t *, &rep.th, -+ int : tcplsinfo_t *, TCP_CLOSE, -+ int : int, TCP_CLOSE, -+ int : int, DTRACE_NET_PROBE_OUTBOUND); -+ if (th->syn && rep.th.seq == 0) -+ DTRACE_TCP_NOCHECK(accept__refused, -+ struct sk_buff * : pktinfo_t *, NULL, -+ struct sock * : csinfo_t *, NULL, -+ __dtrace_tcp_void_ip_t * : -+ ipinfo_t *, &iph, -+ struct tcp_sock * : tcpsinfo_t *, -+ NULL, -+ struct tcphdr * : tcpinfo_t *, -+ &rep.th, -+ int : tcplsinfo_t *, TCP_CLOSE, -+ int : int, TCP_CLOSE, -+ int : int, -+ DTRACE_NET_PROBE_OUTBOUND); -+ } -+ - ip_send_unicast_reply(ctl_sk, - skb, &TCP_SKB_CB(skb)->header.h4.opt, - ip_hdr(skb)->saddr, ip_hdr(skb)->daddr, -@@ -896,6 +945,24 @@ static void tcp_v4_send_ack(const struct sock *sk, - ctl_sk->sk_priority = (sk->sk_state == TCP_TIME_WAIT) ? - inet_twsk(sk)->tw_priority : sk->sk_priority; - transmit_time = tcp_transmit_time(sk); -+ -+ if (DTRACE_TCP_ENABLED(send)) { -+ struct iphdr iph; -+ -+ dtrace_tcp_build_iphdr(ip_hdr(skb)->daddr, ip_hdr(skb)->saddr, -+ &iph); -+ -+ DTRACE_TCP_NOCHECK(send, -+ struct sk_buff * : pktinfo_t *, NULL, -+ struct sock * : csinfo_t *, NULL, -+ __dtrace_tcp_void_ip_t * : ipinfo_t *, &iph, -+ struct tcp_sock * : tcpsinfo_t *, NULL, -+ struct tcphdr * : tcpinfo_t *, &rep, -+ int : tcplsinfo_t *, TCP_CLOSE, -+ int : int, TCP_CLOSE, -+ int : int, DTRACE_NET_PROBE_OUTBOUND); -+ } -+ - ip_send_unicast_reply(ctl_sk, - skb, &TCP_SKB_CB(skb)->header.h4.opt, - ip_hdr(skb)->saddr, ip_hdr(skb)->daddr, -@@ -992,6 +1059,30 @@ static int tcp_v4_send_synack(const struct sock *sk, struct dst_entry *dst, - tcp_bpf_ca_needs_ecn((struct sock *)req)) - tos |= INET_ECN_ECT_0; - -+ if (DTRACE_TCP_ENABLED(send)) { -+ struct iphdr iph; -+ -+ dtrace_tcp_build_iphdr(ireq->ir_loc_addr, -+ ireq->ir_rmt_addr, &iph); -+ -+ /* Do not supply tcp sk - addresses/ports are not -+ * committed yet - instead translators will fill them -+ * in from skb/IP info. -+ */ -+ DTRACE_TCP_NOCHECK(send, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, sk, -+ __dtrace_tcp_void_ip_t * : -+ ipinfo_t *, &iph, -+ struct tcp_sock * : tcpsinfo_t *, -+ NULL, -+ struct tcphdr * : tcpinfo_t *, -+ tcp_hdr(skb), -+ int : tcplsinfo_t *, TCP_LISTEN, -+ int, TCP_LISTEN, -+ int, DTRACE_NET_PROBE_OUTBOUND); -+ } -+ - rcu_read_lock(); - err = ip_build_and_send_pkt(skb, sk, ireq->ir_loc_addr, - ireq->ir_rmt_addr, -@@ -1922,7 +2013,7 @@ int tcp_v4_rcv(struct sk_buff *skb) - const struct iphdr *iph; - const struct tcphdr *th; - bool refcounted; -- struct sock *sk; -+ struct sock *sk = NULL; - int ret; - - if (skb->pkt_type != PACKET_HOST) -@@ -1957,6 +2048,15 @@ int tcp_v4_rcv(struct sk_buff *skb) - if (!sk) - goto no_tcp_socket; - -+ DTRACE_TCP(receive, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, sk, -+ __dtrace_tcp_void_ip_t * : ipinfo_t *, ip_hdr(skb), -+ struct tcp_sock * : tcpsinfo_t *, tcp_sk(sk), -+ struct tcphdr * : tcpinfo_t *, tcp_hdr(skb), -+ int : tcplsinfo_t *, sk ? sk->sk_state : TCP_CLOSE, -+ int, sk ? sk->sk_state : TCP_CLOSE, -+ int, DTRACE_NET_PROBE_INBOUND); - process: - if (sk->sk_state == TCP_TIME_WAIT) - goto do_time_wait; -@@ -2084,6 +2184,18 @@ int tcp_v4_rcv(struct sk_buff *skb) - - discard_it: - /* Discard frame. */ -+ if (DTRACE_TCP_ENABLED(receive) && skb->pkt_type == PACKET_HOST) -+ DTRACE_TCP_NOCHECK(receive, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, sk, -+ __dtrace_tcp_void_ip_t * : ipinfo_t *, -+ ip_hdr(skb), -+ struct tcp_sock * : tcpsinfo_t *, tcp_sk(sk), -+ struct tcphdr * : tcpinfo_t *, tcp_hdr(skb), -+ int : tcplsinfo_t *, -+ sk ? sk->sk_state : TCP_CLOSE, -+ int, sk ? sk->sk_state : TCP_CLOSE, -+ int, DTRACE_NET_PROBE_INBOUND); - kfree_skb(skb); - return 0; - -diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c -index 495dda2449fe..d2e368b7072d 100644 ---- a/net/ipv4/tcp_minisocks.c -+++ b/net/ipv4/tcp_minisocks.c -@@ -24,6 +24,7 @@ - #include <linux/slab.h> - #include <linux/sysctl.h> - #include <linux/workqueue.h> -+#include <linux/sdt.h> - #include <linux/static_key.h> - #include <net/tcp.h> - #include <net/inet_common.h> -@@ -328,6 +329,20 @@ void tcp_time_wait(struct sock *sk, int state, int timeo) - */ - inet_twsk_hashdance(tw, sk, &tcp_hashinfo); - local_bh_enable(); -+ -+ if (DTRACE_TCP_ENABLED(state__change) && -+ state != sk->sk_state) -+ DTRACE_TCP_NOCHECK(state__change, -+ struct sk_buff * : pktinfo_t *, NULL, -+ struct sock * : csinfo_t *, sk, -+ __dtrace_tcp_void_ip_t * : -+ ipinfo_t *, NULL, -+ struct tcp_sock * : tcpsinfo_t *, -+ tcp_sk(sk), -+ struct tcphdr * : tcpinfo_t *, NULL, -+ int : tcplsinfo_t *, sk->sk_state, -+ int, state, -+ int, DTRACE_NET_PROBE_OUTBOUND); - } else { - /* Sorry, if we're out of memory, just CLOSE this - * socket up. We've got bigger problems than -diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c -index e58e2589d7f9..aee3d4d6a2ae 100644 ---- a/net/ipv4/tcp_output.c -+++ b/net/ipv4/tcp_output.c -@@ -44,6 +44,7 @@ - #include <linux/gfp.h> - #include <linux/module.h> - #include <linux/static_key.h> -+#include <linux/sdt.h> - - #include <trace/events/tcp.h> - -@@ -1384,6 +1385,27 @@ static int __tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, - tp->bytes_sent += skb->len - tcp_header_size; - } - -+ DTRACE_TCP(send, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, sk, -+ __dtrace_tcp_void_ip_t * : ipinfo_t *, NULL, -+ struct tcp_sock * : tcpsinfo_t *, tp, -+ struct tcphdr * : tcpinfo_t *, tcp_hdr(skb), -+ int : tcplsinfo_t *, sk->sk_state, int, sk->sk_state, -+ int, DTRACE_NET_PROBE_OUTBOUND); -+ if (DTRACE_TCP_ENABLED(connect__request) && th->syn && -+ th->ack_seq == 0) -+ DTRACE_TCP_NOCHECK(connect__request, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, sk, -+ __dtrace_tcp_void_ip_t * : ipinfo_t *, -+ ip_hdr(skb), -+ struct tcp_sock * : tcpsinfo_t *, tp, -+ struct tcphdr * : tcpinfo_t *, th, -+ int : tcplsinfo_t *, sk->sk_state, -+ int, sk->sk_state, -+ int, DTRACE_NET_PROBE_OUTBOUND); -+ - if (after(tcb->end_seq, tp->snd_nxt) || tcb->seq == tcb->end_seq) - TCP_ADD_STATS(sock_net(sk), TCP_MIB_OUTSEGS, - tcp_skb_pcount(skb)); -@@ -3845,6 +3867,13 @@ int tcp_connect(struct sock *sk) - tp->retrans_stamp = tcp_time_stamp(tp); - tcp_connect_queue_skb(sk, buff); - tcp_ecn_send_syn(sk, buff); -+ DTRACE_TCP(state__change, struct sk_buff * : pktinfo_t *, NULL, -+ struct sock * : csinfo_t *, sk, -+ __dtrace_tcp_void_ip_t * : ipinfo_t *, ip_hdr(buff), -+ struct tcp_sock * : tcpsinfo_t *, tp, -+ struct tcphdr * : tcpinfo_t *, tcp_hdr(buff), -+ int : tcplsinfo_t *, TCP_CLOSE, -+ int, sk->sk_state, int, DTRACE_NET_PROBE_OUTBOUND); - tcp_rbtree_insert(&sk->tcp_rtx_queue, buff); - - /* Send off SYN; include data in Fast Open. */ -diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c -index e37a2fa65c29..5d32f5471d85 100644 ---- a/net/ipv4/udp.c -+++ b/net/ipv4/udp.c -@@ -107,6 +107,7 @@ - #include <trace/events/udp.h> - #include <linux/static_key.h> - #include <linux/btf_ids.h> -+#include <linux/sdt.h> - #include <trace/events/skb.h> - #include <net/busy_poll.h> - #include "udp_impl.h" -@@ -945,6 +946,13 @@ static int udp_send_skb(struct sk_buff *skb, struct flowi4 *fl4, - uh->check = CSUM_MANGLED_0; - - send: -+ DTRACE_UDP(send, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, sk, -+ void_ip_t * : ipinfo_t *, ip_hdr(skb), -+ struct udp_sock * : udpsinfo_t *, udp_sk(sk), -+ struct udphdr * : udpinfo_t *, uh); -+ - err = ip_send_skb(sock_net(sk), skb); - if (err) { - if (err == -ENOBUFS && !inet->recverr) { -@@ -1845,9 +1853,16 @@ int udp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int noblock, - return err; - } - -- if (!peeking) -+ if (!peeking) { -+ DTRACE_UDP(receive, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, sk, -+ void_ip_t * : ipinfo_t *, ip_hdr(skb), -+ struct udp_sock * : udpsinfo_t *, udp_sk(sk), -+ struct udphdr * : udpinfo_t *, udp_hdr(skb)); - UDP_INC_STATS(sock_net(sk), - UDP_MIB_INDATAGRAMS, is_udplite); -+ } - - sock_recv_ts_and_drops(msg, sk, skb); - -@@ -2092,6 +2107,15 @@ static int udp_queue_rcv_one_skb(struct sock *sk, struct sk_buff *skb) - - ret = encap_rcv(sk, skb); - if (ret <= 0) { -+ DTRACE_UDP(receive, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, sk, -+ void_ip_t * : ipinfo_t *, -+ ip_hdr(skb), -+ struct udp_sock * : udpsinfo_t *, -+ udp_sk(sk), -+ struct udphdr * : udpinfo_t *, -+ udp_hdr(skb)); - __UDP_INC_STATS(sock_net(sk), - UDP_MIB_INDATAGRAMS, - is_udplite); -diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c -index e96304d8a4a7..aed39e366b60 100644 ---- a/net/ipv6/ip6_input.c -+++ b/net/ipv6/ip6_input.c -@@ -43,6 +43,7 @@ - #include <net/xfrm.h> - #include <net/inet_ecn.h> - #include <net/dst_metadata.h> -+#include <linux/sdt.h> - - INDIRECT_CALLABLE_DECLARE(void udp_v6_early_demux(struct sk_buff *)); - INDIRECT_CALLABLE_DECLARE(void tcp_v6_early_demux(struct sk_buff *)); -@@ -145,13 +146,14 @@ static void ip6_list_rcv_finish(struct net *net, struct sock *sk, - static struct sk_buff *ip6_rcv_core(struct sk_buff *skb, struct net_device *dev, - struct net *net) - { -- const struct ipv6hdr *hdr; -+ const struct ipv6hdr *hdr = NULL; - u32 pkt_len; - struct inet6_dev *idev; -+ const char *dropreason; - - if (skb->pkt_type == PACKET_OTHERHOST) { -- kfree_skb(skb); -- return NULL; -+ dropreason = "for other host"; -+ goto trace_drop; - } - - rcu_read_lock(); -@@ -163,6 +165,7 @@ static struct sk_buff *ip6_rcv_core(struct sk_buff *skb, struct net_device *dev, - if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL || - !idev || unlikely(idev->cnf.disable_ipv6)) { - __IP6_INC_STATS(net, idev, IPSTATS_MIB_INDISCARDS); -+ dropreason = "could not clone shared buffer"; - goto drop; - } - -@@ -181,13 +184,18 @@ static struct sk_buff *ip6_rcv_core(struct sk_buff *skb, struct net_device *dev, - */ - IP6CB(skb)->iif = skb_valid_dst(skb) ? ip6_dst_idev(skb_dst(skb))->dev->ifindex : dev->ifindex; - -- if (unlikely(!pskb_may_pull(skb, sizeof(*hdr)))) -+ if (unlikely(!pskb_may_pull(skb, sizeof(*hdr)))) { -+ hdr = ipv6_hdr(skb); -+ dropreason = "could not pull skb"; - goto err; -+ } - - hdr = ipv6_hdr(skb); - -- if (hdr->version != 6) -+ if (hdr->version != 6) { -+ dropreason = "header invalid"; - goto err; -+ } - - __IP6_ADD_STATS(net, idev, - IPSTATS_MIB_NOECTPKTS + -@@ -203,8 +211,10 @@ static struct sk_buff *ip6_rcv_core(struct sk_buff *skb, struct net_device *dev, - if ((ipv6_addr_loopback(&hdr->saddr) || - ipv6_addr_loopback(&hdr->daddr)) && - !(dev->flags & IFF_LOOPBACK) && -- !netif_is_l3_master(dev)) -+ !netif_is_l3_master(dev)) { -+ dropreason = "loopback destination received on interface"; - goto err; -+ } - - /* RFC4291 Errata ID: 3480 - * Interface-Local scope spans only a single interface on a -@@ -215,8 +225,10 @@ static struct sk_buff *ip6_rcv_core(struct sk_buff *skb, struct net_device *dev, - if (!(skb->pkt_type == PACKET_LOOPBACK || - dev->flags & IFF_LOOPBACK) && - ipv6_addr_is_multicast(&hdr->daddr) && -- IPV6_ADDR_MC_SCOPE(&hdr->daddr) == 1) -+ IPV6_ADDR_MC_SCOPE(&hdr->daddr) == 1) { -+ dropreason = "interface-local scope received from other node"; - goto err; -+ } - - /* If enabled, drop unicast packets that were encapsulated in link-layer - * multicast or broadcast to protected against the so-called "hole-196" -@@ -225,8 +237,10 @@ static struct sk_buff *ip6_rcv_core(struct sk_buff *skb, struct net_device *dev, - if (!ipv6_addr_is_multicast(&hdr->daddr) && - (skb->pkt_type == PACKET_BROADCAST || - skb->pkt_type == PACKET_MULTICAST) && -- idev->cnf.drop_unicast_in_l2_multicast) -+ idev->cnf.drop_unicast_in_l2_multicast) { -+ dropreason = "unicast packet encapsulated in multi/broadcast"; - goto err; -+ } - - /* RFC4291 2.7 - * Nodes must not originate a packet to a multicast address whose scope -@@ -234,16 +248,21 @@ static struct sk_buff *ip6_rcv_core(struct sk_buff *skb, struct net_device *dev, - * must be silently dropped. - */ - if (ipv6_addr_is_multicast(&hdr->daddr) && -- IPV6_ADDR_MC_SCOPE(&hdr->daddr) == 0) -+ IPV6_ADDR_MC_SCOPE(&hdr->daddr) == 0) { -+ dropreason = -+ "packet to multicast address with reserved scope 0"; - goto err; -+ } - - /* - * RFC4291 2.7 - * Multicast addresses must not be used as source addresses in IPv6 - * packets or appear in any Routing header. - */ -- if (ipv6_addr_is_multicast(&hdr->saddr)) -+ if (ipv6_addr_is_multicast(&hdr->saddr)) { -+ dropreason = "multicast source address in IPv6 packet"; - goto err; -+ } - - /* While RFC4291 is not explicit about v4mapped addresses - * in IPv6 headers, it seems clear linux dual-stack -@@ -253,7 +272,10 @@ static struct sk_buff *ip6_rcv_core(struct sk_buff *skb, struct net_device *dev, - * https://tools.ietf.org/html/draft-itojun-v6ops-v4mapped-harmful-02 - */ - if (ipv6_addr_v4mapped(&hdr->saddr)) -+ { -+ dropreason = "v4-mapped address in IPv6 packet"; - goto err; -+ } - - skb->transport_header = skb->network_header + sizeof(*hdr); - IP6CB(skb)->nhoff = offsetof(struct ipv6hdr, nexthdr); -@@ -265,10 +287,12 @@ static struct sk_buff *ip6_rcv_core(struct sk_buff *skb, struct net_device *dev, - if (pkt_len + sizeof(struct ipv6hdr) > skb->len) { - __IP6_INC_STATS(net, - idev, IPSTATS_MIB_INTRUNCATEDPKTS); -+ dropreason = "truncated packet"; - goto drop; - } - if (pskb_trim_rcsum(skb, pkt_len + sizeof(struct ipv6hdr))) { - __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS); -+ dropreason = "could not trim buffer"; - goto drop; - } - hdr = ipv6_hdr(skb); -@@ -276,9 +300,10 @@ static struct sk_buff *ip6_rcv_core(struct sk_buff *skb, struct net_device *dev, - - if (hdr->nexthdr == NEXTHDR_HOP) { - if (ipv6_parse_hopopts(skb) < 0) { -- __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS); -- rcu_read_unlock(); -- return NULL; -+ dropreason = "could not parse hop opts"; -+ /* do not free skb */ -+ skb = NULL; -+ goto err; - } - } - -@@ -293,6 +318,15 @@ static struct sk_buff *ip6_rcv_core(struct sk_buff *skb, struct net_device *dev, - __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS); - drop: - rcu_read_unlock(); -+trace_drop: -+ DTRACE_IP(drop__in, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, skb ? skb->sk : NULL, -+ void_ip_t * : ipinfo_t *, hdr, -+ struct net_device * : ifinfo_t *, skb ? skb->dev : NULL, -+ struct iphdr * : ipv4info_t *, NULL, -+ struct ipv6hdr * : ipv6info_t *, hdr, -+ const char * : string, dropreason); - kfree_skb(skb); - return NULL; - } -@@ -365,6 +399,8 @@ void ip6_protocol_deliver_rcu(struct net *net, struct sk_buff *skb, int nexthdr, - struct inet6_dev *idev; - unsigned int nhoff; - bool raw; -+ const struct ipv6hdr *hdr; -+ const char *dropreason; - - /* - * Parse extension headers -@@ -374,8 +410,10 @@ void ip6_protocol_deliver_rcu(struct net *net, struct sk_buff *skb, int nexthdr, - idev = ip6_dst_idev(skb_dst(skb)); - nhoff = IP6CB(skb)->nhoff; - if (!have_final) { -- if (!pskb_pull(skb, skb_transport_offset(skb))) -+ if (!pskb_pull(skb, skb_transport_offset(skb))) { -+ dropreason = "could not pull skb"; - goto discard; -+ } - nexthdr = skb_network_header(skb)[nhoff]; - } - -@@ -392,10 +430,10 @@ void ip6_protocol_deliver_rcu(struct net *net, struct sk_buff *skb, int nexthdr, - * ones. This allows foo in UDP encapsulation - * to work. - */ -+ dropreason = "non-final protocol"; - goto discard; - } - } else if (ipprot->flags & INET6_PROTO_FINAL) { -- const struct ipv6hdr *hdr; - int sdif = inet6_sdif(skb); - struct net_device *dev; - -@@ -414,8 +452,10 @@ void ip6_protocol_deliver_rcu(struct net *net, struct sk_buff *skb, int nexthdr, - /* skb->dev passed may be master dev for vrfs. */ - if (sdif) { - dev = dev_get_by_index_rcu(net, sdif); -- if (!dev) -+ if (!dev) { -+ dropreason = "device disappeared"; - goto discard; -+ } - } else { - dev = skb->dev; - } -@@ -423,12 +463,16 @@ void ip6_protocol_deliver_rcu(struct net *net, struct sk_buff *skb, int nexthdr, - if (ipv6_addr_is_multicast(&hdr->daddr) && - !ipv6_chk_mcast_addr(dev, &hdr->daddr, - &hdr->saddr) && -- !ipv6_is_mld(skb, nexthdr, skb_network_header_len(skb))) -+ !ipv6_is_mld(skb, nexthdr, skb_network_header_len(skb))) { -+ dropreason = "destination is multicast"; - goto discard; -+ } - } - if (!(ipprot->flags & INET6_PROTO_NOPOLICY) && -- !xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) -+ !xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) { -+ dropreason = "policy failure"; - goto discard; -+ } - - ret = INDIRECT_CALL_2(ipprot->handler, tcp_v6_rcv, udpv6_rcv, - skb); -@@ -454,6 +498,8 @@ void ip6_protocol_deliver_rcu(struct net *net, struct sk_buff *skb, int nexthdr, - IPSTATS_MIB_INUNKNOWNPROTOS); - icmpv6_send(skb, ICMPV6_PARAMPROB, - ICMPV6_UNK_NEXTHDR, nhoff); -+ dropreason = "policy failure"; -+ goto trace_drop; - } - kfree_skb(skb); - } else { -@@ -465,6 +511,17 @@ void ip6_protocol_deliver_rcu(struct net *net, struct sk_buff *skb, int nexthdr, - - discard: - __IP6_INC_STATS(net, idev, IPSTATS_MIB_INDISCARDS); -+trace_drop: -+ hdr = ipv6_hdr(skb); -+ DTRACE_IP(drop__in, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, skb->sk, -+ void_ip_t * : ipinfo_t *, hdr, -+ struct net_device * : ifinfo_t *, skb->dev, -+ struct iphdr * : ipv4info_t *, NULL, -+ struct ipv6hdr * : ipv6info_t *, hdr, -+ const char * : string, dropreason); -+ rcu_read_unlock(); - kfree_skb(skb); - } - -@@ -480,6 +537,16 @@ static int ip6_input_finish(struct net *net, struct sock *sk, struct sk_buff *sk - - int ip6_input(struct sk_buff *skb) - { -+ struct ipv6hdr *hdr = ipv6_hdr(skb); -+ -+ DTRACE_IP(receive, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, skb->sk, -+ void_ip_t * : ipinfo_t *, hdr, -+ struct net_device * : ifinfo_t *, skb->dev, -+ struct iphdr * : ipv4info_t *, NULL, -+ struct ipv6hdr * : ipv6info_t *, hdr); -+ - return NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_IN, - dev_net(skb->dev), NULL, skb, skb->dev, NULL, - ip6_input_finish); -diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c -index 077d43af8226..1c972fb379b5 100644 ---- a/net/ipv6/ip6_output.c -+++ b/net/ipv6/ip6_output.c -@@ -55,6 +55,7 @@ - #include <net/l3mdev.h> - #include <net/lwtunnel.h> - #include <net/ip_tunnels.h> -+#include <linux/sdt.h> - - static int ip6_finish_output2(struct net *net, struct sock *sk, struct sk_buff *skb) - { -@@ -62,7 +63,8 @@ static int ip6_finish_output2(struct net *net, struct sock *sk, struct sk_buff * - struct net_device *dev = dst->dev; - const struct in6_addr *nexthop; - struct neighbour *neigh; -- int ret; -+ const char *dropreason; -+ int ret = 0; - - if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr)) { - struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb)); -@@ -83,10 +85,11 @@ static int ip6_finish_output2(struct net *net, struct sock *sk, struct sk_buff * - dev_loopback_xmit); - - if (ipv6_hdr(skb)->hop_limit == 0) { -+ dropreason = "hoplimit exceeded"; -+ - IP6_INC_STATS(net, idev, - IPSTATS_MIB_OUTDISCARDS); -- kfree_skb(skb); -- return 0; -+ goto drop; - } - } - -@@ -95,8 +98,8 @@ static int ip6_finish_output2(struct net *net, struct sock *sk, struct sk_buff * - if (IPV6_ADDR_MC_SCOPE(&ipv6_hdr(skb)->daddr) <= - IPV6_ADDR_SCOPE_NODELOCAL && - !(dev->flags & IFF_LOOPBACK)) { -- kfree_skb(skb); -- return 0; -+ dropreason = "invalid scope"; -+ goto drop; - } - } - -@@ -120,9 +123,20 @@ static int ip6_finish_output2(struct net *net, struct sock *sk, struct sk_buff * - } - rcu_read_unlock_bh(); - -+ dropreason = "no route to host"; - IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES); -+ ret = -EINVAL; -+drop: -+ DTRACE_IP(drop__out, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, skb->sk, -+ void_ip_t * : ipinfo_t *, ipv6_hdr(skb), -+ struct net_device * : ifinfo_t *, skb->dev, -+ struct iphdr * : ipv4info_t *, NULL, -+ struct ipv6hdr * : ipv6info_t *, ipv6_hdr(skb), -+ const char * : string, dropreason); - kfree_skb(skb); -- return -EINVAL; -+ return ret; - } - - static int -@@ -207,6 +221,15 @@ int ip6_output(struct net *net, struct sock *sk, struct sk_buff *skb) - skb->dev = dev; - - if (unlikely(idev->cnf.disable_ipv6)) { -+ DTRACE_IP(drop__out, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, skb->sk, -+ void_ip_t * : ipinfo_t *, NULL, -+ struct net_device * : ifinfo_t *, skb->dev, -+ struct iphdr * : ipv4info_t *, NULL, -+ struct ipv6hdr * : ipv6info_t *, NULL, -+ const char * : string, "IPv6 is disabled"); -+ - IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTDISCARDS); - kfree_skb(skb); - return 0; -@@ -243,8 +266,10 @@ int ip6_xmit(const struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6, - struct ipv6hdr *hdr; - u8 proto = fl6->flowi6_proto; - int seg_len = skb->len; -+ const char *dropreason; - int hlimit = -1; - u32 mtu; -+ int err; - - head_room = sizeof(struct ipv6hdr) + LL_RESERVED_SPACE(dst->dev); - if (opt) -@@ -253,10 +278,12 @@ int ip6_xmit(const struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6, - if (unlikely(skb_headroom(skb) < head_room)) { - struct sk_buff *skb2 = skb_realloc_headroom(skb, head_room); - if (!skb2) { -+ dropreason = "out of memory"; - IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), - IPSTATS_MIB_OUTDISCARDS); - kfree_skb(skb); -- return -ENOBUFS; -+ err = -ENOBUFS; -+ goto drop; - } - if (skb->sk) - skb_set_owner_w(skb2, skb->sk); -@@ -313,6 +340,14 @@ int ip6_xmit(const struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6, - if (unlikely(!skb)) - return 0; - -+ DTRACE_IP(send, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, skb->sk, -+ void_ip_t * : ipinfo_t *, hdr, -+ struct net_device * : ifinfo_t *, skb->dev, -+ struct iphdr * : ipv4info_t *, NULL, -+ struct ipv6hdr * : ipv6info_t *, hdr); -+ - /* hooks should never assume socket lock is held. - * we promote our socket to non const - */ -@@ -327,9 +362,21 @@ int ip6_xmit(const struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6, - */ - ipv6_local_error((struct sock *)sk, EMSGSIZE, fl6, mtu); - -+ dropreason = "fragmentation failure"; - IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_FRAGFAILS); -+ err = -EMSGSIZE; -+drop: -+ DTRACE_IP(drop__out, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, skb->sk, -+ void_ip_t * : ipinfo_t *, NULL, -+ struct net_device * : ifinfo_t *, skb->dev, -+ struct iphdr * : ipv4info_t *, NULL, -+ struct ipv6hdr * : ipv6info_t *, NULL, -+ const char * : string, dropreason); -+ - kfree_skb(skb); -- return -EMSGSIZE; -+ return err; - } - EXPORT_SYMBOL(ip6_xmit); - -@@ -464,22 +511,33 @@ int ip6_forward(struct sk_buff *skb) - struct ipv6hdr *hdr = ipv6_hdr(skb); - struct inet6_skb_parm *opt = IP6CB(skb); - struct net *net = dev_net(dst->dev); -+ const char *dropreason; -+ int err = -EINVAL; - u32 mtu; - -- if (net->ipv6.devconf_all->forwarding == 0) -+ if (net->ipv6.devconf_all->forwarding == 0) { -+ dropreason = "forwarding disabled"; - goto error; -+ } - -- if (skb->pkt_type != PACKET_HOST) -+ if (skb->pkt_type != PACKET_HOST) { -+ dropreason = "non-host packet type cannot be forwarded"; - goto drop; -+ } - -- if (unlikely(skb->sk)) -+ if (unlikely(skb->sk)) { -+ dropreason = "socket found for packet to be forwarded"; - goto drop; -+ } - -- if (skb_warn_if_lro(skb)) -+ if (skb_warn_if_lro(skb)) { -+ dropreason = "LRO warning"; - goto drop; -+ } - - if (!xfrm6_policy_check(NULL, XFRM_POLICY_FWD, skb)) { - __IP6_INC_STATS(net, idev, IPSTATS_MIB_INDISCARDS); -+ dropreason = "forwarding disabled by policy"; - goto drop; - } - -@@ -510,8 +568,9 @@ int ip6_forward(struct sk_buff *skb) - icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT, 0); - __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS); - -- kfree_skb(skb); -- return -ETIMEDOUT; -+ dropreason = "hoplimit exceeded"; -+ err = -ETIMEDOUT; -+ goto drop; - } - - /* XXX: idev->cnf.proxy_ndp? */ -@@ -521,6 +580,7 @@ int ip6_forward(struct sk_buff *skb) - if (proxied > 0) - return ip6_input(skb); - else if (proxied < 0) { -+ dropreason = "proxy router cannot forward"; - __IP6_INC_STATS(net, idev, IPSTATS_MIB_INDISCARDS); - goto drop; - } -@@ -528,6 +588,7 @@ int ip6_forward(struct sk_buff *skb) - - if (!xfrm6_route_forward(skb)) { - __IP6_INC_STATS(net, idev, IPSTATS_MIB_INDISCARDS); -+ dropreason = "forwarding disabled for destination"; - goto drop; - } - dst = skb_dst(skb); -@@ -567,9 +628,12 @@ int ip6_forward(struct sk_buff *skb) - - /* This check is security critical. */ - if (addrtype == IPV6_ADDR_ANY || -- addrtype & (IPV6_ADDR_MULTICAST | IPV6_ADDR_LOOPBACK)) -+ addrtype & (IPV6_ADDR_MULTICAST | IPV6_ADDR_LOOPBACK)) { -+ dropreason = "invalid address type for forwarding"; - goto error; -+ } - if (addrtype & IPV6_ADDR_LINKLOCAL) { -+ dropreason = "invalid address type for forwarding"; - icmpv6_send(skb, ICMPV6_DEST_UNREACH, - ICMPV6_NOT_NEIGHBOUR, 0); - goto error; -@@ -583,17 +647,20 @@ int ip6_forward(struct sk_buff *skb) - if (ip6_pkt_too_big(skb, mtu)) { - /* Again, force OUTPUT device used as source address */ - skb->dev = dst->dev; -+ - icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); - __IP6_INC_STATS(net, idev, IPSTATS_MIB_INTOOBIGERRORS); - __IP6_INC_STATS(net, ip6_dst_idev(dst), - IPSTATS_MIB_FRAGFAILS); -- kfree_skb(skb); -- return -EMSGSIZE; -+ dropreason = "packet too big"; -+ err = -EMSGSIZE; -+ goto drop; - } - - if (skb_cow(skb, dst->dev->hard_header_len)) { - __IP6_INC_STATS(net, ip6_dst_idev(dst), - IPSTATS_MIB_OUTDISCARDS); -+ dropreason = "copy-on-write failed"; - goto drop; - } - -@@ -610,6 +677,15 @@ int ip6_forward(struct sk_buff *skb) - error: - __IP6_INC_STATS(net, idev, IPSTATS_MIB_INADDRERRORS); - drop: -+ DTRACE_IP(drop__out, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, skb->sk, -+ void_ip_t * : ipinfo_t *, hdr, -+ struct net_device * : ifinfo_t *, skb->dev, -+ struct iphdr * : ipv4info_t *, NULL, -+ struct ipv6hdr * : ipv6info_t *, hdr, -+ const char * : string, dropreason); -+ - kfree_skb(skb); - return -EINVAL; - } -@@ -1445,6 +1521,7 @@ static int __ip6_append_data(struct sock *sk, - unsigned int maxnonfragsize, headersize; - unsigned int wmem_alloc_delta = 0; - bool paged, extra_uref = false; -+ const char *dropreason; - - skb = skb_peek_tail(queue); - if (!skb) { -@@ -1484,6 +1561,7 @@ static int __ip6_append_data(struct sock *sk, - sk->sk_protocol == IPPROTO_RAW)) { - ipv6_local_rxpmtu(sk, fl6, mtu - headersize + - sizeof(struct ipv6hdr)); -+ dropreason = "fragmentation needed but disabled"; - goto emsgsize; - } - -@@ -1496,7 +1574,9 @@ static int __ip6_append_data(struct sock *sk, - emsgsize: - pmtu = max_t(int, mtu - headersize + sizeof(struct ipv6hdr), 0); - ipv6_local_error(sk, EMSGSIZE, fl6, pmtu); -- return -EMSGSIZE; -+ dropreason = "packet too big"; -+ err = -EMSGSIZE; -+ goto trace_drop; - } - - /* CHECKSUM_PARTIAL only with no extension headers and when -@@ -1511,8 +1591,11 @@ static int __ip6_append_data(struct sock *sk, - - if (flags & MSG_ZEROCOPY && length && sock_flag(sk, SOCK_ZEROCOPY)) { - uarg = sock_zerocopy_realloc(sk, length, skb_zcopy(skb)); -- if (!uarg) -- return -ENOBUFS; -+ if (!uarg) { -+ err = -ENOBUFS; -+ dropreason = "out of memory"; -+ goto error; -+ } - extra_uref = !skb_zcopy(skb); /* only ref on new uarg */ - if (rt->dst.dev->features & NETIF_F_SG && - csummode == CHECKSUM_PARTIAL) { -@@ -1614,6 +1697,7 @@ static int __ip6_append_data(struct sock *sk, - copy = datalen - transhdrlen - fraggap - pagedlen; - if (copy < 0) { - err = -EINVAL; -+ dropreason = "invalid fragment"; - goto error; - } - if (transhdrlen) { -@@ -1626,11 +1710,13 @@ static int __ip6_append_data(struct sock *sk, - 2 * sk->sk_sndbuf) - skb = alloc_skb(alloclen + hh_len, - sk->sk_allocation); -- if (unlikely(!skb)) -- err = -ENOBUFS; - } -- if (!skb) -+ if (unlikely(!skb)) { -+ err = -ENOBUFS; -+ dropreason = "out of memory"; - goto error; -+ } -+ - /* - * Fill in the control structures - */ -@@ -1662,7 +1748,9 @@ static int __ip6_append_data(struct sock *sk, - getfrag(from, data + transhdrlen, offset, - copy, fraggap, skb) < 0) { - err = -EFAULT; -+ dropreason = "could not get fragment"; - kfree_skb(skb); -+ skb = NULL; - goto error; - } - -@@ -1706,20 +1794,25 @@ static int __ip6_append_data(struct sock *sk, - offset, copy, off, skb) < 0) { - __skb_trim(skb, off); - err = -EFAULT; -+ dropreason = "could not get fragment"; - goto error; - } - } else if (!uarg || !uarg->zerocopy) { - int i = skb_shinfo(skb)->nr_frags; - - err = -ENOMEM; -- if (!sk_page_frag_refill(sk, pfrag)) -+ if (!sk_page_frag_refill(sk, pfrag)) { -+ dropreason = "out of memory"; - goto error; -+ } - - if (!skb_can_coalesce(skb, i, pfrag->page, - pfrag->offset)) { - err = -EMSGSIZE; -- if (i == MAX_SKB_FRAGS) -+ if (i == MAX_SKB_FRAGS) { -+ dropreason = "too many fragments"; - goto error; -+ } - - __skb_fill_page_desc(skb, i, pfrag->page, - pfrag->offset, 0); -@@ -1729,8 +1822,10 @@ static int __ip6_append_data(struct sock *sk, - copy = min_t(int, copy, pfrag->size - pfrag->offset); - if (getfrag(from, - page_address(pfrag->page) + pfrag->offset, -- offset, copy, skb->len, skb) < 0) -+ offset, copy, skb->len, skb) < 0) { -+ dropreason = "could not get fragment"; - goto error_efault; -+ } - - pfrag->offset += copy; - skb_frag_size_add(&skb_shinfo(skb)->frags[i - 1], copy); -@@ -1740,8 +1835,10 @@ static int __ip6_append_data(struct sock *sk, - wmem_alloc_delta += copy; - } else { - err = skb_zerocopy_iter_dgram(skb, from, copy); -- if (err < 0) -+ if (err < 0) { -+ dropreason = "skb iteration failure\n"; - goto error; -+ } - } - offset += copy; - length -= copy; -@@ -1758,6 +1855,16 @@ static int __ip6_append_data(struct sock *sk, - sock_zerocopy_put_abort(uarg, extra_uref); - cork->length -= length; - IP6_INC_STATS(sock_net(sk), rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS); -+trace_drop: -+ DTRACE_IP(drop__out, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, skb ? skb->sk : NULL, -+ void_ip_t * : ipinfo_t *, NULL, -+ struct net_device * : ifinfo_t *, skb ? skb->dev : NULL, -+ struct iphdr * : ipv4info_t *, NULL, -+ struct ipv6hdr * : ipv6info_t *, NULL, -+ const char * : string, dropreason); -+ - refcount_add(wmem_alloc_delta, &sk->sk_wmem_alloc); - return err; - } -@@ -1905,9 +2012,20 @@ int ip6_send_skb(struct sk_buff *skb) - if (err) { - if (err > 0) - err = net_xmit_errno(err); -- if (err) -+ if (err) { -+ /* skb may have been freed */ -+ DTRACE_IP(drop__out, -+ struct sk_buff * : pktinfo_t *, NULL, -+ struct sock * : csinfo_t *, NULL, -+ void_ip_t * : ipinfo_t *, NULL, -+ struct net_device * : ifinfo_t *, NULL, -+ struct iphdr * : ipv4info_t *, NULL, -+ struct ipv6hdr * : ipv6info_t *, NULL, -+ const char * : string, "out of memory"); -+ - IP6_INC_STATS(net, rt->rt6i_idev, - IPSTATS_MIB_OUTDISCARDS); -+ } - } - - return err; -@@ -1933,9 +2051,19 @@ static void __ip6_flush_pending_frames(struct sock *sk, - struct sk_buff *skb; - - while ((skb = __skb_dequeue_tail(queue)) != NULL) { -- if (skb_dst(skb)) -+ if (skb_dst(skb)) { -+ DTRACE_IP(drop__out, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, skb->sk, -+ void_ip_t * : ipinfo_t *, ipv6_hdr(skb), -+ struct net_device * : ifinfo_t *, skb->dev, -+ struct iphdr * : ipv4info_t *, NULL, -+ struct ipv6hdr * : ipv6info_t *, -+ ipv6_hdr(skb), -+ const char * : string, "flushing pending frames"); - IP6_INC_STATS(sock_net(sk), ip6_dst_idev(skb_dst(skb)), - IPSTATS_MIB_OUTDISCARDS); -+ } - kfree_skb(skb); - } - -diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c -index 8cd2782a31e4..e90cb6e0781d 100644 ---- a/net/ipv6/mcast.c -+++ b/net/ipv6/mcast.c -@@ -60,6 +60,8 @@ - - #include <net/ip6_checksum.h> - -+#include <linux/sdt.h> -+ - /* Ensure that we have struct in6_addr aligned on 32bit word. */ - static int __mld2_query_bugs[] __attribute__((__unused__)) = { - BUILD_BUG_ON_ZERO(offsetof(struct mld2_query, mld2q_srcs) % 4), -@@ -1644,6 +1646,7 @@ static void mld_sendpack(struct sk_buff *skb) - int payload_len, mldlen; - struct inet6_dev *idev; - struct net *net = dev_net(skb->dev); -+ const char *dropreason; - int err; - struct flowi6 fl6; - struct dst_entry *dst; -@@ -1673,26 +1676,45 @@ static void mld_sendpack(struct sk_buff *skb) - dst = NULL; - } - skb_dst_set(skb, dst); -- if (err) -- goto err_out; -+ if (err) { -+ kfree_skb(skb); -+ skb = NULL; -+ dropreason = "out of memory"; -+ goto out; -+ } -+ -+ DTRACE_IP(send, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, skb->sk, -+ void_ip_t * : ipinfo_t *, ipv6_hdr(skb), -+ struct net_device * : ifinfo_t *, skb->dev, -+ struct iphdr * : ipv4info_t *, NULL, -+ struct ipv6hdr * : ipv6info_t *, ipv6_hdr(skb)); - - err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, - net, net->ipv6.igmp_sk, skb, NULL, skb->dev, - dst_output); -+ dropreason = "multicast send error"; - out: - if (!err) { - ICMP6MSGOUT_INC_STATS(net, idev, ICMPV6_MLD2_REPORT); - ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS); - } else { -+ /* skb may have been freed */ -+ DTRACE_IP(drop__out, -+ struct sk_buff * : pktinfo_t *, NULL, -+ struct sock * : csinfo_t *, NULL, -+ void_ip_t * : ipinfo_t *, NULL, -+ struct net_device * : ifinfo_t *, idev->dev, -+ struct iphdr * : ipv4info_t *, NULL, -+ struct ipv6hdr * : ipv6info_t *, NULL, -+ const char * : string, dropreason); -+ - IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTDISCARDS); - } - - rcu_read_unlock(); - return; -- --err_out: -- kfree_skb(skb); -- goto out; - } - - static int grec_size(struct ifmcaddr6 *pmc, int type, int gdel, int sdel) -@@ -1979,7 +2001,7 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) - { - struct net *net = dev_net(dev); - struct sock *sk = net->ipv6.igmp_sk; -- struct inet6_dev *idev; -+ struct inet6_dev *idev = NULL; - struct sk_buff *skb; - struct mld_msg *hdr; - const struct in6_addr *snd_addr, *saddr; -@@ -1990,6 +2012,7 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) - u8 ra[8] = { IPPROTO_ICMPV6, 0, - IPV6_TLV_ROUTERALERT, 2, 0, 0, - IPV6_TLV_PADN, 0 }; -+ const char *dropreason; - struct flowi6 fl6; - struct dst_entry *dst; - -@@ -2011,10 +2034,8 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) - - if (!skb) { - rcu_read_lock(); -- IP6_INC_STATS(net, __in6_dev_get(dev), -- IPSTATS_MIB_OUTDISCARDS); -- rcu_read_unlock(); -- return; -+ dropreason = "out of memory"; -+ goto out; - } - skb->priority = TC_PRIO_CONTROL; - skb_reserve(skb, hlen); -@@ -2049,26 +2070,43 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) - dst = icmp6_dst_alloc(skb->dev, &fl6); - if (IS_ERR(dst)) { - err = PTR_ERR(dst); -- goto err_out; -+ kfree_skb(skb); -+ skb = NULL; -+ dropreason = "out of memory"; -+ goto out; - } - - skb_dst_set(skb, dst); -+ DTRACE_IP(send, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, skb->sk, -+ void_ip_t * : ipinfo_t *, ipv6_hdr(skb), -+ struct net_device * : ifinfo_t *, skb->dev, -+ struct iphdr * : ipv4info_t *, NULL, -+ struct ipv6hdr * : ipv6info_t *, ipv6_hdr(skb)); - err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, - net, sk, skb, NULL, skb->dev, - dst_output); -+ dropreason = "multicast send error"; - out: - if (!err) { - ICMP6MSGOUT_INC_STATS(net, idev, type); - ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS); -- } else -+ } else { -+ /* skb may have been freed */ -+ DTRACE_IP(drop__out, -+ struct sk_buff * : pktinfo_t *, NULL, -+ struct sock * : csinfo_t *, sk, -+ void_ip_t * : ipinfo_t *, NULL, -+ struct net_device * : ifinfo_t *, idev->dev, -+ struct iphdr * : ipv4info_t *, NULL, -+ struct ipv6hdr * : ipv6info_t *, NULL, -+ const char * : string, dropreason); - IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTDISCARDS); -+ } - - rcu_read_unlock(); - return; -- --err_out: -- kfree_skb(skb); -- goto out; - } - - static void mld_send_initial_cr(struct inet6_dev *idev) -diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c -index 76717478f173..35ae4eaffd89 100644 ---- a/net/ipv6/ndisc.c -+++ b/net/ipv6/ndisc.c -@@ -68,6 +68,7 @@ - - #include <linux/netfilter.h> - #include <linux/netfilter_ipv6.h> -+#include <linux/sdt.h> - - static u32 ndisc_hash(const void *pkey, - const struct net_device *dev, -@@ -505,6 +506,14 @@ static void ndisc_send_skb(struct sk_buff *skb, - idev = __in6_dev_get(dst->dev); - IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len); - -+ DTRACE_IP(send, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, skb->sk, -+ void_ip_t * : ipinfo_t *, ipv6_hdr(skb), -+ struct net_device * : ifinfo_t *, skb->dev, -+ struct iphdr * : ipv4info_t *, NULL, -+ struct ipv6hdr * : ipv6info_t *, ipv6_hdr(skb)); -+ - err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, - net, sk, skb, NULL, dst->dev, - dst_output); -diff --git a/net/ipv6/output_core.c b/net/ipv6/output_core.c -index af36acc1a644..811a88767a5c 100644 ---- a/net/ipv6/output_core.c -+++ b/net/ipv6/output_core.c -@@ -10,6 +10,7 @@ - #include <net/addrconf.h> - #include <net/secure_seq.h> - #include <linux/netfilter.h> -+#include <linux/sdt.h> - - static u32 __ipv6_select_ident(struct net *net, - const struct in6_addr *dst, -@@ -164,6 +165,14 @@ int __ip6_local_out(struct net *net, struct sock *sk, struct sk_buff *skb) - - skb->protocol = htons(ETH_P_IPV6); - -+ DTRACE_IP(send, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, skb->sk, -+ void_ip_t * : ipinfo_t *, ipv6_hdr(skb), -+ struct net_device * : ifinfo_t *, skb->dev, -+ struct iphdr * : ipv4info_t *, NULL, -+ struct ipv6hdr * : ipv6info_t *, ipv6_hdr(skb)); -+ - return nf_hook(NFPROTO_IPV6, NF_INET_LOCAL_OUT, - net, sk, skb, NULL, skb_dst(skb)->dev, - dst_output); -diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c -index 6e4ab80a3b94..f88c9441ec51 100644 ---- a/net/ipv6/raw.c -+++ b/net/ipv6/raw.c -@@ -58,6 +58,7 @@ - #include <linux/proc_fs.h> - #include <linux/seq_file.h> - #include <linux/export.h> -+#include <linux/sdt.h> - - #define ICMPV6_HDRLEN 4 /* ICMPv6 header, RFC 4443 Section 2.1 */ - -@@ -622,26 +623,34 @@ static int rawv6_send_hdrinc(struct sock *sk, struct msghdr *msg, int length, - struct ipv6_pinfo *np = inet6_sk(sk); - struct net *net = sock_net(sk); - struct ipv6hdr *iph; -- struct sk_buff *skb; -+ struct sk_buff *skb = NULL; - int err; - struct rt6_info *rt = (struct rt6_info *)*dstp; - int hlen = LL_RESERVED_SPACE(rt->dst.dev); - int tlen = rt->dst.dev->needed_tailroom; -+ const char *dropreason; - - if (length > rt->dst.dev->mtu) { - ipv6_local_error(sk, EMSGSIZE, fl6, rt->dst.dev->mtu); -- return -EMSGSIZE; -+ dropreason = "packet too big"; -+ err = -EMSGSIZE; -+ goto error_check; -+ } -+ if (length < sizeof(struct ipv6hdr)) { -+ dropreason = "packet too short"; -+ err = -EINVAL; -+ goto error_check; - } -- if (length < sizeof(struct ipv6hdr)) -- return -EINVAL; - if (flags&MSG_PROBE) - goto out; - - skb = sock_alloc_send_skb(sk, - length + hlen + tlen + 15, - flags & MSG_DONTWAIT, &err); -- if (!skb) -+ if (!skb) { -+ dropreason = "out of memory"; - goto error; -+ } - skb_reserve(skb, hlen); - - skb->protocol = htons(ETH_P_IPV6); -@@ -665,7 +674,8 @@ static int rawv6_send_hdrinc(struct sock *sk, struct msghdr *msg, int length, - if (err) { - err = -EFAULT; - kfree_skb(skb); -- goto error; -+ dropreason = "could not copy msg"; -+ goto error_check; - } - - skb_dst_set(skb, &rt->dst); -@@ -684,6 +694,13 @@ static int rawv6_send_hdrinc(struct sock *sk, struct msghdr *msg, int length, - */ - rcu_read_lock(); - IP6_UPD_PO_STATS(net, rt->rt6i_idev, IPSTATS_MIB_OUT, skb->len); -+ DTRACE_IP(send, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, skb->sk, -+ void_ip_t * : ipinfo_t *, ipv6_hdr(skb), -+ struct net_device * : ifinfo_t *, skb->dev, -+ struct iphdr * : ipv4info_t *, NULL, -+ struct ipv6hdr * : ipv6info_t *, ipv6_hdr(skb)); - err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, net, sk, skb, - NULL, rt->dst.dev, dst_output); - if (err > 0) -@@ -691,6 +708,7 @@ static int rawv6_send_hdrinc(struct sock *sk, struct msghdr *msg, int length, - if (err) { - IP6_INC_STATS(net, rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS); - rcu_read_unlock(); -+ dropreason = "raw send error"; - goto error_check; - } - rcu_read_unlock(); -@@ -700,6 +718,14 @@ static int rawv6_send_hdrinc(struct sock *sk, struct msghdr *msg, int length, - error: - IP6_INC_STATS(net, rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS); - error_check: -+ DTRACE_IP(drop__out, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, skb ? skb->sk : NULL, -+ void_ip_t * : ipinfo_t *, skb ? ipv6_hdr(skb) : NULL, -+ struct net_device * : ifinfo_t *, skb ? skb->dev : NULL, -+ struct iphdr * : ipv4info_t *, NULL, -+ struct ipv6hdr * : ipv6info_t *, skb ? ipv6_hdr(skb) : NULL, -+ const char * : string, dropreason); - if (err == -ENOBUFS && !np->recverr) - err = 0; - return err; -diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c -index 991dc36f95ff..acc63c455651 100644 ---- a/net/ipv6/tcp_ipv6.c -+++ b/net/ipv6/tcp_ipv6.c -@@ -65,6 +65,7 @@ - - #include <crypto/hash.h> - #include <linux/scatterlist.h> -+#include <linux/sdt.h> - - #include <trace/events/tcp.h> - -@@ -496,6 +497,20 @@ static int tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, - return 0; - } - -+/* Since we want to trace send events in TCP prior to pushing the segment to -+ * IP - where the IP header is added - we need to construct an argument -+ * containing relevant IP info so that TCP probe consumers can utilize it. -+ */ -+static inline void dtrace_tcp_build_ipv6hdr(struct in6_addr *saddr, -+ struct in6_addr *daddr, -+ struct ipv6hdr *ip6h) -+{ -+ ip6h->version = 6; -+ ip6h->payload_len = 0; -+ ip6h->nexthdr = IPPROTO_TCP; -+ ip6h->saddr = *saddr; -+ ip6h->daddr = *daddr; -+} - - static int tcp_v6_send_synack(const struct sock *sk, struct dst_entry *dst, - struct flowi *fl, -@@ -540,6 +555,32 @@ static int tcp_v6_send_synack(const struct sock *sk, struct dst_entry *dst, - opt = ireq->ipv6_opt; - if (!opt) - opt = rcu_dereference(np->opt); -+ -+ if (DTRACE_TCP_ENABLED(send)) { -+ struct ipv6hdr ip6h; -+ -+ dtrace_tcp_build_ipv6hdr(&ireq->ir_v6_loc_addr, -+ &ireq->ir_v6_rmt_addr, &ip6h); -+ -+ /* Do not supply tcp sk - addresses/ports are not -+ * committed yet - instead translators will fill them -+ * in from IP/TCP data. -+ */ -+ DTRACE_TCP_NOCHECK(send, -+ struct sk_buff * : pktinfo_t *, -+ NULL, -+ struct sock * : csinfo_t *, sk, -+ __dtrace_tcp_void_ip_t * : -+ ipinfo_t *, &ip6h, -+ struct tcp_sock * : tcpsinfo_t *, -+ NULL, -+ struct tcphdr * : tcpinfo_t *, -+ tcp_hdr(skb), -+ int : tcplsinfo_t *, TCP_LISTEN, -+ int, TCP_LISTEN, -+ int, DTRACE_NET_PROBE_OUTBOUND); -+ } -+ - err = ip6_xmit(sk, skb, fl6, sk->sk_mark, opt, - tclass, sk->sk_priority); - rcu_read_unlock(); -@@ -969,6 +1010,49 @@ static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32 - dst = ip6_dst_lookup_flow(sock_net(ctl_sk), ctl_sk, &fl6, NULL); - if (!IS_ERR(dst)) { - skb_dst_set(buff, dst); -+ -+ if (DTRACE_TCP_ENABLED(send) || -+ DTRACE_TCP_ENABLED(accept__refused)) { -+ struct ipv6hdr ip6h; -+ -+ dtrace_tcp_build_ipv6hdr(&fl6.saddr, &fl6.daddr, -+ &ip6h); -+ -+ /* Do not supply tcp sk - addresses/ports are not -+ * committed yet - instead translators will fill them -+ * in from IP/TCP data. -+ */ -+ DTRACE_TCP_NOCHECK(send, -+ struct sk_buff * : pktinfo_t *, -+ NULL, -+ struct sock * : csinfo_t *, NULL, -+ __dtrace_tcp_void_ip_t * : -+ ipinfo_t *, &ip6h, -+ struct tcp_sock * : tcpsinfo_t *, -+ NULL, -+ struct tcphdr * : tcpinfo_t *, t1, -+ int : tcplsinfo_t *, TCP_CLOSE, -+ int, TCP_CLOSE, -+ int, DTRACE_NET_PROBE_OUTBOUND); -+ if (rst && th->syn && th->ack == 0) -+ DTRACE_TCP_NOCHECK(accept__refused, -+ struct sk_buff * : -+ pktinfo_t *, NULL, -+ struct sock * : csinfo_t *, -+ NULL, -+ __dtrace_tcp_void_ip_t * : -+ ipinfo_t *, &ip6h, -+ struct tcp_sock * : -+ tcpsinfo_t *, NULL, -+ struct tcphdr * : -+ tcpinfo_t *, t1, -+ int : tcplsinfo_t *, -+ TCP_CLOSE, -+ int, TCP_CLOSE, -+ int, -+ DTRACE_NET_PROBE_OUTBOUND); -+ } -+ - ip6_xmit(ctl_sk, buff, &fl6, fl6.flowi6_mark, NULL, - tclass & ~INET_ECN_MASK, priority); - TCP_INC_STATS(net, TCP_MIB_OUTSEGS); -@@ -1583,7 +1667,7 @@ INDIRECT_CALLABLE_SCOPE int tcp_v6_rcv(struct sk_buff *skb) - const struct tcphdr *th; - const struct ipv6hdr *hdr; - bool refcounted; -- struct sock *sk; -+ struct sock *sk = NULL; - int ret; - struct net *net = dev_net(skb->dev); - -@@ -1618,6 +1702,15 @@ INDIRECT_CALLABLE_SCOPE int tcp_v6_rcv(struct sk_buff *skb) - if (!sk) - goto no_tcp_socket; - -+ DTRACE_TCP(receive, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, sk, -+ __dtrace_tcp_void_ip_t * : ipinfo_t *, hdr, -+ struct tcp_sock * : tcpsinfo_t *, tcp_sk(sk), -+ struct tcphdr * : tcpinfo_t *, th, -+ int : tcplsinfo_t *, sk ? sk->sk_state : TCP_CLOSE, -+ int, sk ? sk->sk_state : TCP_CLOSE, -+ int, DTRACE_NET_PROBE_INBOUND); - process: - if (sk->sk_state == TCP_TIME_WAIT) - goto do_time_wait; -@@ -1737,6 +1830,18 @@ INDIRECT_CALLABLE_SCOPE int tcp_v6_rcv(struct sk_buff *skb) - } - - discard_it: -+ if (DTRACE_TCP_ENABLED(receive) && skb->pkt_type == PACKET_HOST) -+ DTRACE_TCP_NOCHECK(receive, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, sk, -+ __dtrace_tcp_void_ip_t * : ipinfo_t *, -+ ipv6_hdr(skb), -+ struct tcp_sock * : tcpsinfo_t *, tcp_sk(sk), -+ struct tcphdr * : tcpinfo_t *, tcp_hdr(skb), -+ int : tcplsinfo_t *, -+ sk ? sk->sk_state : TCP_CLOSE, -+ int, sk ? sk->sk_state : TCP_CLOSE, -+ int, DTRACE_NET_PROBE_INBOUND); - kfree_skb(skb); - return 0; - -diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c -index 29d9691359b9..996afe0fb057 100644 ---- a/net/ipv6/udp.c -+++ b/net/ipv6/udp.c -@@ -51,6 +51,7 @@ - - #include <linux/proc_fs.h> - #include <linux/seq_file.h> -+#include <linux/sdt.h> - #include <trace/events/skb.h> - #include "udp_impl.h" - -@@ -386,8 +387,15 @@ int udpv6_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, - kfree_skb(skb); - return err; - } -- if (!peeking) -+ if (!peeking) { - SNMP_INC_STATS(mib, UDP_MIB_INDATAGRAMS); -+ DTRACE_UDP(receive, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, sk, -+ void_ip_t * : ipinfo_t *, ip_hdr(skb), -+ struct udp_sock * : udpsinfo_t *, udp_sk(sk), -+ struct udphdr * : udpinfo_t *, udp_hdr(skb)); -+ } - - sock_recv_ts_and_drops(msg, sk, skb); - -@@ -685,6 +693,15 @@ static int udpv6_queue_rcv_one_skb(struct sock *sk, struct sk_buff *skb) - - ret = encap_rcv(sk, skb); - if (ret <= 0) { -+ DTRACE_UDP(receive, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, sk, -+ void_ip_t * : ipinfo_t *, -+ ip_hdr(skb), -+ struct udp_sock * : udpsinfo_t *, -+ udp_sk(sk), -+ struct udphdr * : udpinfo_t *, -+ udp_hdr(skb)); - __UDP_INC_STATS(sock_net(sk), - UDP_MIB_INDATAGRAMS, - is_udplite); -@@ -1238,6 +1255,13 @@ static int udp_v6_send_skb(struct sk_buff *skb, struct flowi6 *fl6, - err = 0; - } - } else { -+ DTRACE_UDP(send, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, sk, -+ void_ip_t * : ipinfo_t *, ip_hdr(skb), -+ struct udp_sock * : udpsinfo_t *, udp_sk(sk), -+ struct udphdr * : udpinfo_t *, uh); -+ - UDP6_INC_STATS(sock_net(sk), - UDP_MIB_OUTDATAGRAMS, is_udplite); - } --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/dtrace-patches/0018-dtrace-add-sample-script-for-building-DTrace-on-Fedo.patch b/sys-kernel/cairn-sources/files/5.10.13/dtrace-patches/0018-dtrace-add-sample-script-for-building-DTrace-on-Fedo.patch deleted file mode 100644 index a19e99b5fa67..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/dtrace-patches/0018-dtrace-add-sample-script-for-building-DTrace-on-Fedo.patch +++ /dev/null @@ -1,241 +0,0 @@ -From 6e49525673d614475c5e9b7b164bd48bad93b4a3 Mon Sep 17 00:00:00 2001 -From: Eugene Loh <eugene.loh@oracle.com> -Date: Mon, 12 Aug 2019 20:51:06 -0700 -Subject: [PATCH 18/19] dtrace: add sample script for building DTrace on Fedora - -Signed-off-by: Eugene Loh <eugene.loh@oracle.com> ---- - samples/dtrace/DTrace-on-Fedora.sh | 221 +++++++++++++++++++++++++++++ - 1 file changed, 221 insertions(+) - create mode 100755 samples/dtrace/DTrace-on-Fedora.sh - -diff --git a/samples/dtrace/DTrace-on-Fedora.sh b/samples/dtrace/DTrace-on-Fedora.sh -new file mode 100755 -index 000000000000..3857027381a5 ---- /dev/null -+++ b/samples/dtrace/DTrace-on-Fedora.sh -@@ -0,0 +1,221 @@ -+#!/bin/sh -+ -+# Oracle Linux DTrace. -+# Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. -+# Licensed under the Universal Permissive License v 1.0 as shown at -+# http://oss.oracle.com/licenses/upl. -+# -+ -+# Oracle has been working in recent years on porting DTrace, the -+# dynamic tracing tool, to Linux. DTrace offers easy-to-use, powerful, -+# safe, and unintrusive tracing. Oracle's initial focus was the Oracle -+# Unbreakable Enterprise Kernel (UEK), but DTrace runs on upstream Linux -+# kernels and other distributions' Linux kernels as well. Note that at -+# the moment, Oracle is in the process of upstreaming DTrace-related work -+# and reimplementing DTrace itself on top of existing kernel infrastructure -+# such as eBPF. -+ -+# This script illustrates how to build DTrace on Fedora on x86. -+# It is intended as a tutorial rather than a robust, turn-key utility. -+# Read and understand the steps as you execute them. The steps are -+# similar to what one does to build DTrace on other Linux distributions. -+ -+# Useful references on building a custom Fedora kernel include: -+# https://fedoraproject.org/wiki/Building_a_custom_kernel -+# https://fedoraproject.org/wiki/Building_a_custom_kernel#Building_Vanilla_upstream_kernel -+# Roughly speaking, you should have about 20 Gbyte of disk space -+# available and expect to wait a few hours for the build to complete. -+ -+# The overall process is: -+# 1. download and build the CTF library for DTrace to use -+# 2. download Fedora kernel source code -+# 3. prepare DTrace patches to apply -+# 4. prepare the kernel source code -+# a. Linux base code -+# b. apply Linux patches (if any) -+# c. apply Fedora patches -+# d. apply DTrace patches -+# e. prepare makefile and config -+# 5. build the kernel -+# 6. reboot -+# 7. download and build the DTrace userspace utility -+ -+ -+# pick one -+# DTrace patches change relatively infrequently. -+# So DTrace_branch might not have to match your Fedora kernel version exactly. -+#fedora_release=f29; DTrace_branch=5.2.7 ; num_DTrace_patches=19 -+ fedora_release=f30; DTrace_branch=5.2.7 ; num_DTrace_patches=19 -+ -+# Step 1: download and build the CTF library for DTrace to use -+ -+sudo dnf install -y git -+git clone https://github.com/oracle/libdtrace-ctf.git -+cd libdtrace-ctf -+sudo dnf builddep -y libdtrace-ctf.spec # install dependencies -+make -+sudo make install -+cd .. -+ -+# Step 2: download Fedora kernel source code -+ -+sudo dnf install -y fedora-packager -+fedpkg co -a kernel # anonymous clone of Fedora patches -+cd kernel -+git checkout origin/$fedora_release -+fedpkg sources # download tarballs of kernel sources -+sudo dnf builddep -y kernel.spec # install dependencies -+cd .. -+ -+# Step 3: prepare DTrace patches to apply -+ -+# download DTrace kernel code -+git clone https://github.com/oracle/dtrace-linux-kernel.git -+cd dtrace-linux-kernel/ -+git checkout origin/$DTrace_branch -+ -+# The DTrace patches will be the most recent commits. -+# Make sure you use all of them but nothing before that. -+# Make sure the top patches are DTrace -+# and the next one after them is the Linux baseline you want. -+# E.g., the top commits here are DTrace, and the last one is Linux upstream: -+# [...] -+# 66f76fef08e3 dtrace: modular components and x86 support -+# 25f11bb97fb9 dtrace: core and x86 -+# 3c5af76fa5fb waitfd: new syscall implementing waitpid() over fds -+# e95e4350d02b kallsyms: introduce new /proc/kallmodsyms including builtin modules too -+# 86e43efc644c ctf: generate CTF information for the kernel -+# a3b22b9f11d9 (tag: v5.0-rc7) Linux 5.0-rc7 -+git log -n $(($num_DTrace_patches + 1)) --oneline -+ -+# generate the DTrace patches -+git format-patch -$num_DTrace_patches -+ -+cd .. -+ -+# Step 4: prepare the kernel source code -+ -+# Step 4a: Linux base code -+ -+if [ -e kernel/linux-*.xz ]; then -+ /usr/bin/xz -dc kernel/linux-*.tar.xz | /usr/bin/tar -xof - -+else -+ tar xzf kernel/linux-*.tar.gz -+fi -+ -+# make a git repo so patches can be applied -+cd linux-* -+git init -+git config user.email "kernel-team@fedoraproject.org" -+git config user.name "Fedora Kernel Team" -+git config gc.auto 0 -+git add . -+git commit -a -q -m "baseline" -+ -+# Step 4b: apply Linux patches (if any) -+ -+if [ -e ../kernel/patch-*.xz ]; then -+ xzcat ../kernel/patch-*.xz | patch -p1 -F1 -s -+ git commit -a -m "Stable update" -+fi -+ -+# Step 4c: apply Fedora patches -+ -+for x in `awk '/^Patch/ {print $2}' ../kernel/kernel.spec`; do -+ git am ../kernel/$x -+done -+ -+# Step 4d: apply DTrace patches -+ -+for x in ../dtrace-linux-kernel/00*.patch; do -+ git am $x -+ if [ $? -ne 0 ]; then -+ echo DTrace patch did not apply cleanly -+ exit 1 -+ fi -+done -+ -+# Step 4e: prepare makefile and config -+ -+# modify the version tag in the Makefile -+sed -i.old \ -+ 's/^EXTRAVERSION =.*$/EXTRAVERSION = -200.DTrace_'$fedora_release'.x86_64/' \ -+ Makefile -+ -+# use the Fedora config file -+cp ../kernel/kernel-x86_64.config .config -+ -+# modify the config file for DTrace -+sed -i \ -+ -e 's/# CONFIG_UNWINDER_FRAME_POINTER is not set/CONFIG_UNWINDER_FRAME_POINTER=y/' \ -+ -e 's/CONFIG_UNWINDER_ORC=y/# CONFIG_UNWINDER_ORC is not set/' .config -+echo "CONFIG_DTRACE=y" >> .config -+echo "CONFIG_DT_CORE=m" >> .config -+echo "CONFIG_DT_FASTTRAP=m" >> .config -+echo "CONFIG_DT_PROFILE=m" >> .config -+echo "CONFIG_DT_SDT=m" >> .config -+echo "CONFIG_DT_SDT_PERF=y" >> .config -+echo "CONFIG_DT_FBT=m" >> .config -+echo "CONFIG_DT_SYSTRACE=m" >> .config -+echo "CONFIG_DT_DT_TEST=m" >> .config -+echo "CONFIG_DT_DT_PERF=m" >> .config -+echo "CONFIG_DT_DEBUG=y" >> .config -+echo "# CONFIG_DT_DEBUG_MUTEX is not set" >> .config -+ -+# Step 5: build the kernel -+ -+# (might take hours) -+make olddefconfig -+make -j4 -+make -j4 ctf -+ -+# install -+sudo make modules_install -+sudo make install -+sudo make INSTALL_HDR_PATH=/usr headers_install -+cd .. -+ -+# Step 6: reboot -+ -+sudo reboot -+ -+# Step 7: download and build the DTrace userspace utility -+ -+git clone https://github.com/oracle/dtrace-utils.git -+cd dtrace-utils -+ -+# The DTrace packages are missing from Fedora repos, -+# and we just built that software ourselves. -+# So eliminate those packages from the .spec file -+# before calling dnf builddep. -+sed -i.old \ -+ -e 's/-devel libdtrace-ctf-devel >= [0-9\.]*/-devel/' \ -+ -e '/^BuildRequires: dtrace-kernel-headers = [0-9\.]*$/d' dtrace-utils.spec -+sudo dnf builddep -y dtrace-utils.spec -+ -+make -+sudo make install -+cd .. -+ -+exit 0 -+ -+# Now, we can use DTrace on Fedora! (Notice that it is installed at /usr/sbin/dtrace. -+# Some other utility is at /usr/bin/dtrace.) You must be logged in as -+# root to use DTrace. The first thing to do is to list the available probes: -+# -+# # /usr/sbin/dtrace -l -+# ID PROVIDER MODULE FUNCTION NAME -+# 1 dtrace BEGIN -+# 2 dtrace END -+# 3 dtrace ERROR -+# 5 fbt isofs isofs_hashi entry -+# 6 fbt isofs isofs_hashi return -+# 7 fbt isofs isofs_statfs entry -+# 8 fbt isofs isofs_statfs return -+# 9 fbt isofs isofs_iget5_test entry -+# 10 fbt isofs isofs_iget5_test return -+# [...thousands of lines omitted...] -+# -+# Next, check out the Oracle DTrace Guide for simple examples and more information. -+# https://docs.oracle.com/cd/E52668_01/E38608/html/index.html -+ --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/dtrace-patches/0019-locking-publicize-mutex_owner-and-mutex_owned-again.patch b/sys-kernel/cairn-sources/files/5.10.13/dtrace-patches/0019-locking-publicize-mutex_owner-and-mutex_owned-again.patch deleted file mode 100644 index df04191dcf9d..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/dtrace-patches/0019-locking-publicize-mutex_owner-and-mutex_owned-again.patch +++ /dev/null @@ -1,86 +0,0 @@ -From cbc0fec32fc028d2e75a00f7a0609bc1960b02ee Mon Sep 17 00:00:00 2001 -From: Nick Alcock <nick.alcock@oracle.com> -Date: Mon, 9 Dec 2019 16:51:44 +0000 -Subject: [PATCH 19/19] locking: publicize mutex_owner and mutex_owned again - -DTrace uses both of them. - -Signed-off-by: Nick Alcock <nick.alcock@oracle.com> ---- - dtrace/dtrace_dif.c | 2 +- - include/linux/mutex.h | 16 +++++----------- - kernel/locking/mutex.c | 19 +++++++++++++++++++ - 3 files changed, 25 insertions(+), 12 deletions(-) - -diff --git a/dtrace/dtrace_dif.c b/dtrace/dtrace_dif.c -index ae7f01b4ed9b..798302d322a3 100644 ---- a/dtrace/dtrace_dif.c -+++ b/dtrace/dtrace_dif.c -@@ -2439,7 +2439,7 @@ static void dtrace_dif_subr(uint_t subr, uint_t rd, uint64_t *regs, - break; - - #ifdef CONFIG_SMP -- regs[rd] = (uintptr_t)__mutex_owner(&mtx); -+ regs[rd] = (uintptr_t)mutex_owner(&mtx); - #else - regs[rd] = 0; - #endif -diff --git a/include/linux/mutex.h b/include/linux/mutex.h -index bb18028db361..a1f15a42ea16 100644 ---- a/include/linux/mutex.h -+++ b/include/linux/mutex.h -@@ -228,16 +228,10 @@ enum mutex_trylock_recursive_enum { - extern /* __deprecated */ __must_check enum mutex_trylock_recursive_enum - mutex_trylock_recursive(struct mutex *lock); - --#if defined(CONFIG_DEBUG_MUTEXES) || defined(CONFIG_SMP) --static inline int mutex_owned(struct mutex *lock) --{ -- return mutex_is_locked(lock) && __mutex_owner(lock) == current; --} --#else --static inline int mutex_owned(struct mutex *lock) --{ -- return mutex_is_locked(lock); --} --#endif -+extern int -+mutex_owned(struct mutex *lock); -+ -+extern struct task_struct * -+mutex_owner(struct mutex *lock); - - #endif /* __LINUX_MUTEX_H */ -diff --git a/kernel/locking/mutex.c b/kernel/locking/mutex.c -index e784dd89d924..b856d7ffc51c 100644 ---- a/kernel/locking/mutex.c -+++ b/kernel/locking/mutex.c -@@ -97,6 +97,25 @@ mutex_trylock_recursive(struct mutex *lock) - } - EXPORT_SYMBOL(mutex_trylock_recursive); - -+struct task_struct *mutex_owner(struct mutex *lock) -+{ -+ return __mutex_owner (lock); -+} -+EXPORT_SYMBOL(mutex_owner); -+ -+#if defined(CONFIG_DEBUG_MUTEXES) || defined(CONFIG_SMP) -+int mutex_owned(struct mutex *lock) -+{ -+ return mutex_is_locked(lock) && __mutex_owner(lock) == current; -+} -+#else -+int mutex_owned(struct mutex *lock) -+{ -+ return mutex_is_locked(lock); -+} -+#endif -+EXPORT_SYMBOL(mutex_owned); -+ - static inline unsigned long __owner_flags(unsigned long owner) - { - return owner & MUTEX_FLAGS; --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/gentoo-patches/0000_README b/sys-kernel/cairn-sources/files/5.10.13/gentoo-patches/0000_README deleted file mode 100644 index fe8a77823d04..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/gentoo-patches/0000_README +++ /dev/null @@ -1,120 +0,0 @@ -README --------------------------------------------------------------------------- -This patchset is to be the series of patches for gentoo-sources. -It is designed for cross-compatibility, fixes and stability, with performance -and additional features/driver support being a second. - -Unless otherwise stated and marked as such, this kernel should be suitable for -all environments. - - -Patchset Numbering Scheme --------------------------------------------------------------------------- - -FIXES -1000-1400 linux-stable -1400-1500 linux-stable queue -1500-1700 security -1700-1800 architecture-related -1800-1900 mm/scheduling/misc -1900-2000 filesystems -2000-2100 networking core -2100-2200 storage core -2200-2300 power management (ACPI, APM) -2300-2400 bus (USB, IEEE1394, PCI, PCMCIA, ...) -2400-2500 network drivers -2500-2600 storage drivers -2600-2700 input -2700-2900 media (graphics, sound, tv) -2900-3000 other -3000-4000 reserved - -FEATURES -4000-4100 network -4100-4200 storage -4200-4300 graphics -4300-4400 filesystem -4400-4500 security enhancement -4500-4600 other - -EXPERIMENTAL -5000-5100 experimental patches (BFQ, ...) - -Individual Patch Descriptions: --------------------------------------------------------------------------- - -Patch: 1000_linux-5.10.1.patch -From: http://www.kernel.org -Desc: Linux 5.10.1 - -Patch: 1001_linux-5.10.2.patch -From: http://www.kernel.org -Desc: Linux 5.10.2 - -Patch: 1002_linux-5.10.3.patch -From: http://www.kernel.org -Desc: Linux 5.10.3 - -Patch: 1003_linux-5.10.4.patch -From: http://www.kernel.org -Desc: Linux 5.10.4 - -Patch: 1004_linux-5.10.5.patch -From: http://www.kernel.org -Desc: Linux 5.10.5 - -Patch: 1005_linux-5.10.6.patch -From: http://www.kernel.org -Desc: Linux 5.10.6 - -Patch: 1006_linux-5.10.7.patch -From: http://www.kernel.org -Desc: Linux 5.10.7 - -Patch: 1007_linux-5.10.8.patch -From: http://www.kernel.org -Desc: Linux 5.10.8 - -Patch: 1008_linux-5.10.9.patch -From: http://www.kernel.org -Desc: Linux 5.10.9 - -Patch: 1009_linux-5.10.10.patch -From: http://www.kernel.org -Desc: Linux 5.10.10 - -Patch: 1010_linux-5.10.11.patch -From: http://www.kernel.org -Desc: Linux 5.10.11 - -Patch: 1500_XATTR_USER_PREFIX.patch -From: https://bugs.gentoo.org/show_bug.cgi?id=470644 -Desc: Support for namespace user.pax.* on tmpfs. - -Patch: 1510_fs-enable-link-security-restrictions-by-default.patch -From: http://sources.debian.net/src/linux/3.16.7-ckt4-3/debian/patches/debian/fs-enable-link-security-restrictions-by-default.patch/ -Desc: Enable link security restrictions by default. - -Patch: 2000_BT-Check-key-sizes-only-if-Secure-Simple-Pairing-enabled.patch -From: https://lore.kernel.org/linux-bluetooth/20190522070540.48895-1-marcel@holtmann.org/raw -Desc: Bluetooth: Check key sizes only when Secure Simple Pairing is enabled. See bug #686758 - -Patch: 2900_tmp513-Fix-build-issue-by-selecting-CONFIG_REG.patch -From: https://bugs.gentoo.org/710790 -Desc: tmp513 requies REGMAP_I2C to build. Select it by default in Kconfig. See bug #710790. Thanks to Phil Stracchino - -Patch: 2920_sign-file-patch-for-libressl.patch -From: https://bugs.gentoo.org/717166 -Desc: sign-file: full functionality with modern LibreSSL - -Patch: 4567_distro-Gentoo-Kconfig.patch -From: Tom Wijsman <TomWij@gentoo.org> -Desc: Add Gentoo Linux support config settings and defaults. - -Patch: 5000_shifts-ubuntu-20.04.patch -From: https://git.launchpad.net/~ubuntu-kernel/ubuntu/+source/linux/+git/focal -Desc: UID/GID shifting overlay filesystem for containers - -Patch: 5013_enable-cpu-optimizations-for-gcc10.patch -From: https://github.com/graysky2/kernel_gcc_patch/ -Desc: Kernel patch enables gcc = v10.1+ optimizations for additional CPUs. diff --git a/sys-kernel/cairn-sources/files/5.10.13/gentoo-patches/1500_XATTR_USER_PREFIX.patch b/sys-kernel/cairn-sources/files/5.10.13/gentoo-patches/1500_XATTR_USER_PREFIX.patch deleted file mode 100644 index 245dcc29fa56..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/gentoo-patches/1500_XATTR_USER_PREFIX.patch +++ /dev/null @@ -1,67 +0,0 @@ -From: Anthony G. Basile <blueness@gentoo.org> - -This patch adds support for a restricted user-controlled namespace on -tmpfs filesystem used to house PaX flags. The namespace must be of the -form user.pax.* and its value cannot exceed a size of 8 bytes. - -This is needed even on all Gentoo systems so that XATTR_PAX flags -are preserved for users who might build packages using portage on -a tmpfs system with a non-hardened kernel and then switch to a -hardened kernel with XATTR_PAX enabled. - -The namespace is added to any user with Extended Attribute support -enabled for tmpfs. Users who do not enable xattrs will not have -the XATTR_PAX flags preserved. - -diff --git a/include/uapi/linux/xattr.h b/include/uapi/linux/xattr.h -index 1590c49..5eab462 100644 ---- a/include/uapi/linux/xattr.h -+++ b/include/uapi/linux/xattr.h -@@ -73,5 +73,9 @@ - #define XATTR_POSIX_ACL_DEFAULT "posix_acl_default" - #define XATTR_NAME_POSIX_ACL_DEFAULT XATTR_SYSTEM_PREFIX XATTR_POSIX_ACL_DEFAULT - -+/* User namespace */ -+#define XATTR_PAX_PREFIX XATTR_USER_PREFIX "pax." -+#define XATTR_PAX_FLAGS_SUFFIX "flags" -+#define XATTR_NAME_PAX_FLAGS XATTR_PAX_PREFIX XATTR_PAX_FLAGS_SUFFIX - - #endif /* _UAPI_LINUX_XATTR_H */ ---- a/mm/shmem.c 2020-05-04 15:30:27.042035334 -0400 -+++ b/mm/shmem.c 2020-05-04 15:34:57.013881725 -0400 -@@ -3238,6 +3238,14 @@ static int shmem_xattr_handler_set(const - struct shmem_inode_info *info = SHMEM_I(inode); - - name = xattr_full_name(handler, name); -+ -+ if (!strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)) { -+ if (strcmp(name, XATTR_NAME_PAX_FLAGS)) -+ return -EOPNOTSUPP; -+ if (size > 8) -+ return -EINVAL; -+ } -+ - return simple_xattr_set(&info->xattrs, name, value, size, flags, NULL); - } - -@@ -3253,6 +3261,12 @@ static const struct xattr_handler shmem_ - .set = shmem_xattr_handler_set, - }; - -+static const struct xattr_handler shmem_user_xattr_handler = { -+ .prefix = XATTR_USER_PREFIX, -+ .get = shmem_xattr_handler_get, -+ .set = shmem_xattr_handler_set, -+}; -+ - static const struct xattr_handler *shmem_xattr_handlers[] = { - #ifdef CONFIG_TMPFS_POSIX_ACL - &posix_acl_access_xattr_handler, -@@ -3260,6 +3274,7 @@ static const struct xattr_handler *shmem - #endif - &shmem_security_xattr_handler, - &shmem_trusted_xattr_handler, -+ &shmem_user_xattr_handler, - NULL - }; - diff --git a/sys-kernel/cairn-sources/files/5.10.13/gentoo-patches/1510_fs-enable-link-security-restrictions-by-default.patch b/sys-kernel/cairn-sources/files/5.10.13/gentoo-patches/1510_fs-enable-link-security-restrictions-by-default.patch deleted file mode 100644 index f0ed144fb17a..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/gentoo-patches/1510_fs-enable-link-security-restrictions-by-default.patch +++ /dev/null @@ -1,20 +0,0 @@ -From: Ben Hutchings <ben@decadent.org.uk> -Subject: fs: Enable link security restrictions by default -Date: Fri, 02 Nov 2012 05:32:06 +0000 -Bug-Debian: https://bugs.debian.org/609455 -Forwarded: not-needed -This reverts commit 561ec64ae67ef25cac8d72bb9c4bfc955edfd415 -('VFS: don't do protected {sym,hard}links by default'). ---- a/fs/namei.c 2018-09-28 07:56:07.770005006 -0400 -+++ b/fs/namei.c 2018-09-28 07:56:43.370349204 -0400 -@@ -885,8 +885,8 @@ static inline void put_link(struct namei - path_put(&last->link); - } - --int sysctl_protected_symlinks __read_mostly = 0; --int sysctl_protected_hardlinks __read_mostly = 0; -+int sysctl_protected_symlinks __read_mostly = 1; -+int sysctl_protected_hardlinks __read_mostly = 1; - int sysctl_protected_fifos __read_mostly; - int sysctl_protected_regular __read_mostly; - diff --git a/sys-kernel/cairn-sources/files/5.10.13/gentoo-patches/2000_BT-Check-key-sizes-only-if-Secure-Simple-Pairing-enabled.patch b/sys-kernel/cairn-sources/files/5.10.13/gentoo-patches/2000_BT-Check-key-sizes-only-if-Secure-Simple-Pairing-enabled.patch deleted file mode 100644 index 394ad48fc20c..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/gentoo-patches/2000_BT-Check-key-sizes-only-if-Secure-Simple-Pairing-enabled.patch +++ /dev/null @@ -1,37 +0,0 @@ -The encryption is only mandatory to be enforced when both sides are using -Secure Simple Pairing and this means the key size check makes only sense -in that case. - -On legacy Bluetooth 2.0 and earlier devices like mice the encryption was -optional and thus causing an issue if the key size check is not bound to -using Secure Simple Pairing. - -Fixes: d5bb334a8e17 ("Bluetooth: Align minimum encryption key size for LE and BR/EDR connections") -Signed-off-by: Marcel Holtmann <marcel@holtmann.org> -Cc: stable@vger.kernel.org ---- - net/bluetooth/hci_conn.c | 9 +++++++-- - 1 file changed, 7 insertions(+), 2 deletions(-) - -diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c -index 3cf0764d5793..7516cdde3373 100644 ---- a/net/bluetooth/hci_conn.c -+++ b/net/bluetooth/hci_conn.c -@@ -1272,8 +1272,13 @@ int hci_conn_check_link_mode(struct hci_conn *conn) - return 0; - } - -- if (hci_conn_ssp_enabled(conn) && -- !test_bit(HCI_CONN_ENCRYPT, &conn->flags)) -+ /* If Secure Simple Pairing is not enabled, then legacy connection -+ * setup is used and no encryption or key sizes can be enforced. -+ */ -+ if (!hci_conn_ssp_enabled(conn)) -+ return 1; -+ -+ if (!test_bit(HCI_CONN_ENCRYPT, &conn->flags)) - return 0; - - /* The minimum encryption key size needs to be enforced by the --- -2.20.1 diff --git a/sys-kernel/cairn-sources/files/5.10.13/gentoo-patches/2900_tmp513-Fix-build-issue-by-selecting-CONFIG_REG.patch b/sys-kernel/cairn-sources/files/5.10.13/gentoo-patches/2900_tmp513-Fix-build-issue-by-selecting-CONFIG_REG.patch deleted file mode 100644 index 433568579cab..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/gentoo-patches/2900_tmp513-Fix-build-issue-by-selecting-CONFIG_REG.patch +++ /dev/null @@ -1,30 +0,0 @@ -From dc328d75a6f37f4ff11a81ae16b1ec88c3197640 Mon Sep 17 00:00:00 2001 -From: Mike Pagano <mpagano@gentoo.org> -Date: Mon, 23 Mar 2020 08:20:06 -0400 -Subject: [PATCH 1/1] This driver requires REGMAP_I2C to build. Select it by - default in Kconfig. Reported at gentoo bugzilla: - https://bugs.gentoo.org/710790 -Cc: mpagano@gentoo.org - -Reported-by: Phil Stracchino <phils@caerllewys.net> - -Signed-off-by: Mike Pagano <mpagano@gentoo.org> ---- - drivers/hwmon/Kconfig | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig -index 47ac20aee06f..530b4f29ba85 100644 ---- a/drivers/hwmon/Kconfig -+++ b/drivers/hwmon/Kconfig -@@ -1769,6 +1769,7 @@ config SENSORS_TMP421 - config SENSORS_TMP513 - tristate "Texas Instruments TMP513 and compatibles" - depends on I2C -+ select REGMAP_I2C - help - If you say yes here you get support for Texas Instruments TMP512, - and TMP513 temperature and power supply sensor chips. --- -2.24.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/gentoo-patches/2920_sign-file-patch-for-libressl.patch b/sys-kernel/cairn-sources/files/5.10.13/gentoo-patches/2920_sign-file-patch-for-libressl.patch deleted file mode 100644 index e6ec017d46c8..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/gentoo-patches/2920_sign-file-patch-for-libressl.patch +++ /dev/null @@ -1,16 +0,0 @@ ---- a/scripts/sign-file.c 2020-05-20 18:47:21.282820662 -0400 -+++ b/scripts/sign-file.c 2020-05-20 18:48:37.991081899 -0400 -@@ -41,9 +41,10 @@ - * signing with anything other than SHA1 - so we're stuck with that if such is - * the case. - */ --#if defined(LIBRESSL_VERSION_NUMBER) || \ -- OPENSSL_VERSION_NUMBER < 0x10000000L || \ -- defined(OPENSSL_NO_CMS) -+#if defined(OPENSSL_NO_CMS) || \ -+ ( defined(LIBRESSL_VERSION_NUMBER) \ -+ && (LIBRESSL_VERSION_NUMBER < 0x3010000fL) ) || \ -+ OPENSSL_VERSION_NUMBER < 0x10000000L - #define USE_PKCS7 - #endif - #ifndef USE_PKCS7 diff --git a/sys-kernel/cairn-sources/files/5.10.13/gentoo-patches/4567_distro-Gentoo-Kconfig.patch b/sys-kernel/cairn-sources/files/5.10.13/gentoo-patches/4567_distro-Gentoo-Kconfig.patch deleted file mode 100644 index e754a3e6e459..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/gentoo-patches/4567_distro-Gentoo-Kconfig.patch +++ /dev/null @@ -1,169 +0,0 @@ ---- a/Kconfig 2020-04-15 11:05:30.202413863 -0400 -+++ b/Kconfig 2020-04-15 10:37:45.683952949 -0400 -@@ -32,3 +32,5 @@ source "lib/Kconfig" - source "lib/Kconfig.debug" - - source "Documentation/Kconfig" -+ -+source "distro/Kconfig" ---- /dev/null 2020-09-24 03:06:47.590000000 -0400 -+++ b/distro/Kconfig 2020-09-24 11:31:29.403150624 -0400 -@@ -0,0 +1,158 @@ -+menu "Gentoo Linux" -+ -+config GENTOO_LINUX -+ bool "Gentoo Linux support" -+ -+ default y -+ -+ help -+ In order to boot Gentoo Linux a minimal set of config settings needs to -+ be enabled in the kernel; to avoid the users from having to enable them -+ manually as part of a Gentoo Linux installation or a new clean config, -+ we enable these config settings by default for convenience. -+ -+ See the settings that become available for more details and fine-tuning. -+ -+config GENTOO_LINUX_UDEV -+ bool "Linux dynamic and persistent device naming (userspace devfs) support" -+ -+ depends on GENTOO_LINUX -+ default y if GENTOO_LINUX -+ -+ select DEVTMPFS -+ select TMPFS -+ select UNIX -+ -+ select MMU -+ select SHMEM -+ -+ help -+ In order to boot Gentoo Linux a minimal set of config settings needs to -+ be enabled in the kernel; to avoid the users from having to enable them -+ manually as part of a Gentoo Linux installation or a new clean config, -+ we enable these config settings by default for convenience. -+ -+ Currently this only selects TMPFS, DEVTMPFS and their dependencies. -+ TMPFS is enabled to maintain a tmpfs file system at /dev/shm, /run and -+ /sys/fs/cgroup; DEVTMPFS to maintain a devtmpfs file system at /dev. -+ -+ Some of these are critical files that need to be available early in the -+ boot process; if not available, it causes sysfs and udev to malfunction. -+ -+ To ensure Gentoo Linux boots, it is best to leave this setting enabled; -+ if you run a custom setup, you could consider whether to disable this. -+ -+config GENTOO_LINUX_PORTAGE -+ bool "Select options required by Portage features" -+ -+ depends on GENTOO_LINUX -+ default y if GENTOO_LINUX -+ -+ select CGROUPS -+ select NAMESPACES -+ select IPC_NS -+ select NET_NS -+ select PID_NS -+ select SYSVIPC -+ select UTS_NS -+ -+ help -+ This enables options required by various Portage FEATURES. -+ Currently this selects: -+ -+ CGROUPS (required for FEATURES=cgroup) -+ IPC_NS (required for FEATURES=ipc-sandbox) -+ NET_NS (required for FEATURES=network-sandbox) -+ PID_NS (required for FEATURES=pid-sandbox) -+ SYSVIPC (required by IPC_NS) -+ -+ -+ It is highly recommended that you leave this enabled as these FEATURES -+ are, or will soon be, enabled by default. -+ -+menu "Support for init systems, system and service managers" -+ visible if GENTOO_LINUX -+ -+config GENTOO_LINUX_INIT_SCRIPT -+ bool "OpenRC, runit and other script based systems and managers" -+ -+ default y if GENTOO_LINUX -+ -+ depends on GENTOO_LINUX -+ -+ select BINFMT_SCRIPT -+ select CGROUPS -+ select EPOLL -+ select FILE_LOCKING -+ select INOTIFY_USER -+ select SIGNALFD -+ select TIMERFD -+ -+ help -+ The init system is the first thing that loads after the kernel booted. -+ -+ These config settings allow you to select which init systems to support; -+ instead of having to select all the individual settings all over the -+ place, these settings allows you to select all the settings at once. -+ -+ This particular setting enables all the known requirements for OpenRC, -+ runit and similar script based systems and managers. -+ -+ If you are unsure about this, it is best to leave this setting enabled. -+ -+config GENTOO_LINUX_INIT_SYSTEMD -+ bool "systemd" -+ -+ default n -+ -+ depends on GENTOO_LINUX && GENTOO_LINUX_UDEV -+ -+ select AUTOFS4_FS -+ select BLK_DEV_BSG -+ select BPF_SYSCALL -+ select CGROUP_BPF -+ select CGROUPS -+ select CHECKPOINT_RESTORE -+ select CRYPTO_HMAC -+ select CRYPTO_SHA256 -+ select CRYPTO_USER_API_HASH -+ select DEVPTS_MULTIPLE_INSTANCES -+ select DMIID if X86_32 || X86_64 || X86 -+ select EPOLL -+ select FANOTIFY -+ select FHANDLE -+ select FILE_LOCKING -+ select INOTIFY_USER -+ select IPV6 -+ select NET -+ select NET_NS -+ select PROC_FS -+ select SECCOMP -+ select SECCOMP_FILTER -+ select SIGNALFD -+ select SYSFS -+ select TIMERFD -+ select TMPFS_POSIX_ACL -+ select TMPFS_XATTR -+ select USER_NS -+ -+ select ANON_INODES -+ select BLOCK -+ select EVENTFD -+ select FSNOTIFY -+ select INET -+ select NLATTR -+ -+ help -+ The init system is the first thing that loads after the kernel booted. -+ -+ These config settings allow you to select which init systems to support; -+ instead of having to select all the individual settings all over the -+ place, these settings allows you to select all the settings at once. -+ -+ This particular setting enables all the known requirements for systemd; -+ it also enables suggested optional settings, as the package suggests to. -+ -+endmenu -+ -+endmenu diff --git a/sys-kernel/cairn-sources/files/5.10.13/gentoo-patches/5000_shiftfs-ubuntu-20.04.patch b/sys-kernel/cairn-sources/files/5.10.13/gentoo-patches/5000_shiftfs-ubuntu-20.04.patch deleted file mode 100644 index 665fc660b0de..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/gentoo-patches/5000_shiftfs-ubuntu-20.04.patch +++ /dev/null @@ -1,2203 +0,0 @@ ---- /dev/null 2021-01-08 13:33:13.190303432 -0500 -+++ b/fs/shiftfs.c 2021-01-08 19:02:40.000000000 -0500 -@@ -0,0 +1,2157 @@ -+#include <linux/btrfs.h> -+#include <linux/capability.h> -+#include <linux/cred.h> -+#include <linux/mount.h> -+#include <linux/fdtable.h> -+#include <linux/file.h> -+#include <linux/fs.h> -+#include <linux/namei.h> -+#include <linux/module.h> -+#include <linux/kernel.h> -+#include <linux/magic.h> -+#include <linux/parser.h> -+#include <linux/security.h> -+#include <linux/seq_file.h> -+#include <linux/statfs.h> -+#include <linux/slab.h> -+#include <linux/user_namespace.h> -+#include <linux/uidgid.h> -+#include <linux/xattr.h> -+#include <linux/posix_acl.h> -+#include <linux/posix_acl_xattr.h> -+#include <linux/uio.h> -+#include <linux/fiemap.h> -+ -+struct shiftfs_super_info { -+ struct vfsmount *mnt; -+ struct user_namespace *userns; -+ /* creds of process who created the super block */ -+ const struct cred *creator_cred; -+ bool mark; -+ unsigned int passthrough; -+ unsigned int passthrough_mark; -+}; -+ -+static void shiftfs_fill_inode(struct inode *inode, unsigned long ino, -+ umode_t mode, dev_t dev, struct dentry *dentry); -+ -+#define SHIFTFS_PASSTHROUGH_NONE 0 -+#define SHIFTFS_PASSTHROUGH_STAT 1 -+#define SHIFTFS_PASSTHROUGH_IOCTL 2 -+#define SHIFTFS_PASSTHROUGH_ALL \ -+ (SHIFTFS_PASSTHROUGH_STAT | SHIFTFS_PASSTHROUGH_IOCTL) -+ -+static inline bool shiftfs_passthrough_ioctls(struct shiftfs_super_info *info) -+{ -+ if (!(info->passthrough & SHIFTFS_PASSTHROUGH_IOCTL)) -+ return false; -+ -+ return true; -+} -+ -+static inline bool shiftfs_passthrough_statfs(struct shiftfs_super_info *info) -+{ -+ if (!(info->passthrough & SHIFTFS_PASSTHROUGH_STAT)) -+ return false; -+ -+ return true; -+} -+ -+enum { -+ OPT_MARK, -+ OPT_PASSTHROUGH, -+ OPT_LAST, -+}; -+ -+/* global filesystem options */ -+static const match_table_t tokens = { -+ { OPT_MARK, "mark" }, -+ { OPT_PASSTHROUGH, "passthrough=%u" }, -+ { OPT_LAST, NULL } -+}; -+ -+static const struct cred *shiftfs_override_creds(const struct super_block *sb) -+{ -+ struct shiftfs_super_info *sbinfo = sb->s_fs_info; -+ -+ return override_creds(sbinfo->creator_cred); -+} -+ -+static inline void shiftfs_revert_object_creds(const struct cred *oldcred, -+ struct cred *newcred) -+{ -+ revert_creds(oldcred); -+ put_cred(newcred); -+} -+ -+static kuid_t shift_kuid(struct user_namespace *from, struct user_namespace *to, -+ kuid_t kuid) -+{ -+ uid_t uid = from_kuid(from, kuid); -+ return make_kuid(to, uid); -+} -+ -+static kgid_t shift_kgid(struct user_namespace *from, struct user_namespace *to, -+ kgid_t kgid) -+{ -+ gid_t gid = from_kgid(from, kgid); -+ return make_kgid(to, gid); -+} -+ -+static int shiftfs_override_object_creds(const struct super_block *sb, -+ const struct cred **oldcred, -+ struct cred **newcred, -+ struct dentry *dentry, umode_t mode, -+ bool hardlink) -+{ -+ struct shiftfs_super_info *sbinfo = sb->s_fs_info; -+ kuid_t fsuid = current_fsuid(); -+ kgid_t fsgid = current_fsgid(); -+ -+ *oldcred = shiftfs_override_creds(sb); -+ -+ *newcred = prepare_creds(); -+ if (!*newcred) { -+ revert_creds(*oldcred); -+ return -ENOMEM; -+ } -+ -+ (*newcred)->fsuid = shift_kuid(sb->s_user_ns, sbinfo->userns, fsuid); -+ (*newcred)->fsgid = shift_kgid(sb->s_user_ns, sbinfo->userns, fsgid); -+ -+ if (!hardlink) { -+ int err = security_dentry_create_files_as(dentry, mode, -+ &dentry->d_name, -+ *oldcred, *newcred); -+ if (err) { -+ shiftfs_revert_object_creds(*oldcred, *newcred); -+ return err; -+ } -+ } -+ -+ put_cred(override_creds(*newcred)); -+ return 0; -+} -+ -+static void shiftfs_copyattr(struct inode *from, struct inode *to) -+{ -+ struct user_namespace *from_ns = from->i_sb->s_user_ns; -+ struct user_namespace *to_ns = to->i_sb->s_user_ns; -+ -+ to->i_uid = shift_kuid(from_ns, to_ns, from->i_uid); -+ to->i_gid = shift_kgid(from_ns, to_ns, from->i_gid); -+ to->i_mode = from->i_mode; -+ to->i_atime = from->i_atime; -+ to->i_mtime = from->i_mtime; -+ to->i_ctime = from->i_ctime; -+ i_size_write(to, i_size_read(from)); -+} -+ -+static void shiftfs_copyflags(struct inode *from, struct inode *to) -+{ -+ unsigned int mask = S_SYNC | S_IMMUTABLE | S_APPEND | S_NOATIME; -+ -+ inode_set_flags(to, from->i_flags & mask, mask); -+} -+ -+static void shiftfs_file_accessed(struct file *file) -+{ -+ struct inode *upperi, *loweri; -+ -+ if (file->f_flags & O_NOATIME) -+ return; -+ -+ upperi = file_inode(file); -+ loweri = upperi->i_private; -+ -+ if (!loweri) -+ return; -+ -+ upperi->i_mtime = loweri->i_mtime; -+ upperi->i_ctime = loweri->i_ctime; -+ -+ touch_atime(&file->f_path); -+} -+ -+static int shiftfs_parse_mount_options(struct shiftfs_super_info *sbinfo, -+ char *options) -+{ -+ char *p; -+ substring_t args[MAX_OPT_ARGS]; -+ -+ sbinfo->mark = false; -+ sbinfo->passthrough = 0; -+ -+ while ((p = strsep(&options, ",")) != NULL) { -+ int err, intarg, token; -+ -+ if (!*p) -+ continue; -+ -+ token = match_token(p, tokens, args); -+ switch (token) { -+ case OPT_MARK: -+ sbinfo->mark = true; -+ break; -+ case OPT_PASSTHROUGH: -+ err = match_int(&args[0], &intarg); -+ if (err) -+ return err; -+ -+ if (intarg & ~SHIFTFS_PASSTHROUGH_ALL) -+ return -EINVAL; -+ -+ sbinfo->passthrough = intarg; -+ break; -+ default: -+ return -EINVAL; -+ } -+ } -+ -+ return 0; -+} -+ -+static void shiftfs_d_release(struct dentry *dentry) -+{ -+ struct dentry *lowerd = dentry->d_fsdata; -+ -+ if (lowerd) -+ dput(lowerd); -+} -+ -+static struct dentry *shiftfs_d_real(struct dentry *dentry, -+ const struct inode *inode) -+{ -+ struct dentry *lowerd = dentry->d_fsdata; -+ -+ if (inode && d_inode(dentry) == inode) -+ return dentry; -+ -+ lowerd = d_real(lowerd, inode); -+ if (lowerd && (!inode || inode == d_inode(lowerd))) -+ return lowerd; -+ -+ WARN(1, "shiftfs_d_real(%pd4, %s:%lu): real dentry not found\n", dentry, -+ inode ? inode->i_sb->s_id : "NULL", inode ? inode->i_ino : 0); -+ return dentry; -+} -+ -+static int shiftfs_d_weak_revalidate(struct dentry *dentry, unsigned int flags) -+{ -+ int err = 1; -+ struct dentry *lowerd = dentry->d_fsdata; -+ -+ if (d_is_negative(lowerd) != d_is_negative(dentry)) -+ return 0; -+ -+ if ((lowerd->d_flags & DCACHE_OP_WEAK_REVALIDATE)) -+ err = lowerd->d_op->d_weak_revalidate(lowerd, flags); -+ -+ if (d_really_is_positive(dentry)) { -+ struct inode *inode = d_inode(dentry); -+ struct inode *loweri = d_inode(lowerd); -+ -+ shiftfs_copyattr(loweri, inode); -+ } -+ -+ return err; -+} -+ -+static int shiftfs_d_revalidate(struct dentry *dentry, unsigned int flags) -+{ -+ int err = 1; -+ struct dentry *lowerd = dentry->d_fsdata; -+ -+ if (d_unhashed(lowerd) || -+ ((d_is_negative(lowerd) != d_is_negative(dentry)))) -+ return 0; -+ -+ if (flags & LOOKUP_RCU) -+ return -ECHILD; -+ -+ if ((lowerd->d_flags & DCACHE_OP_REVALIDATE)) -+ err = lowerd->d_op->d_revalidate(lowerd, flags); -+ -+ if (d_really_is_positive(dentry)) { -+ struct inode *inode = d_inode(dentry); -+ struct inode *loweri = d_inode(lowerd); -+ -+ shiftfs_copyattr(loweri, inode); -+ } -+ -+ return err; -+} -+ -+static const struct dentry_operations shiftfs_dentry_ops = { -+ .d_release = shiftfs_d_release, -+ .d_real = shiftfs_d_real, -+ .d_revalidate = shiftfs_d_revalidate, -+ .d_weak_revalidate = shiftfs_d_weak_revalidate, -+}; -+ -+static const char *shiftfs_get_link(struct dentry *dentry, struct inode *inode, -+ struct delayed_call *done) -+{ -+ const char *p; -+ const struct cred *oldcred; -+ struct dentry *lowerd; -+ -+ /* RCU lookup not supported */ -+ if (!dentry) -+ return ERR_PTR(-ECHILD); -+ -+ lowerd = dentry->d_fsdata; -+ oldcred = shiftfs_override_creds(dentry->d_sb); -+ p = vfs_get_link(lowerd, done); -+ revert_creds(oldcred); -+ -+ return p; -+} -+ -+static int shiftfs_setxattr(struct dentry *dentry, struct inode *inode, -+ const char *name, const void *value, -+ size_t size, int flags) -+{ -+ struct dentry *lowerd = dentry->d_fsdata; -+ int err; -+ const struct cred *oldcred; -+ -+ oldcred = shiftfs_override_creds(dentry->d_sb); -+ err = vfs_setxattr(lowerd, name, value, size, flags); -+ revert_creds(oldcred); -+ -+ shiftfs_copyattr(lowerd->d_inode, inode); -+ -+ return err; -+} -+ -+static int shiftfs_xattr_get(const struct xattr_handler *handler, -+ struct dentry *dentry, struct inode *inode, -+ const char *name, void *value, size_t size) -+{ -+ struct dentry *lowerd = dentry->d_fsdata; -+ int err; -+ const struct cred *oldcred; -+ -+ oldcred = shiftfs_override_creds(dentry->d_sb); -+ err = vfs_getxattr(lowerd, name, value, size); -+ revert_creds(oldcred); -+ -+ return err; -+} -+ -+static ssize_t shiftfs_listxattr(struct dentry *dentry, char *list, -+ size_t size) -+{ -+ struct dentry *lowerd = dentry->d_fsdata; -+ int err; -+ const struct cred *oldcred; -+ -+ oldcred = shiftfs_override_creds(dentry->d_sb); -+ err = vfs_listxattr(lowerd, list, size); -+ revert_creds(oldcred); -+ -+ return err; -+} -+ -+static int shiftfs_removexattr(struct dentry *dentry, const char *name) -+{ -+ struct dentry *lowerd = dentry->d_fsdata; -+ int err; -+ const struct cred *oldcred; -+ -+ oldcred = shiftfs_override_creds(dentry->d_sb); -+ err = vfs_removexattr(lowerd, name); -+ revert_creds(oldcred); -+ -+ /* update c/mtime */ -+ shiftfs_copyattr(lowerd->d_inode, d_inode(dentry)); -+ -+ return err; -+} -+ -+static int shiftfs_xattr_set(const struct xattr_handler *handler, -+ struct dentry *dentry, struct inode *inode, -+ const char *name, const void *value, size_t size, -+ int flags) -+{ -+ if (!value) -+ return shiftfs_removexattr(dentry, name); -+ return shiftfs_setxattr(dentry, inode, name, value, size, flags); -+} -+ -+static int shiftfs_inode_test(struct inode *inode, void *data) -+{ -+ return inode->i_private == data; -+} -+ -+static int shiftfs_inode_set(struct inode *inode, void *data) -+{ -+ inode->i_private = data; -+ return 0; -+} -+ -+static int shiftfs_create_object(struct inode *diri, struct dentry *dentry, -+ umode_t mode, const char *symlink, -+ struct dentry *hardlink, bool excl) -+{ -+ int err; -+ const struct cred *oldcred; -+ struct cred *newcred; -+ void *loweri_iop_ptr = NULL; -+ umode_t modei = mode; -+ struct super_block *dir_sb = diri->i_sb; -+ struct dentry *lowerd_new = dentry->d_fsdata; -+ struct inode *inode = NULL, *loweri_dir = diri->i_private; -+ const struct inode_operations *loweri_dir_iop = loweri_dir->i_op; -+ struct dentry *lowerd_link = NULL; -+ -+ if (hardlink) { -+ loweri_iop_ptr = loweri_dir_iop->link; -+ } else { -+ switch (mode & S_IFMT) { -+ case S_IFDIR: -+ loweri_iop_ptr = loweri_dir_iop->mkdir; -+ break; -+ case S_IFREG: -+ loweri_iop_ptr = loweri_dir_iop->create; -+ break; -+ case S_IFLNK: -+ loweri_iop_ptr = loweri_dir_iop->symlink; -+ break; -+ case S_IFSOCK: -+ /* fall through */ -+ case S_IFIFO: -+ loweri_iop_ptr = loweri_dir_iop->mknod; -+ break; -+ } -+ } -+ if (!loweri_iop_ptr) { -+ err = -EINVAL; -+ goto out_iput; -+ } -+ -+ inode_lock_nested(loweri_dir, I_MUTEX_PARENT); -+ -+ if (!hardlink) { -+ inode = new_inode(dir_sb); -+ if (!inode) { -+ err = -ENOMEM; -+ goto out_iput; -+ } -+ -+ /* -+ * new_inode() will have added the new inode to the super -+ * block's list of inodes. Further below we will call -+ * inode_insert5() Which would perform the same operation again -+ * thereby corrupting the list. To avoid this raise I_CREATING -+ * in i_state which will cause inode_insert5() to skip this -+ * step. I_CREATING will be cleared by d_instantiate_new() -+ * below. -+ */ -+ spin_lock(&inode->i_lock); -+ inode->i_state |= I_CREATING; -+ spin_unlock(&inode->i_lock); -+ -+ inode_init_owner(inode, diri, mode); -+ modei = inode->i_mode; -+ } -+ -+ err = shiftfs_override_object_creds(dentry->d_sb, &oldcred, &newcred, -+ dentry, modei, hardlink != NULL); -+ if (err) -+ goto out_iput; -+ -+ if (hardlink) { -+ lowerd_link = hardlink->d_fsdata; -+ err = vfs_link(lowerd_link, loweri_dir, lowerd_new, NULL); -+ } else { -+ switch (modei & S_IFMT) { -+ case S_IFDIR: -+ err = vfs_mkdir(loweri_dir, lowerd_new, modei); -+ break; -+ case S_IFREG: -+ err = vfs_create(loweri_dir, lowerd_new, modei, excl); -+ break; -+ case S_IFLNK: -+ err = vfs_symlink(loweri_dir, lowerd_new, symlink); -+ break; -+ case S_IFSOCK: -+ /* fall through */ -+ case S_IFIFO: -+ err = vfs_mknod(loweri_dir, lowerd_new, modei, 0); -+ break; -+ default: -+ err = -EINVAL; -+ break; -+ } -+ } -+ -+ shiftfs_revert_object_creds(oldcred, newcred); -+ -+ if (!err && WARN_ON(!lowerd_new->d_inode)) -+ err = -EIO; -+ if (err) -+ goto out_iput; -+ -+ if (hardlink) { -+ inode = d_inode(hardlink); -+ ihold(inode); -+ -+ /* copy up times from lower inode */ -+ shiftfs_copyattr(d_inode(lowerd_link), inode); -+ set_nlink(d_inode(hardlink), d_inode(lowerd_link)->i_nlink); -+ d_instantiate(dentry, inode); -+ } else { -+ struct inode *inode_tmp; -+ struct inode *loweri_new = d_inode(lowerd_new); -+ -+ inode_tmp = inode_insert5(inode, (unsigned long)loweri_new, -+ shiftfs_inode_test, shiftfs_inode_set, -+ loweri_new); -+ if (unlikely(inode_tmp != inode)) { -+ pr_err_ratelimited("shiftfs: newly created inode found in cache\n"); -+ iput(inode_tmp); -+ err = -EINVAL; -+ goto out_iput; -+ } -+ -+ ihold(loweri_new); -+ shiftfs_fill_inode(inode, loweri_new->i_ino, loweri_new->i_mode, -+ 0, lowerd_new); -+ d_instantiate_new(dentry, inode); -+ } -+ -+ shiftfs_copyattr(loweri_dir, diri); -+ if (loweri_iop_ptr == loweri_dir_iop->mkdir) -+ set_nlink(diri, loweri_dir->i_nlink); -+ -+ inode = NULL; -+ -+out_iput: -+ iput(inode); -+ inode_unlock(loweri_dir); -+ -+ return err; -+} -+ -+static int shiftfs_create(struct inode *dir, struct dentry *dentry, -+ umode_t mode, bool excl) -+{ -+ mode |= S_IFREG; -+ -+ return shiftfs_create_object(dir, dentry, mode, NULL, NULL, excl); -+} -+ -+static int shiftfs_mkdir(struct inode *dir, struct dentry *dentry, -+ umode_t mode) -+{ -+ mode |= S_IFDIR; -+ -+ return shiftfs_create_object(dir, dentry, mode, NULL, NULL, false); -+} -+ -+static int shiftfs_link(struct dentry *hardlink, struct inode *dir, -+ struct dentry *dentry) -+{ -+ return shiftfs_create_object(dir, dentry, 0, NULL, hardlink, false); -+} -+ -+static int shiftfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, -+ dev_t rdev) -+{ -+ if (!S_ISFIFO(mode) && !S_ISSOCK(mode)) -+ return -EPERM; -+ -+ return shiftfs_create_object(dir, dentry, mode, NULL, NULL, false); -+} -+ -+static int shiftfs_symlink(struct inode *dir, struct dentry *dentry, -+ const char *symlink) -+{ -+ return shiftfs_create_object(dir, dentry, S_IFLNK, symlink, NULL, false); -+} -+ -+static int shiftfs_rm(struct inode *dir, struct dentry *dentry, bool rmdir) -+{ -+ struct dentry *lowerd = dentry->d_fsdata; -+ struct inode *loweri = dir->i_private; -+ struct inode *inode = d_inode(dentry); -+ int err; -+ const struct cred *oldcred; -+ -+ dget(lowerd); -+ oldcred = shiftfs_override_creds(dentry->d_sb); -+ inode_lock_nested(loweri, I_MUTEX_PARENT); -+ if (rmdir) -+ err = vfs_rmdir(loweri, lowerd); -+ else -+ err = vfs_unlink(loweri, lowerd, NULL); -+ revert_creds(oldcred); -+ -+ if (!err) { -+ d_drop(dentry); -+ -+ if (rmdir) -+ clear_nlink(inode); -+ else -+ drop_nlink(inode); -+ } -+ inode_unlock(loweri); -+ -+ shiftfs_copyattr(loweri, dir); -+ dput(lowerd); -+ -+ return err; -+} -+ -+static int shiftfs_unlink(struct inode *dir, struct dentry *dentry) -+{ -+ return shiftfs_rm(dir, dentry, false); -+} -+ -+static int shiftfs_rmdir(struct inode *dir, struct dentry *dentry) -+{ -+ return shiftfs_rm(dir, dentry, true); -+} -+ -+static int shiftfs_rename(struct inode *olddir, struct dentry *old, -+ struct inode *newdir, struct dentry *new, -+ unsigned int flags) -+{ -+ struct dentry *lowerd_dir_old = old->d_parent->d_fsdata, -+ *lowerd_dir_new = new->d_parent->d_fsdata, -+ *lowerd_old = old->d_fsdata, *lowerd_new = new->d_fsdata, -+ *trapd; -+ struct inode *loweri_dir_old = lowerd_dir_old->d_inode, -+ *loweri_dir_new = lowerd_dir_new->d_inode; -+ int err = -EINVAL; -+ const struct cred *oldcred; -+ -+ trapd = lock_rename(lowerd_dir_new, lowerd_dir_old); -+ -+ if (trapd == lowerd_old || trapd == lowerd_new) -+ goto out_unlock; -+ -+ oldcred = shiftfs_override_creds(old->d_sb); -+ err = vfs_rename(loweri_dir_old, lowerd_old, loweri_dir_new, lowerd_new, -+ NULL, flags); -+ revert_creds(oldcred); -+ -+ shiftfs_copyattr(loweri_dir_old, olddir); -+ shiftfs_copyattr(loweri_dir_new, newdir); -+ -+out_unlock: -+ unlock_rename(lowerd_dir_new, lowerd_dir_old); -+ -+ return err; -+} -+ -+static struct dentry *shiftfs_lookup(struct inode *dir, struct dentry *dentry, -+ unsigned int flags) -+{ -+ struct dentry *new; -+ struct inode *newi; -+ const struct cred *oldcred; -+ struct dentry *lowerd = dentry->d_parent->d_fsdata; -+ struct inode *inode = NULL, *loweri = lowerd->d_inode; -+ -+ inode_lock(loweri); -+ oldcred = shiftfs_override_creds(dentry->d_sb); -+ new = lookup_one_len(dentry->d_name.name, lowerd, dentry->d_name.len); -+ revert_creds(oldcred); -+ inode_unlock(loweri); -+ -+ if (IS_ERR(new)) -+ return new; -+ -+ dentry->d_fsdata = new; -+ -+ newi = new->d_inode; -+ if (!newi) -+ goto out; -+ -+ inode = iget5_locked(dentry->d_sb, (unsigned long)newi, -+ shiftfs_inode_test, shiftfs_inode_set, newi); -+ if (!inode) { -+ dput(new); -+ return ERR_PTR(-ENOMEM); -+ } -+ if (inode->i_state & I_NEW) { -+ /* -+ * inode->i_private set by shiftfs_inode_set(), but we still -+ * need to take a reference -+ */ -+ ihold(newi); -+ shiftfs_fill_inode(inode, newi->i_ino, newi->i_mode, 0, new); -+ unlock_new_inode(inode); -+ } -+ -+out: -+ return d_splice_alias(inode, dentry); -+} -+ -+static int shiftfs_permission(struct inode *inode, int mask) -+{ -+ int err; -+ const struct cred *oldcred; -+ struct inode *loweri = inode->i_private; -+ -+ if (!loweri) { -+ WARN_ON(!(mask & MAY_NOT_BLOCK)); -+ return -ECHILD; -+ } -+ -+ err = generic_permission(inode, mask); -+ if (err) -+ return err; -+ -+ oldcred = shiftfs_override_creds(inode->i_sb); -+ err = inode_permission(loweri, mask); -+ revert_creds(oldcred); -+ -+ return err; -+} -+ -+static int shiftfs_fiemap(struct inode *inode, -+ struct fiemap_extent_info *fieinfo, u64 start, -+ u64 len) -+{ -+ int err; -+ const struct cred *oldcred; -+ struct inode *loweri = inode->i_private; -+ -+ if (!loweri->i_op->fiemap) -+ return -EOPNOTSUPP; -+ -+ oldcred = shiftfs_override_creds(inode->i_sb); -+ if (fieinfo->fi_flags & FIEMAP_FLAG_SYNC) -+ filemap_write_and_wait(loweri->i_mapping); -+ err = loweri->i_op->fiemap(loweri, fieinfo, start, len); -+ revert_creds(oldcred); -+ -+ return err; -+} -+ -+static int shiftfs_tmpfile(struct inode *dir, struct dentry *dentry, -+ umode_t mode) -+{ -+ int err; -+ const struct cred *oldcred; -+ struct dentry *lowerd = dentry->d_fsdata; -+ struct inode *loweri = dir->i_private; -+ -+ if (!loweri->i_op->tmpfile) -+ return -EOPNOTSUPP; -+ -+ oldcred = shiftfs_override_creds(dir->i_sb); -+ err = loweri->i_op->tmpfile(loweri, lowerd, mode); -+ revert_creds(oldcred); -+ -+ return err; -+} -+ -+static int shiftfs_setattr(struct dentry *dentry, struct iattr *attr) -+{ -+ struct dentry *lowerd = dentry->d_fsdata; -+ struct inode *loweri = lowerd->d_inode; -+ struct iattr newattr; -+ const struct cred *oldcred; -+ struct super_block *sb = dentry->d_sb; -+ struct shiftfs_super_info *sbinfo = sb->s_fs_info; -+ int err; -+ -+ err = setattr_prepare(dentry, attr); -+ if (err) -+ return err; -+ -+ newattr = *attr; -+ newattr.ia_uid = shift_kuid(sb->s_user_ns, sbinfo->userns, attr->ia_uid); -+ newattr.ia_gid = shift_kgid(sb->s_user_ns, sbinfo->userns, attr->ia_gid); -+ -+ /* -+ * mode change is for clearing setuid/setgid bits. Allow lower fs -+ * to interpret this in its own way. -+ */ -+ if (newattr.ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID)) -+ newattr.ia_valid &= ~ATTR_MODE; -+ -+ inode_lock(loweri); -+ oldcred = shiftfs_override_creds(dentry->d_sb); -+ err = notify_change(lowerd, &newattr, NULL); -+ revert_creds(oldcred); -+ inode_unlock(loweri); -+ -+ shiftfs_copyattr(loweri, d_inode(dentry)); -+ -+ return err; -+} -+ -+static int shiftfs_getattr(const struct path *path, struct kstat *stat, -+ u32 request_mask, unsigned int query_flags) -+{ -+ struct inode *inode = path->dentry->d_inode; -+ struct dentry *lowerd = path->dentry->d_fsdata; -+ struct inode *loweri = lowerd->d_inode; -+ struct shiftfs_super_info *info = path->dentry->d_sb->s_fs_info; -+ struct path newpath = { .mnt = info->mnt, .dentry = lowerd }; -+ struct user_namespace *from_ns = loweri->i_sb->s_user_ns; -+ struct user_namespace *to_ns = inode->i_sb->s_user_ns; -+ const struct cred *oldcred; -+ int err; -+ -+ oldcred = shiftfs_override_creds(inode->i_sb); -+ err = vfs_getattr(&newpath, stat, request_mask, query_flags); -+ revert_creds(oldcred); -+ -+ if (err) -+ return err; -+ -+ /* transform the underlying id */ -+ stat->uid = shift_kuid(from_ns, to_ns, stat->uid); -+ stat->gid = shift_kgid(from_ns, to_ns, stat->gid); -+ return 0; -+} -+ -+#ifdef CONFIG_SHIFT_FS_POSIX_ACL -+ -+static int -+shift_acl_ids(struct user_namespace *from, struct user_namespace *to, -+ struct posix_acl *acl) -+{ -+ int i; -+ -+ for (i = 0; i < acl->a_count; i++) { -+ struct posix_acl_entry *e = &acl->a_entries[i]; -+ switch(e->e_tag) { -+ case ACL_USER: -+ e->e_uid = shift_kuid(from, to, e->e_uid); -+ if (!uid_valid(e->e_uid)) -+ return -EOVERFLOW; -+ break; -+ case ACL_GROUP: -+ e->e_gid = shift_kgid(from, to, e->e_gid); -+ if (!gid_valid(e->e_gid)) -+ return -EOVERFLOW; -+ break; -+ } -+ } -+ return 0; -+} -+ -+static void -+shift_acl_xattr_ids(struct user_namespace *from, struct user_namespace *to, -+ void *value, size_t size) -+{ -+ struct posix_acl_xattr_header *header = value; -+ struct posix_acl_xattr_entry *entry = (void *)(header + 1), *end; -+ int count; -+ kuid_t kuid; -+ kgid_t kgid; -+ -+ if (!value) -+ return; -+ if (size < sizeof(struct posix_acl_xattr_header)) -+ return; -+ if (header->a_version != cpu_to_le32(POSIX_ACL_XATTR_VERSION)) -+ return; -+ -+ count = posix_acl_xattr_count(size); -+ if (count < 0) -+ return; -+ if (count == 0) -+ return; -+ -+ for (end = entry + count; entry != end; entry++) { -+ switch(le16_to_cpu(entry->e_tag)) { -+ case ACL_USER: -+ kuid = make_kuid(&init_user_ns, le32_to_cpu(entry->e_id)); -+ kuid = shift_kuid(from, to, kuid); -+ entry->e_id = cpu_to_le32(from_kuid(&init_user_ns, kuid)); -+ break; -+ case ACL_GROUP: -+ kgid = make_kgid(&init_user_ns, le32_to_cpu(entry->e_id)); -+ kgid = shift_kgid(from, to, kgid); -+ entry->e_id = cpu_to_le32(from_kgid(&init_user_ns, kgid)); -+ break; -+ default: -+ break; -+ } -+ } -+} -+ -+static struct posix_acl *shiftfs_get_acl(struct inode *inode, int type) -+{ -+ struct inode *loweri = inode->i_private; -+ const struct cred *oldcred; -+ struct posix_acl *lower_acl, *acl = NULL; -+ struct user_namespace *from_ns = loweri->i_sb->s_user_ns; -+ struct user_namespace *to_ns = inode->i_sb->s_user_ns; -+ int size; -+ int err; -+ -+ if (!IS_POSIXACL(loweri)) -+ return NULL; -+ -+ oldcred = shiftfs_override_creds(inode->i_sb); -+ lower_acl = get_acl(loweri, type); -+ revert_creds(oldcred); -+ -+ if (lower_acl && !IS_ERR(lower_acl)) { -+ /* XXX: export posix_acl_clone? */ -+ size = sizeof(struct posix_acl) + -+ lower_acl->a_count * sizeof(struct posix_acl_entry); -+ acl = kmemdup(lower_acl, size, GFP_KERNEL); -+ posix_acl_release(lower_acl); -+ -+ if (!acl) -+ return ERR_PTR(-ENOMEM); -+ -+ refcount_set(&acl->a_refcount, 1); -+ -+ err = shift_acl_ids(from_ns, to_ns, acl); -+ if (err) { -+ kfree(acl); -+ return ERR_PTR(err); -+ } -+ } -+ -+ return acl; -+} -+ -+static int -+shiftfs_posix_acl_xattr_get(const struct xattr_handler *handler, -+ struct dentry *dentry, struct inode *inode, -+ const char *name, void *buffer, size_t size) -+{ -+ struct inode *loweri = inode->i_private; -+ int ret; -+ -+ ret = shiftfs_xattr_get(NULL, dentry, inode, handler->name, -+ buffer, size); -+ if (ret < 0) -+ return ret; -+ -+ inode_lock(loweri); -+ shift_acl_xattr_ids(loweri->i_sb->s_user_ns, inode->i_sb->s_user_ns, -+ buffer, size); -+ inode_unlock(loweri); -+ return ret; -+} -+ -+static int -+shiftfs_posix_acl_xattr_set(const struct xattr_handler *handler, -+ struct dentry *dentry, struct inode *inode, -+ const char *name, const void *value, -+ size_t size, int flags) -+{ -+ struct inode *loweri = inode->i_private; -+ int err; -+ -+ if (!IS_POSIXACL(loweri) || !loweri->i_op->set_acl) -+ return -EOPNOTSUPP; -+ if (handler->flags == ACL_TYPE_DEFAULT && !S_ISDIR(inode->i_mode)) -+ return value ? -EACCES : 0; -+ if (!inode_owner_or_capable(inode)) -+ return -EPERM; -+ -+ if (value) { -+ shift_acl_xattr_ids(inode->i_sb->s_user_ns, -+ loweri->i_sb->s_user_ns, -+ (void *)value, size); -+ err = shiftfs_setxattr(dentry, inode, handler->name, value, -+ size, flags); -+ } else { -+ err = shiftfs_removexattr(dentry, handler->name); -+ } -+ -+ if (!err) -+ shiftfs_copyattr(loweri, inode); -+ -+ return err; -+} -+ -+static const struct xattr_handler -+shiftfs_posix_acl_access_xattr_handler = { -+ .name = XATTR_NAME_POSIX_ACL_ACCESS, -+ .flags = ACL_TYPE_ACCESS, -+ .get = shiftfs_posix_acl_xattr_get, -+ .set = shiftfs_posix_acl_xattr_set, -+}; -+ -+static const struct xattr_handler -+shiftfs_posix_acl_default_xattr_handler = { -+ .name = XATTR_NAME_POSIX_ACL_DEFAULT, -+ .flags = ACL_TYPE_DEFAULT, -+ .get = shiftfs_posix_acl_xattr_get, -+ .set = shiftfs_posix_acl_xattr_set, -+}; -+ -+#else /* !CONFIG_SHIFT_FS_POSIX_ACL */ -+ -+#define shiftfs_get_acl NULL -+ -+#endif /* CONFIG_SHIFT_FS_POSIX_ACL */ -+ -+static const struct inode_operations shiftfs_dir_inode_operations = { -+ .lookup = shiftfs_lookup, -+ .mkdir = shiftfs_mkdir, -+ .symlink = shiftfs_symlink, -+ .unlink = shiftfs_unlink, -+ .rmdir = shiftfs_rmdir, -+ .rename = shiftfs_rename, -+ .link = shiftfs_link, -+ .setattr = shiftfs_setattr, -+ .create = shiftfs_create, -+ .mknod = shiftfs_mknod, -+ .permission = shiftfs_permission, -+ .getattr = shiftfs_getattr, -+ .listxattr = shiftfs_listxattr, -+ .get_acl = shiftfs_get_acl, -+}; -+ -+static const struct inode_operations shiftfs_file_inode_operations = { -+ .fiemap = shiftfs_fiemap, -+ .getattr = shiftfs_getattr, -+ .get_acl = shiftfs_get_acl, -+ .listxattr = shiftfs_listxattr, -+ .permission = shiftfs_permission, -+ .setattr = shiftfs_setattr, -+ .tmpfile = shiftfs_tmpfile, -+}; -+ -+static const struct inode_operations shiftfs_special_inode_operations = { -+ .getattr = shiftfs_getattr, -+ .get_acl = shiftfs_get_acl, -+ .listxattr = shiftfs_listxattr, -+ .permission = shiftfs_permission, -+ .setattr = shiftfs_setattr, -+}; -+ -+static const struct inode_operations shiftfs_symlink_inode_operations = { -+ .getattr = shiftfs_getattr, -+ .get_link = shiftfs_get_link, -+ .listxattr = shiftfs_listxattr, -+ .setattr = shiftfs_setattr, -+}; -+ -+static struct file *shiftfs_open_realfile(const struct file *file, -+ struct inode *realinode) -+{ -+ struct file *realfile; -+ const struct cred *old_cred; -+ struct inode *inode = file_inode(file); -+ struct dentry *lowerd = file->f_path.dentry->d_fsdata; -+ struct shiftfs_super_info *info = inode->i_sb->s_fs_info; -+ struct path realpath = { .mnt = info->mnt, .dentry = lowerd }; -+ -+ old_cred = shiftfs_override_creds(inode->i_sb); -+ realfile = open_with_fake_path(&realpath, file->f_flags, realinode, -+ info->creator_cred); -+ revert_creds(old_cred); -+ -+ return realfile; -+} -+ -+#define SHIFTFS_SETFL_MASK (O_APPEND | O_NONBLOCK | O_NDELAY | O_DIRECT) -+ -+static int shiftfs_change_flags(struct file *file, unsigned int flags) -+{ -+ struct inode *inode = file_inode(file); -+ int err; -+ -+ /* if some flag changed that cannot be changed then something's amiss */ -+ if (WARN_ON((file->f_flags ^ flags) & ~SHIFTFS_SETFL_MASK)) -+ return -EIO; -+ -+ flags &= SHIFTFS_SETFL_MASK; -+ -+ if (((flags ^ file->f_flags) & O_APPEND) && IS_APPEND(inode)) -+ return -EPERM; -+ -+ if (flags & O_DIRECT) { -+ if (!file->f_mapping->a_ops || -+ !file->f_mapping->a_ops->direct_IO) -+ return -EINVAL; -+ } -+ -+ if (file->f_op->check_flags) { -+ err = file->f_op->check_flags(flags); -+ if (err) -+ return err; -+ } -+ -+ spin_lock(&file->f_lock); -+ file->f_flags = (file->f_flags & ~SHIFTFS_SETFL_MASK) | flags; -+ spin_unlock(&file->f_lock); -+ -+ return 0; -+} -+ -+static int shiftfs_open(struct inode *inode, struct file *file) -+{ -+ struct file *realfile; -+ -+ realfile = shiftfs_open_realfile(file, inode->i_private); -+ if (IS_ERR(realfile)) -+ return PTR_ERR(realfile); -+ -+ file->private_data = realfile; -+ /* For O_DIRECT dentry_open() checks f_mapping->a_ops->direct_IO. */ -+ file->f_mapping = realfile->f_mapping; -+ -+ return 0; -+} -+ -+static int shiftfs_dir_open(struct inode *inode, struct file *file) -+{ -+ struct file *realfile; -+ const struct cred *oldcred; -+ struct dentry *lowerd = file->f_path.dentry->d_fsdata; -+ struct shiftfs_super_info *info = inode->i_sb->s_fs_info; -+ struct path realpath = { .mnt = info->mnt, .dentry = lowerd }; -+ -+ oldcred = shiftfs_override_creds(file->f_path.dentry->d_sb); -+ realfile = dentry_open(&realpath, file->f_flags | O_NOATIME, -+ info->creator_cred); -+ revert_creds(oldcred); -+ if (IS_ERR(realfile)) -+ return PTR_ERR(realfile); -+ -+ file->private_data = realfile; -+ -+ return 0; -+} -+ -+static int shiftfs_release(struct inode *inode, struct file *file) -+{ -+ struct file *realfile = file->private_data; -+ -+ if (realfile) -+ fput(realfile); -+ -+ return 0; -+} -+ -+static int shiftfs_dir_release(struct inode *inode, struct file *file) -+{ -+ return shiftfs_release(inode, file); -+} -+ -+static loff_t shiftfs_dir_llseek(struct file *file, loff_t offset, int whence) -+{ -+ struct file *realfile = file->private_data; -+ -+ return vfs_llseek(realfile, offset, whence); -+} -+ -+static loff_t shiftfs_file_llseek(struct file *file, loff_t offset, int whence) -+{ -+ struct inode *realinode = file_inode(file)->i_private; -+ -+ return generic_file_llseek_size(file, offset, whence, -+ realinode->i_sb->s_maxbytes, -+ i_size_read(realinode)); -+} -+ -+/* XXX: Need to figure out what to to about atime updates, maybe other -+ * timestamps too ... ref. ovl_file_accessed() */ -+ -+static rwf_t shiftfs_iocb_to_rwf(struct kiocb *iocb) -+{ -+ int ifl = iocb->ki_flags; -+ rwf_t flags = 0; -+ -+ if (ifl & IOCB_NOWAIT) -+ flags |= RWF_NOWAIT; -+ if (ifl & IOCB_HIPRI) -+ flags |= RWF_HIPRI; -+ if (ifl & IOCB_DSYNC) -+ flags |= RWF_DSYNC; -+ if (ifl & IOCB_SYNC) -+ flags |= RWF_SYNC; -+ -+ return flags; -+} -+ -+static int shiftfs_real_fdget(const struct file *file, struct fd *lowerfd) -+{ -+ struct file *realfile; -+ -+ if (file->f_op->open != shiftfs_open && -+ file->f_op->open != shiftfs_dir_open) -+ return -EINVAL; -+ -+ realfile = file->private_data; -+ lowerfd->flags = 0; -+ lowerfd->file = realfile; -+ -+ /* Did the flags change since open? */ -+ if (unlikely(file->f_flags & ~lowerfd->file->f_flags)) -+ return shiftfs_change_flags(lowerfd->file, file->f_flags); -+ -+ return 0; -+} -+ -+static ssize_t shiftfs_read_iter(struct kiocb *iocb, struct iov_iter *iter) -+{ -+ struct file *file = iocb->ki_filp; -+ struct fd lowerfd; -+ const struct cred *oldcred; -+ ssize_t ret; -+ -+ if (!iov_iter_count(iter)) -+ return 0; -+ -+ ret = shiftfs_real_fdget(file, &lowerfd); -+ if (ret) -+ return ret; -+ -+ oldcred = shiftfs_override_creds(file->f_path.dentry->d_sb); -+ ret = vfs_iter_read(lowerfd.file, iter, &iocb->ki_pos, -+ shiftfs_iocb_to_rwf(iocb)); -+ revert_creds(oldcred); -+ -+ shiftfs_file_accessed(file); -+ -+ fdput(lowerfd); -+ return ret; -+} -+ -+static ssize_t shiftfs_write_iter(struct kiocb *iocb, struct iov_iter *iter) -+{ -+ struct file *file = iocb->ki_filp; -+ struct inode *inode = file_inode(file); -+ struct fd lowerfd; -+ const struct cred *oldcred; -+ ssize_t ret; -+ -+ if (!iov_iter_count(iter)) -+ return 0; -+ -+ inode_lock(inode); -+ /* Update mode */ -+ shiftfs_copyattr(inode->i_private, inode); -+ ret = file_remove_privs(file); -+ if (ret) -+ goto out_unlock; -+ -+ ret = shiftfs_real_fdget(file, &lowerfd); -+ if (ret) -+ goto out_unlock; -+ -+ oldcred = shiftfs_override_creds(file->f_path.dentry->d_sb); -+ file_start_write(lowerfd.file); -+ ret = vfs_iter_write(lowerfd.file, iter, &iocb->ki_pos, -+ shiftfs_iocb_to_rwf(iocb)); -+ file_end_write(lowerfd.file); -+ revert_creds(oldcred); -+ -+ /* Update size */ -+ shiftfs_copyattr(inode->i_private, inode); -+ -+ fdput(lowerfd); -+ -+out_unlock: -+ inode_unlock(inode); -+ return ret; -+} -+ -+static int shiftfs_fsync(struct file *file, loff_t start, loff_t end, -+ int datasync) -+{ -+ struct fd lowerfd; -+ const struct cred *oldcred; -+ int ret; -+ -+ ret = shiftfs_real_fdget(file, &lowerfd); -+ if (ret) -+ return ret; -+ -+ oldcred = shiftfs_override_creds(file->f_path.dentry->d_sb); -+ ret = vfs_fsync_range(lowerfd.file, start, end, datasync); -+ revert_creds(oldcred); -+ -+ fdput(lowerfd); -+ return ret; -+} -+ -+static int shiftfs_mmap(struct file *file, struct vm_area_struct *vma) -+{ -+ struct file *realfile = file->private_data; -+ const struct cred *oldcred; -+ int ret; -+ -+ if (!realfile->f_op->mmap) -+ return -ENODEV; -+ -+ if (WARN_ON(file != vma->vm_file)) -+ return -EIO; -+ -+ oldcred = shiftfs_override_creds(file->f_path.dentry->d_sb); -+ vma->vm_file = get_file(realfile); -+ ret = call_mmap(vma->vm_file, vma); -+ revert_creds(oldcred); -+ -+ shiftfs_file_accessed(file); -+ -+ if (ret) { -+ /* -+ * Drop refcount from new vm_file value and restore original -+ * vm_file value -+ */ -+ vma->vm_file = file; -+ fput(realfile); -+ } else { -+ /* Drop refcount from previous vm_file value */ -+ fput(file); -+ } -+ -+ return ret; -+} -+ -+static long shiftfs_fallocate(struct file *file, int mode, loff_t offset, -+ loff_t len) -+{ -+ struct inode *inode = file_inode(file); -+ struct inode *loweri = inode->i_private; -+ struct fd lowerfd; -+ const struct cred *oldcred; -+ int ret; -+ -+ ret = shiftfs_real_fdget(file, &lowerfd); -+ if (ret) -+ return ret; -+ -+ oldcred = shiftfs_override_creds(file->f_path.dentry->d_sb); -+ ret = vfs_fallocate(lowerfd.file, mode, offset, len); -+ revert_creds(oldcred); -+ -+ /* Update size */ -+ shiftfs_copyattr(loweri, inode); -+ -+ fdput(lowerfd); -+ return ret; -+} -+ -+static int shiftfs_fadvise(struct file *file, loff_t offset, loff_t len, -+ int advice) -+{ -+ struct fd lowerfd; -+ const struct cred *oldcred; -+ int ret; -+ -+ ret = shiftfs_real_fdget(file, &lowerfd); -+ if (ret) -+ return ret; -+ -+ oldcred = shiftfs_override_creds(file->f_path.dentry->d_sb); -+ ret = vfs_fadvise(lowerfd.file, offset, len, advice); -+ revert_creds(oldcred); -+ -+ fdput(lowerfd); -+ return ret; -+} -+ -+static int shiftfs_override_ioctl_creds(int cmd, const struct super_block *sb, -+ const struct cred **oldcred, -+ struct cred **newcred) -+{ -+ struct shiftfs_super_info *sbinfo = sb->s_fs_info; -+ kuid_t fsuid = current_fsuid(); -+ kgid_t fsgid = current_fsgid(); -+ -+ *oldcred = shiftfs_override_creds(sb); -+ -+ *newcred = prepare_creds(); -+ if (!*newcred) { -+ revert_creds(*oldcred); -+ return -ENOMEM; -+ } -+ -+ (*newcred)->fsuid = shift_kuid(sb->s_user_ns, sbinfo->userns, fsuid); -+ (*newcred)->fsgid = shift_kgid(sb->s_user_ns, sbinfo->userns, fsgid); -+ -+ /* clear all caps to prevent bypassing capable() checks */ -+ cap_clear((*newcred)->cap_bset); -+ cap_clear((*newcred)->cap_effective); -+ cap_clear((*newcred)->cap_inheritable); -+ cap_clear((*newcred)->cap_permitted); -+ -+ if (cmd == BTRFS_IOC_SNAP_DESTROY) { -+ kuid_t kuid_root = make_kuid(sb->s_user_ns, 0); -+ /* -+ * Allow the root user in the container to remove subvolumes -+ * from other users. -+ */ -+ if (uid_valid(kuid_root) && uid_eq(fsuid, kuid_root)) -+ cap_raise((*newcred)->cap_effective, CAP_DAC_OVERRIDE); -+ } -+ -+ put_cred(override_creds(*newcred)); -+ return 0; -+} -+ -+static inline void shiftfs_revert_ioctl_creds(const struct cred *oldcred, -+ struct cred *newcred) -+{ -+ return shiftfs_revert_object_creds(oldcred, newcred); -+} -+ -+static inline bool is_btrfs_snap_ioctl(int cmd) -+{ -+ if ((cmd == BTRFS_IOC_SNAP_CREATE) || (cmd == BTRFS_IOC_SNAP_CREATE_V2)) -+ return true; -+ -+ return false; -+} -+ -+static int shiftfs_btrfs_ioctl_fd_restore(int cmd, int fd, void __user *arg, -+ struct btrfs_ioctl_vol_args *v1, -+ struct btrfs_ioctl_vol_args_v2 *v2) -+{ -+ int ret; -+ -+ if (!is_btrfs_snap_ioctl(cmd)) -+ return 0; -+ -+ if (cmd == BTRFS_IOC_SNAP_CREATE) -+ ret = copy_to_user(arg, v1, sizeof(*v1)); -+ else -+ ret = copy_to_user(arg, v2, sizeof(*v2)); -+ -+ __close_fd(current->files, fd); -+ kfree(v1); -+ kfree(v2); -+ -+ return ret; -+} -+ -+static int shiftfs_btrfs_ioctl_fd_replace(int cmd, void __user *arg, -+ struct btrfs_ioctl_vol_args **b1, -+ struct btrfs_ioctl_vol_args_v2 **b2, -+ int *newfd) -+{ -+ int oldfd, ret; -+ struct fd src; -+ struct fd lfd = {}; -+ struct btrfs_ioctl_vol_args *v1 = NULL; -+ struct btrfs_ioctl_vol_args_v2 *v2 = NULL; -+ -+ if (!is_btrfs_snap_ioctl(cmd)) -+ return 0; -+ -+ if (cmd == BTRFS_IOC_SNAP_CREATE) { -+ v1 = memdup_user(arg, sizeof(*v1)); -+ if (IS_ERR(v1)) -+ return PTR_ERR(v1); -+ oldfd = v1->fd; -+ *b1 = v1; -+ } else { -+ v2 = memdup_user(arg, sizeof(*v2)); -+ if (IS_ERR(v2)) -+ return PTR_ERR(v2); -+ oldfd = v2->fd; -+ *b2 = v2; -+ } -+ -+ src = fdget(oldfd); -+ if (!src.file) -+ return -EINVAL; -+ -+ ret = shiftfs_real_fdget(src.file, &lfd); -+ if (ret) { -+ fdput(src); -+ return ret; -+ } -+ -+ /* -+ * shiftfs_real_fdget() does not take a reference to lfd.file, so -+ * take a reference here to offset the one which will be put by -+ * __close_fd(), and make sure that reference is put on fdput(lfd). -+ */ -+ get_file(lfd.file); -+ lfd.flags |= FDPUT_FPUT; -+ fdput(src); -+ -+ *newfd = get_unused_fd_flags(lfd.file->f_flags); -+ if (*newfd < 0) { -+ fdput(lfd); -+ return *newfd; -+ } -+ -+ fd_install(*newfd, lfd.file); -+ -+ if (cmd == BTRFS_IOC_SNAP_CREATE) { -+ v1->fd = *newfd; -+ ret = copy_to_user(arg, v1, sizeof(*v1)); -+ v1->fd = oldfd; -+ } else { -+ v2->fd = *newfd; -+ ret = copy_to_user(arg, v2, sizeof(*v2)); -+ v2->fd = oldfd; -+ } -+ -+ if (ret) -+ shiftfs_btrfs_ioctl_fd_restore(cmd, *newfd, arg, v1, v2); -+ -+ return ret; -+} -+ -+static long shiftfs_real_ioctl(struct file *file, unsigned int cmd, -+ unsigned long arg) -+{ -+ struct fd lowerfd; -+ struct cred *newcred; -+ const struct cred *oldcred; -+ int newfd = -EBADF; -+ long err = 0, ret = 0; -+ void __user *argp = (void __user *)arg; -+ struct super_block *sb = file->f_path.dentry->d_sb; -+ struct btrfs_ioctl_vol_args *btrfs_v1 = NULL; -+ struct btrfs_ioctl_vol_args_v2 *btrfs_v2 = NULL; -+ -+ ret = shiftfs_btrfs_ioctl_fd_replace(cmd, argp, &btrfs_v1, &btrfs_v2, -+ &newfd); -+ if (ret < 0) -+ return ret; -+ -+ ret = shiftfs_real_fdget(file, &lowerfd); -+ if (ret) -+ goto out_restore; -+ -+ ret = shiftfs_override_ioctl_creds(cmd, sb, &oldcred, &newcred); -+ if (ret) -+ goto out_fdput; -+ -+ ret = vfs_ioctl(lowerfd.file, cmd, arg); -+ -+ shiftfs_revert_ioctl_creds(oldcred, newcred); -+ -+ shiftfs_copyattr(file_inode(lowerfd.file), file_inode(file)); -+ shiftfs_copyflags(file_inode(lowerfd.file), file_inode(file)); -+ -+out_fdput: -+ fdput(lowerfd); -+ -+out_restore: -+ err = shiftfs_btrfs_ioctl_fd_restore(cmd, newfd, argp, -+ btrfs_v1, btrfs_v2); -+ if (!ret) -+ ret = err; -+ -+ return ret; -+} -+ -+static bool in_ioctl_whitelist(int flag, unsigned long arg) -+{ -+ void __user *argp = (void __user *)arg; -+ u64 flags = 0; -+ -+ switch (flag) { -+ case BTRFS_IOC_FS_INFO: -+ return true; -+ case BTRFS_IOC_SNAP_CREATE: -+ return true; -+ case BTRFS_IOC_SNAP_CREATE_V2: -+ return true; -+ case BTRFS_IOC_SUBVOL_CREATE: -+ return true; -+ case BTRFS_IOC_SUBVOL_CREATE_V2: -+ return true; -+ case BTRFS_IOC_SUBVOL_GETFLAGS: -+ return true; -+ case BTRFS_IOC_SUBVOL_SETFLAGS: -+ if (copy_from_user(&flags, argp, sizeof(flags))) -+ return false; -+ -+ if (flags & ~BTRFS_SUBVOL_RDONLY) -+ return false; -+ -+ return true; -+ case BTRFS_IOC_SNAP_DESTROY: -+ return true; -+ } -+ -+ return false; -+} -+ -+static long shiftfs_ioctl(struct file *file, unsigned int cmd, -+ unsigned long arg) -+{ -+ switch (cmd) { -+ case FS_IOC_GETVERSION: -+ /* fall through */ -+ case FS_IOC_GETFLAGS: -+ /* fall through */ -+ case FS_IOC_SETFLAGS: -+ break; -+ default: -+ if (!in_ioctl_whitelist(cmd, arg) || -+ !shiftfs_passthrough_ioctls(file->f_path.dentry->d_sb->s_fs_info)) -+ return -ENOTTY; -+ } -+ -+ return shiftfs_real_ioctl(file, cmd, arg); -+} -+ -+static long shiftfs_compat_ioctl(struct file *file, unsigned int cmd, -+ unsigned long arg) -+{ -+ switch (cmd) { -+ case FS_IOC32_GETVERSION: -+ /* fall through */ -+ case FS_IOC32_GETFLAGS: -+ /* fall through */ -+ case FS_IOC32_SETFLAGS: -+ break; -+ default: -+ if (!in_ioctl_whitelist(cmd, arg) || -+ !shiftfs_passthrough_ioctls(file->f_path.dentry->d_sb->s_fs_info)) -+ return -ENOIOCTLCMD; -+ } -+ -+ return shiftfs_real_ioctl(file, cmd, arg); -+} -+ -+enum shiftfs_copyop { -+ SHIFTFS_COPY, -+ SHIFTFS_CLONE, -+ SHIFTFS_DEDUPE, -+}; -+ -+static ssize_t shiftfs_copyfile(struct file *file_in, loff_t pos_in, -+ struct file *file_out, loff_t pos_out, u64 len, -+ unsigned int flags, enum shiftfs_copyop op) -+{ -+ ssize_t ret; -+ struct fd real_in, real_out; -+ const struct cred *oldcred; -+ struct inode *inode_out = file_inode(file_out); -+ struct inode *loweri = inode_out->i_private; -+ -+ ret = shiftfs_real_fdget(file_out, &real_out); -+ if (ret) -+ return ret; -+ -+ ret = shiftfs_real_fdget(file_in, &real_in); -+ if (ret) { -+ fdput(real_out); -+ return ret; -+ } -+ -+ oldcred = shiftfs_override_creds(inode_out->i_sb); -+ switch (op) { -+ case SHIFTFS_COPY: -+ ret = vfs_copy_file_range(real_in.file, pos_in, real_out.file, -+ pos_out, len, flags); -+ break; -+ -+ case SHIFTFS_CLONE: -+ ret = vfs_clone_file_range(real_in.file, pos_in, real_out.file, -+ pos_out, len, flags); -+ break; -+ -+ case SHIFTFS_DEDUPE: -+ ret = vfs_dedupe_file_range_one(real_in.file, pos_in, -+ real_out.file, pos_out, len, -+ flags); -+ break; -+ } -+ revert_creds(oldcred); -+ -+ /* Update size */ -+ shiftfs_copyattr(loweri, inode_out); -+ -+ fdput(real_in); -+ fdput(real_out); -+ -+ return ret; -+} -+ -+static ssize_t shiftfs_copy_file_range(struct file *file_in, loff_t pos_in, -+ struct file *file_out, loff_t pos_out, -+ size_t len, unsigned int flags) -+{ -+ return shiftfs_copyfile(file_in, pos_in, file_out, pos_out, len, flags, -+ SHIFTFS_COPY); -+} -+ -+static loff_t shiftfs_remap_file_range(struct file *file_in, loff_t pos_in, -+ struct file *file_out, loff_t pos_out, -+ loff_t len, unsigned int remap_flags) -+{ -+ enum shiftfs_copyop op; -+ -+ if (remap_flags & ~(REMAP_FILE_DEDUP | REMAP_FILE_ADVISORY)) -+ return -EINVAL; -+ -+ if (remap_flags & REMAP_FILE_DEDUP) -+ op = SHIFTFS_DEDUPE; -+ else -+ op = SHIFTFS_CLONE; -+ -+ return shiftfs_copyfile(file_in, pos_in, file_out, pos_out, len, -+ remap_flags, op); -+} -+ -+static int shiftfs_iterate_shared(struct file *file, struct dir_context *ctx) -+{ -+ const struct cred *oldcred; -+ int err = -ENOTDIR; -+ struct file *realfile = file->private_data; -+ -+ oldcred = shiftfs_override_creds(file->f_path.dentry->d_sb); -+ err = iterate_dir(realfile, ctx); -+ revert_creds(oldcred); -+ -+ return err; -+} -+ -+const struct file_operations shiftfs_file_operations = { -+ .open = shiftfs_open, -+ .release = shiftfs_release, -+ .llseek = shiftfs_file_llseek, -+ .read_iter = shiftfs_read_iter, -+ .write_iter = shiftfs_write_iter, -+ .fsync = shiftfs_fsync, -+ .mmap = shiftfs_mmap, -+ .fallocate = shiftfs_fallocate, -+ .fadvise = shiftfs_fadvise, -+ .unlocked_ioctl = shiftfs_ioctl, -+ .compat_ioctl = shiftfs_compat_ioctl, -+ .copy_file_range = shiftfs_copy_file_range, -+ .remap_file_range = shiftfs_remap_file_range, -+}; -+ -+const struct file_operations shiftfs_dir_operations = { -+ .open = shiftfs_dir_open, -+ .release = shiftfs_dir_release, -+ .compat_ioctl = shiftfs_compat_ioctl, -+ .fsync = shiftfs_fsync, -+ .iterate_shared = shiftfs_iterate_shared, -+ .llseek = shiftfs_dir_llseek, -+ .read = generic_read_dir, -+ .unlocked_ioctl = shiftfs_ioctl, -+}; -+ -+static const struct address_space_operations shiftfs_aops = { -+ /* For O_DIRECT dentry_open() checks f_mapping->a_ops->direct_IO */ -+ .direct_IO = noop_direct_IO, -+}; -+ -+static void shiftfs_fill_inode(struct inode *inode, unsigned long ino, -+ umode_t mode, dev_t dev, struct dentry *dentry) -+{ -+ struct inode *loweri; -+ -+ inode->i_ino = ino; -+ inode->i_flags |= S_NOCMTIME; -+ -+ mode &= S_IFMT; -+ inode->i_mode = mode; -+ switch (mode & S_IFMT) { -+ case S_IFDIR: -+ inode->i_op = &shiftfs_dir_inode_operations; -+ inode->i_fop = &shiftfs_dir_operations; -+ break; -+ case S_IFLNK: -+ inode->i_op = &shiftfs_symlink_inode_operations; -+ break; -+ case S_IFREG: -+ inode->i_op = &shiftfs_file_inode_operations; -+ inode->i_fop = &shiftfs_file_operations; -+ inode->i_mapping->a_ops = &shiftfs_aops; -+ break; -+ default: -+ inode->i_op = &shiftfs_special_inode_operations; -+ init_special_inode(inode, mode, dev); -+ break; -+ } -+ -+ if (!dentry) -+ return; -+ -+ loweri = dentry->d_inode; -+ if (!loweri->i_op->get_link) -+ inode->i_opflags |= IOP_NOFOLLOW; -+ -+ shiftfs_copyattr(loweri, inode); -+ shiftfs_copyflags(loweri, inode); -+ set_nlink(inode, loweri->i_nlink); -+} -+ -+static int shiftfs_show_options(struct seq_file *m, struct dentry *dentry) -+{ -+ struct super_block *sb = dentry->d_sb; -+ struct shiftfs_super_info *sbinfo = sb->s_fs_info; -+ -+ if (sbinfo->mark) -+ seq_show_option(m, "mark", NULL); -+ -+ if (sbinfo->passthrough) -+ seq_printf(m, ",passthrough=%u", sbinfo->passthrough); -+ -+ return 0; -+} -+ -+static int shiftfs_statfs(struct dentry *dentry, struct kstatfs *buf) -+{ -+ struct super_block *sb = dentry->d_sb; -+ struct shiftfs_super_info *sbinfo = sb->s_fs_info; -+ struct dentry *root = sb->s_root; -+ struct dentry *realroot = root->d_fsdata; -+ struct path realpath = { .mnt = sbinfo->mnt, .dentry = realroot }; -+ int err; -+ -+ err = vfs_statfs(&realpath, buf); -+ if (err) -+ return err; -+ -+ if (!shiftfs_passthrough_statfs(sbinfo)) -+ buf->f_type = sb->s_magic; -+ -+ return 0; -+} -+ -+static void shiftfs_evict_inode(struct inode *inode) -+{ -+ struct inode *loweri = inode->i_private; -+ -+ clear_inode(inode); -+ -+ if (loweri) -+ iput(loweri); -+} -+ -+static void shiftfs_put_super(struct super_block *sb) -+{ -+ struct shiftfs_super_info *sbinfo = sb->s_fs_info; -+ -+ if (sbinfo) { -+ mntput(sbinfo->mnt); -+ put_cred(sbinfo->creator_cred); -+ kfree(sbinfo); -+ } -+} -+ -+static const struct xattr_handler shiftfs_xattr_handler = { -+ .prefix = "", -+ .get = shiftfs_xattr_get, -+ .set = shiftfs_xattr_set, -+}; -+ -+const struct xattr_handler *shiftfs_xattr_handlers[] = { -+#ifdef CONFIG_SHIFT_FS_POSIX_ACL -+ &shiftfs_posix_acl_access_xattr_handler, -+ &shiftfs_posix_acl_default_xattr_handler, -+#endif -+ &shiftfs_xattr_handler, -+ NULL -+}; -+ -+static inline bool passthrough_is_subset(int old_flags, int new_flags) -+{ -+ if ((new_flags & old_flags) != new_flags) -+ return false; -+ -+ return true; -+} -+ -+static int shiftfs_super_check_flags(unsigned long old_flags, -+ unsigned long new_flags) -+{ -+ if ((old_flags & SB_RDONLY) && !(new_flags & SB_RDONLY)) -+ return -EPERM; -+ -+ if ((old_flags & SB_NOSUID) && !(new_flags & SB_NOSUID)) -+ return -EPERM; -+ -+ if ((old_flags & SB_NODEV) && !(new_flags & SB_NODEV)) -+ return -EPERM; -+ -+ if ((old_flags & SB_NOEXEC) && !(new_flags & SB_NOEXEC)) -+ return -EPERM; -+ -+ if ((old_flags & SB_NOATIME) && !(new_flags & SB_NOATIME)) -+ return -EPERM; -+ -+ if ((old_flags & SB_NODIRATIME) && !(new_flags & SB_NODIRATIME)) -+ return -EPERM; -+ -+ if (!(old_flags & SB_POSIXACL) && (new_flags & SB_POSIXACL)) -+ return -EPERM; -+ -+ return 0; -+} -+ -+static int shiftfs_remount(struct super_block *sb, int *flags, char *data) -+{ -+ int err; -+ struct shiftfs_super_info new = {}; -+ struct shiftfs_super_info *info = sb->s_fs_info; -+ -+ err = shiftfs_parse_mount_options(&new, data); -+ if (err) -+ return err; -+ -+ err = shiftfs_super_check_flags(sb->s_flags, *flags); -+ if (err) -+ return err; -+ -+ /* Mark mount option cannot be changed. */ -+ if (info->mark || (info->mark != new.mark)) -+ return -EPERM; -+ -+ if (info->passthrough != new.passthrough) { -+ /* Don't allow exceeding passthrough options of mark mount. */ -+ if (!passthrough_is_subset(info->passthrough_mark, -+ info->passthrough)) -+ return -EPERM; -+ -+ info->passthrough = new.passthrough; -+ } -+ -+ return 0; -+} -+ -+static const struct super_operations shiftfs_super_ops = { -+ .put_super = shiftfs_put_super, -+ .show_options = shiftfs_show_options, -+ .statfs = shiftfs_statfs, -+ .remount_fs = shiftfs_remount, -+ .evict_inode = shiftfs_evict_inode, -+}; -+ -+struct shiftfs_data { -+ void *data; -+ const char *path; -+}; -+ -+static void shiftfs_super_force_flags(struct super_block *sb, -+ unsigned long lower_flags) -+{ -+ sb->s_flags |= lower_flags & (SB_RDONLY | SB_NOSUID | SB_NODEV | -+ SB_NOEXEC | SB_NOATIME | SB_NODIRATIME); -+ -+ if (!(lower_flags & SB_POSIXACL)) -+ sb->s_flags &= ~SB_POSIXACL; -+} -+ -+static int shiftfs_fill_super(struct super_block *sb, void *raw_data, -+ int silent) -+{ -+ int err; -+ struct path path = {}; -+ struct shiftfs_super_info *sbinfo_mp; -+ char *name = NULL; -+ struct inode *inode = NULL; -+ struct dentry *dentry = NULL; -+ struct shiftfs_data *data = raw_data; -+ struct shiftfs_super_info *sbinfo = NULL; -+ -+ if (!data->path) -+ return -EINVAL; -+ -+ sb->s_fs_info = kzalloc(sizeof(*sbinfo), GFP_KERNEL); -+ if (!sb->s_fs_info) -+ return -ENOMEM; -+ sbinfo = sb->s_fs_info; -+ -+ err = shiftfs_parse_mount_options(sbinfo, data->data); -+ if (err) -+ return err; -+ -+ /* to mount a mark, must be userns admin */ -+ if (!sbinfo->mark && !ns_capable(current_user_ns(), CAP_SYS_ADMIN)) -+ return -EPERM; -+ -+ name = kstrdup(data->path, GFP_KERNEL); -+ if (!name) -+ return -ENOMEM; -+ -+ err = kern_path(name, LOOKUP_FOLLOW, &path); -+ if (err) -+ goto out_free_name; -+ -+ if (!S_ISDIR(path.dentry->d_inode->i_mode)) { -+ err = -ENOTDIR; -+ goto out_put_path; -+ } -+ -+ sb->s_flags |= SB_POSIXACL; -+ -+ if (sbinfo->mark) { -+ struct cred *cred_tmp; -+ struct super_block *lower_sb = path.mnt->mnt_sb; -+ -+ /* to mark a mount point, must root wrt lower s_user_ns */ -+ if (!ns_capable(lower_sb->s_user_ns, CAP_SYS_ADMIN)) { -+ err = -EPERM; -+ goto out_put_path; -+ } -+ -+ /* -+ * this part is visible unshifted, so make sure no -+ * executables that could be used to give suid -+ * privileges -+ */ -+ sb->s_iflags = SB_I_NOEXEC; -+ -+ shiftfs_super_force_flags(sb, lower_sb->s_flags); -+ -+ /* -+ * Handle nesting of shiftfs mounts by referring this mark -+ * mount back to the original mark mount. This is more -+ * efficient and alleviates concerns about stack depth. -+ */ -+ if (lower_sb->s_magic == SHIFTFS_MAGIC) { -+ sbinfo_mp = lower_sb->s_fs_info; -+ -+ /* Doesn't make sense to mark a mark mount */ -+ if (sbinfo_mp->mark) { -+ err = -EINVAL; -+ goto out_put_path; -+ } -+ -+ if (!passthrough_is_subset(sbinfo_mp->passthrough, -+ sbinfo->passthrough)) { -+ err = -EPERM; -+ goto out_put_path; -+ } -+ -+ sbinfo->mnt = mntget(sbinfo_mp->mnt); -+ dentry = dget(path.dentry->d_fsdata); -+ /* -+ * Copy up the passthrough mount options from the -+ * parent mark mountpoint. -+ */ -+ sbinfo->passthrough_mark = sbinfo_mp->passthrough_mark; -+ sbinfo->creator_cred = get_cred(sbinfo_mp->creator_cred); -+ } else { -+ sbinfo->mnt = mntget(path.mnt); -+ dentry = dget(path.dentry); -+ /* -+ * For a new mark passthrough_mark and passthrough -+ * are identical. -+ */ -+ sbinfo->passthrough_mark = sbinfo->passthrough; -+ -+ cred_tmp = prepare_creds(); -+ if (!cred_tmp) { -+ err = -ENOMEM; -+ goto out_put_path; -+ } -+ /* Don't override disk quota limits or use reserved space. */ -+ cap_lower(cred_tmp->cap_effective, CAP_SYS_RESOURCE); -+ sbinfo->creator_cred = cred_tmp; -+ } -+ } else { -+ /* -+ * This leg executes if we're admin capable in the namespace, -+ * so be very careful. -+ */ -+ err = -EPERM; -+ if (path.dentry->d_sb->s_magic != SHIFTFS_MAGIC) -+ goto out_put_path; -+ -+ sbinfo_mp = path.dentry->d_sb->s_fs_info; -+ if (!sbinfo_mp->mark) -+ goto out_put_path; -+ -+ if (!passthrough_is_subset(sbinfo_mp->passthrough, -+ sbinfo->passthrough)) -+ goto out_put_path; -+ -+ sbinfo->mnt = mntget(sbinfo_mp->mnt); -+ sbinfo->creator_cred = get_cred(sbinfo_mp->creator_cred); -+ dentry = dget(path.dentry->d_fsdata); -+ /* -+ * Copy up passthrough settings from mark mountpoint so we can -+ * verify when the overlay wants to remount with different -+ * passthrough settings. -+ */ -+ sbinfo->passthrough_mark = sbinfo_mp->passthrough; -+ shiftfs_super_force_flags(sb, path.mnt->mnt_sb->s_flags); -+ } -+ -+ sb->s_stack_depth = dentry->d_sb->s_stack_depth + 1; -+ if (sb->s_stack_depth > FILESYSTEM_MAX_STACK_DEPTH) { -+ printk(KERN_ERR "shiftfs: maximum stacking depth exceeded\n"); -+ err = -EINVAL; -+ goto out_put_path; -+ } -+ -+ inode = new_inode(sb); -+ if (!inode) { -+ err = -ENOMEM; -+ goto out_put_path; -+ } -+ shiftfs_fill_inode(inode, dentry->d_inode->i_ino, S_IFDIR, 0, dentry); -+ -+ ihold(dentry->d_inode); -+ inode->i_private = dentry->d_inode; -+ -+ sb->s_magic = SHIFTFS_MAGIC; -+ sb->s_maxbytes = MAX_LFS_FILESIZE; -+ sb->s_op = &shiftfs_super_ops; -+ sb->s_xattr = shiftfs_xattr_handlers; -+ sb->s_d_op = &shiftfs_dentry_ops; -+ sb->s_root = d_make_root(inode); -+ if (!sb->s_root) { -+ err = -ENOMEM; -+ goto out_put_path; -+ } -+ -+ sb->s_root->d_fsdata = dentry; -+ sbinfo->userns = get_user_ns(dentry->d_sb->s_user_ns); -+ shiftfs_copyattr(dentry->d_inode, sb->s_root->d_inode); -+ -+ dentry = NULL; -+ err = 0; -+ -+out_put_path: -+ path_put(&path); -+ -+out_free_name: -+ kfree(name); -+ -+ dput(dentry); -+ -+ return err; -+} -+ -+static struct dentry *shiftfs_mount(struct file_system_type *fs_type, -+ int flags, const char *dev_name, void *data) -+{ -+ struct shiftfs_data d = { data, dev_name }; -+ -+ return mount_nodev(fs_type, flags, &d, shiftfs_fill_super); -+} -+ -+static struct file_system_type shiftfs_type = { -+ .owner = THIS_MODULE, -+ .name = "shiftfs", -+ .mount = shiftfs_mount, -+ .kill_sb = kill_anon_super, -+ .fs_flags = FS_USERNS_MOUNT, -+}; -+ -+static int __init shiftfs_init(void) -+{ -+ return register_filesystem(&shiftfs_type); -+} -+ -+static void __exit shiftfs_exit(void) -+{ -+ unregister_filesystem(&shiftfs_type); -+} -+ -+MODULE_ALIAS_FS("shiftfs"); -+MODULE_AUTHOR("James Bottomley"); -+MODULE_AUTHOR("Seth Forshee <seth.forshee@canonical.com>"); -+MODULE_AUTHOR("Christian Brauner <christian.brauner@ubuntu.com>"); -+MODULE_DESCRIPTION("id shifting filesystem"); -+MODULE_LICENSE("GPL v2"); -+module_init(shiftfs_init) -+module_exit(shiftfs_exit) ---- a/include/uapi/linux/magic.h 2021-01-06 19:08:45.234777659 -0500 -+++ b/include/uapi/linux/magic.h 2021-01-06 19:09:53.900375394 -0500 -@@ -96,4 +96,6 @@ - #define DEVMEM_MAGIC 0x454d444d /* "DMEM" */ - #define Z3FOLD_MAGIC 0x33 - -+#define SHIFTFS_MAGIC 0x6a656a62 -+ - #endif /* __LINUX_MAGIC_H__ */ ---- a/fs/Makefile 2021-01-08 18:08:28.187064015 -0500 -+++ b/fs/Makefile 2021-01-08 18:09:00.788217579 -0500 -@@ -136,3 +136,4 @@ obj-$(CONFIG_EFIVAR_FS) += efivarfs/ - obj-$(CONFIG_EROFS_FS) += erofs/ - obj-$(CONFIG_VBOXSF_FS) += vboxsf/ - obj-$(CONFIG_ZONEFS_FS) += zonefs/ -+obj-$(CONFIG_SHIFT_FS) += shiftfs.o ---- a/fs/Kconfig 2021-01-06 19:14:17.709697891 -0500 -+++ b/fs/Kconfig 2021-01-06 19:15:23.413281282 -0500 -@@ -122,6 +122,24 @@ source "fs/autofs/Kconfig" - source "fs/fuse/Kconfig" - source "fs/overlayfs/Kconfig" - -+config SHIFT_FS -+ tristate "UID/GID shifting overlay filesystem for containers" -+ help -+ This filesystem can overlay any mounted filesystem and shift -+ the uid/gid the files appear at. The idea is that -+ unprivileged containers can use this to mount root volumes -+ using this technique. -+ -+config SHIFT_FS_POSIX_ACL -+ bool "shiftfs POSIX Access Control Lists" -+ depends on SHIFT_FS -+ select FS_POSIX_ACL -+ help -+ POSIX Access Control Lists (ACLs) support permissions for users and -+ groups beyond the owner/group/world scheme. -+ -+ If you don't know what Access Control Lists are, say N. -+ - menu "Caches" - - source "fs/fscache/Kconfig" diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0001-make-DEFAULT_MMAP_MIN_ADDR-match-LSM_MMAP_MIN_ADDR.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0001-make-DEFAULT_MMAP_MIN_ADDR-match-LSM_MMAP_MIN_ADDR.patch deleted file mode 100644 index 4dcd7523054f..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0001-make-DEFAULT_MMAP_MIN_ADDR-match-LSM_MMAP_MIN_ADDR.patch +++ /dev/null @@ -1,27 +0,0 @@ -From d9d30b2b018fa6ee76deb27ebb1d8820f511a732 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Sat, 27 May 2017 07:22:12 -0400 -Subject: [PATCH 001/113] make DEFAULT_MMAP_MIN_ADDR match LSM_MMAP_MIN_ADDR - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - mm/Kconfig | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/mm/Kconfig b/mm/Kconfig -index 390165ffbb0f..3b24c9e3535e 100644 ---- a/mm/Kconfig -+++ b/mm/Kconfig -@@ -321,7 +321,8 @@ config KSM - config DEFAULT_MMAP_MIN_ADDR - int "Low address space to protect from user allocation" - depends on MMU -- default 4096 -+ default 32768 if ARM || (ARM64 && COMPAT) -+ default 65536 - help - This is the portion of low virtual memory which should be protected - from userspace allocation. Keeping a user from writing to low pages --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0002-enable-HARDENED_USERCOPY-by-default.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0002-enable-HARDENED_USERCOPY-by-default.patch deleted file mode 100644 index e972ca800f5e..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0002-enable-HARDENED_USERCOPY-by-default.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 86d91201e7eaa175f380a7d7c6dfa238a73cb816 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Mon, 29 May 2017 06:17:41 -0400 -Subject: [PATCH 002/113] enable HARDENED_USERCOPY by default - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - security/Kconfig | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/security/Kconfig b/security/Kconfig -index 7561f6f99f1d..9446ddf40974 100644 ---- a/security/Kconfig -+++ b/security/Kconfig -@@ -154,6 +154,7 @@ config HARDENED_USERCOPY - bool "Harden memory copies between kernel and userspace" - depends on HAVE_HARDENED_USERCOPY_ALLOCATOR - imply STRICT_DEVMEM -+ default y - help - This option checks for obviously wrong memory regions when - copying memory to/from the kernel (via copy_to_user() and --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0003-disable-HARDENED_USERCOPY_FALLBACK-by-default.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0003-disable-HARDENED_USERCOPY_FALLBACK-by-default.patch deleted file mode 100644 index 056d3b0dd6ae..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0003-disable-HARDENED_USERCOPY_FALLBACK-by-default.patch +++ /dev/null @@ -1,24 +0,0 @@ -From c91c4da25ecdb24c7ce90778d33184c2ad3c306c Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Thu, 26 Apr 2018 02:01:26 -0400 -Subject: [PATCH 003/113] disable HARDENED_USERCOPY_FALLBACK by default - ---- - security/Kconfig | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/security/Kconfig b/security/Kconfig -index 9446ddf40974..5c388f7fe09d 100644 ---- a/security/Kconfig -+++ b/security/Kconfig -@@ -167,7 +167,6 @@ config HARDENED_USERCOPY - config HARDENED_USERCOPY_FALLBACK - bool "Allow usercopy whitelist violations to fallback to object size" - depends on HARDENED_USERCOPY -- default y - help - This is a temporary option that allows missing usercopy whitelists - to be discovered via a WARN() to the kernel log, instead of --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0004-enable-SECURITY_DMESG_RESTRICT-by-default.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0004-enable-SECURITY_DMESG_RESTRICT-by-default.patch deleted file mode 100644 index e7c85fc85348..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0004-enable-SECURITY_DMESG_RESTRICT-by-default.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 8706ca7dbe2b4bf85f7549b5e532172ec70ecb33 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Wed, 3 May 2017 12:05:15 -0400 -Subject: [PATCH 004/113] enable SECURITY_DMESG_RESTRICT by default - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - security/Kconfig | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/security/Kconfig b/security/Kconfig -index 5c388f7fe09d..428ad7622370 100644 ---- a/security/Kconfig -+++ b/security/Kconfig -@@ -9,7 +9,7 @@ source "security/keys/Kconfig" - - config SECURITY_DMESG_RESTRICT - bool "Restrict unprivileged access to the kernel syslog" -- default n -+ default y - help - This enforces restrictions on unprivileged users reading the kernel - syslog via dmesg(8). --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0005-set-kptr_restrict-2-by-default.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0005-set-kptr_restrict-2-by-default.patch deleted file mode 100644 index ebc662b49cc8..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0005-set-kptr_restrict-2-by-default.patch +++ /dev/null @@ -1,26 +0,0 @@ -From cfa910285b72779ce423fe38eeb194f6adcbf9d4 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Wed, 3 May 2017 12:06:14 -0400 -Subject: [PATCH 005/113] set kptr_restrict=2 by default - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - lib/vsprintf.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/lib/vsprintf.c b/lib/vsprintf.c -index 14c9a6af1b23..2501f75bd74d 100644 ---- a/lib/vsprintf.c -+++ b/lib/vsprintf.c -@@ -821,7 +821,7 @@ static char *ptr_to_id(char *buf, char *end, const void *ptr, - return pointer_string(buf, end, (const void *)hashval, spec); - } - --int kptr_restrict __read_mostly; -+int kptr_restrict __read_mostly = 2; - - static noinline_for_stack - char *restricted_pointer(char *buf, char *end, const void *ptr, --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0006-enable-DEBUG_LIST-by-default.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0006-enable-DEBUG_LIST-by-default.patch deleted file mode 100644 index cc518b81a539..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0006-enable-DEBUG_LIST-by-default.patch +++ /dev/null @@ -1,25 +0,0 @@ -From f06c970c3a69ceaa4653e8db98175c3e276995d6 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Wed, 3 May 2017 12:10:57 -0400 -Subject: [PATCH 006/113] enable DEBUG_LIST by default - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - lib/Kconfig.debug | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug -index c789b39ed527..89c9d6aebf77 100644 ---- a/lib/Kconfig.debug -+++ b/lib/Kconfig.debug -@@ -1471,6 +1471,7 @@ menu "Debug kernel data structures" - config DEBUG_LIST - bool "Debug linked list manipulation" - depends on DEBUG_KERNEL || BUG_ON_DATA_CORRUPTION -+ default y - help - Enable this to turn on extended checks in the linked-list - walking routines. --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0007-enable-BUG_ON_DATA_CORRUPTION-by-default.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0007-enable-BUG_ON_DATA_CORRUPTION-by-default.patch deleted file mode 100644 index 8d5725148e80..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0007-enable-BUG_ON_DATA_CORRUPTION-by-default.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 1ed4992d5312b9f195fb25a5db794243e411349c Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Mon, 29 May 2017 12:21:21 -0400 -Subject: [PATCH 007/113] enable BUG_ON_DATA_CORRUPTION by default - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - lib/Kconfig.debug | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug -index 89c9d6aebf77..11068e77d146 100644 ---- a/lib/Kconfig.debug -+++ b/lib/Kconfig.debug -@@ -1511,6 +1511,7 @@ config DEBUG_NOTIFIERS - config BUG_ON_DATA_CORRUPTION - bool "Trigger a BUG when data corruption is detected" - select DEBUG_LIST -+ default y - help - Select this option if the kernel should BUG when it encounters - data corruption in kernel memory structures when they get checked --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0008-enable-ARM64_SW_TTBR0_PAN-by-default.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0008-enable-ARM64_SW_TTBR0_PAN-by-default.patch deleted file mode 100644 index 27c93f3cdf6e..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0008-enable-ARM64_SW_TTBR0_PAN-by-default.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 69f9e43c30be97a4bac4ed7e019190842824fe42 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Sun, 25 Feb 2018 01:39:32 -0500 -Subject: [PATCH 008/113] enable ARM64_SW_TTBR0_PAN by default - ---- - arch/arm64/Kconfig | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig -index a6b5b7ef40ae..a145245ec5e7 100644 ---- a/arch/arm64/Kconfig -+++ b/arch/arm64/Kconfig -@@ -1199,6 +1199,7 @@ config RODATA_FULL_DEFAULT_ENABLED - - config ARM64_SW_TTBR0_PAN - bool "Emulate Privileged Access Never using TTBR0_EL1 switching" -+ default y - help - Enabling this option prevents the kernel from accessing - user-space memory directly by pointing TTBR0_EL1 to a reserved --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0009-arm64-enable-RANDOMIZE_BASE-by-default.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0009-arm64-enable-RANDOMIZE_BASE-by-default.patch deleted file mode 100644 index d53952c79d9d..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0009-arm64-enable-RANDOMIZE_BASE-by-default.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 2d8a717c80114334be591d35b9e09fdcc56c9368 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Sun, 25 Feb 2018 01:33:48 -0500 -Subject: [PATCH 009/113] arm64: enable RANDOMIZE_BASE by default - ---- - arch/arm64/Kconfig | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig -index a145245ec5e7..21088a6532d8 100644 ---- a/arch/arm64/Kconfig -+++ b/arch/arm64/Kconfig -@@ -1790,6 +1790,7 @@ config RANDOMIZE_BASE - bool "Randomize the address of the kernel image" - select ARM64_MODULE_PLTS if MODULES - select RELOCATABLE -+ default y - help - Randomizes the virtual address at which the kernel image is - loaded, as a security feature that deters exploit attempts --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0010-enable-SLAB_FREELIST_RANDOM-by-default.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0010-enable-SLAB_FREELIST_RANDOM-by-default.patch deleted file mode 100644 index 8353e06ca342..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0010-enable-SLAB_FREELIST_RANDOM-by-default.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 9d94f16c3379f590e962739a865e86daef05a0bd Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Wed, 3 May 2017 19:43:38 -0400 -Subject: [PATCH 010/113] enable SLAB_FREELIST_RANDOM by default - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - init/Kconfig | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/init/Kconfig b/init/Kconfig -index 0872a5a2e759..dcbcb4243316 100644 ---- a/init/Kconfig -+++ b/init/Kconfig -@@ -1929,6 +1929,7 @@ config SLAB_MERGE_DEFAULT - config SLAB_FREELIST_RANDOM - bool "Randomize slab freelist" - depends on SLAB || SLUB -+ default y - help - Randomizes the freelist order used on creating new pages. This - security feature reduces the predictability of the kernel slab --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0011-enable-SLAB_FREELIST_HARDENED-by-default.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0011-enable-SLAB_FREELIST_HARDENED-by-default.patch deleted file mode 100644 index 6a3683cc5b2e..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0011-enable-SLAB_FREELIST_HARDENED-by-default.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 32ee17a35ba371cefc7bd7fed7a8686e040dabcb Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Sun, 20 Aug 2017 15:39:25 -0400 -Subject: [PATCH 011/113] enable SLAB_FREELIST_HARDENED by default - ---- - init/Kconfig | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/init/Kconfig b/init/Kconfig -index dcbcb4243316..667d1c6c021b 100644 ---- a/init/Kconfig -+++ b/init/Kconfig -@@ -1938,6 +1938,7 @@ config SLAB_FREELIST_RANDOM - config SLAB_FREELIST_HARDENED - bool "Harden slab freelist metadata" - depends on SLAB || SLUB -+ default y - help - Many kernel heap attacks try to target slab cache metadata and - other infrastructure. This options makes minor performance --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0012-disable-SLAB_MERGE_DEFAULT-by-default.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0012-disable-SLAB_MERGE_DEFAULT-by-default.patch deleted file mode 100644 index 2ab0649fba29..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0012-disable-SLAB_MERGE_DEFAULT-by-default.patch +++ /dev/null @@ -1,24 +0,0 @@ -From add6f0f716837cb517911ad94ca80faf98ca1b21 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Sat, 8 Jul 2017 02:38:54 -0400 -Subject: [PATCH 012/113] disable SLAB_MERGE_DEFAULT by default - ---- - init/Kconfig | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/init/Kconfig b/init/Kconfig -index 667d1c6c021b..859ab5ae66ff 100644 ---- a/init/Kconfig -+++ b/init/Kconfig -@@ -1914,7 +1914,6 @@ endchoice - - config SLAB_MERGE_DEFAULT - bool "Allow slab caches to be merged" -- default y - help - For reduced kernel memory fragmentation, slab caches can be - merged when they share the same size and other characteristics. --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0013-enable-FORTIFY_SOURCE-by-default.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0013-enable-FORTIFY_SOURCE-by-default.patch deleted file mode 100644 index 2b17e240ca4a..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0013-enable-FORTIFY_SOURCE-by-default.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 1c354980f5d5132617e3f17a80dea1bbd34a0e3f Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Mon, 8 May 2017 12:51:54 -0400 -Subject: [PATCH 013/113] enable FORTIFY_SOURCE by default - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - security/Kconfig | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/security/Kconfig b/security/Kconfig -index 428ad7622370..3a2c68c7b50f 100644 ---- a/security/Kconfig -+++ b/security/Kconfig -@@ -191,6 +191,7 @@ config HARDENED_USERCOPY_PAGESPAN - config FORTIFY_SOURCE - bool "Harden common str/mem functions against buffer overflows" - depends on ARCH_HAS_FORTIFY_SOURCE -+ default y - help - Detect overflows of buffers in common string and memory functions - where the compiler can determine and validate the buffer sizes. --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0014-enable-PANIC_ON_OOPS-by-default.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0014-enable-PANIC_ON_OOPS-by-default.patch deleted file mode 100644 index 70939ea89c19..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0014-enable-PANIC_ON_OOPS-by-default.patch +++ /dev/null @@ -1,34 +0,0 @@ -From f9249a0e6ddb4d8550cd268d22ba80fb475ac0fe Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Wed, 3 May 2017 12:09:17 -0400 -Subject: [PATCH 014/113] enable PANIC_ON_OOPS by default - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - lib/Kconfig.debug | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug -index 11068e77d146..45b169177fb9 100644 ---- a/lib/Kconfig.debug -+++ b/lib/Kconfig.debug -@@ -894,6 +894,7 @@ menu "Debug Oops, Lockups and Hangs" - - config PANIC_ON_OOPS - bool "Panic on Oops" -+ default y - help - Say Y here to enable the kernel to panic when it oopses. This - has the same effect as setting oops=panic on the kernel command -@@ -903,7 +904,7 @@ config PANIC_ON_OOPS - anything erroneous after an oops which could result in data - corruption or other issues. - -- Say N if unsure. -+ Say Y if unsure. - - config PANIC_ON_OOPS_VALUE - int --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0015-stop-hiding-SLUB_DEBUG-behind-EXPERT.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0015-stop-hiding-SLUB_DEBUG-behind-EXPERT.patch deleted file mode 100644 index 57729fc4588c..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0015-stop-hiding-SLUB_DEBUG-behind-EXPERT.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 7606dac7028e3e79600656d1a93ca21a04cbf684 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Sun, 14 May 2017 22:39:34 -0400 -Subject: [PATCH 015/113] stop hiding SLUB_DEBUG behind EXPERT - -It can make sense to disable this to reduce attack surface / complexity. ---- - init/Kconfig | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/init/Kconfig b/init/Kconfig -index 859ab5ae66ff..74680a15ceb4 100644 ---- a/init/Kconfig -+++ b/init/Kconfig -@@ -1843,7 +1843,7 @@ config VM_EVENT_COUNTERS - - config SLUB_DEBUG - default y -- bool "Enable SLUB debugging support" if EXPERT -+ bool "Enable SLUB debugging support" - depends on SLUB && SYSFS - help - SLUB has extensive debug support features. Disabling these can --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0016-stop-hiding-X86_16BIT-behind-EXPERT.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0016-stop-hiding-X86_16BIT-behind-EXPERT.patch deleted file mode 100644 index 8734c952758e..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0016-stop-hiding-X86_16BIT-behind-EXPERT.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 36b1d1ea9f227293955790f03eb7e00fe4e45441 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Thu, 4 May 2017 18:11:31 -0400 -Subject: [PATCH 016/113] stop hiding X86_16BIT behind EXPERT - ---- - arch/x86/Kconfig | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig -index 3a5ecb1039bf..d2d5e0cbf85c 100644 ---- a/arch/x86/Kconfig -+++ b/arch/x86/Kconfig -@@ -1194,7 +1194,7 @@ config VM86 - default X86_LEGACY_VM86 - - config X86_16BIT -- bool "Enable support for 16-bit segments" if EXPERT -+ bool "Enable support for 16-bit segments" - default y - depends on MODIFY_LDT_SYSCALL - help --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0017-disable-X86_16BIT-by-default.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0017-disable-X86_16BIT-by-default.patch deleted file mode 100644 index fd505e4ed16c..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0017-disable-X86_16BIT-by-default.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 5f32dbb0e3343ed1aeef7fbad9727cbe51982604 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Thu, 4 May 2017 18:11:52 -0400 -Subject: [PATCH 017/113] disable X86_16BIT by default - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - arch/x86/Kconfig | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig -index d2d5e0cbf85c..ab6e7e2d3cf0 100644 ---- a/arch/x86/Kconfig -+++ b/arch/x86/Kconfig -@@ -1195,7 +1195,6 @@ config VM86 - - config X86_16BIT - bool "Enable support for 16-bit segments" -- default y - depends on MODIFY_LDT_SYSCALL - help - This option is required by programs like Wine to run 16-bit --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0018-stop-hiding-MODIFY_LDT_SYSCALL-behind-EXPERT.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0018-stop-hiding-MODIFY_LDT_SYSCALL-behind-EXPERT.patch deleted file mode 100644 index 782c0b45dd1d..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0018-stop-hiding-MODIFY_LDT_SYSCALL-behind-EXPERT.patch +++ /dev/null @@ -1,25 +0,0 @@ -From b3cd6107dc0d9ef30ea155577406837b97b85473 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Thu, 4 May 2017 18:15:52 -0400 -Subject: [PATCH 018/113] stop hiding MODIFY_LDT_SYSCALL behind EXPERT - ---- - arch/x86/Kconfig | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig -index ab6e7e2d3cf0..7b9df510469b 100644 ---- a/arch/x86/Kconfig -+++ b/arch/x86/Kconfig -@@ -2392,7 +2392,7 @@ config CMDLINE_OVERRIDE - be set to 'N' under normal conditions. - - config MODIFY_LDT_SYSCALL -- bool "Enable the LDT (local descriptor table)" if EXPERT -+ bool "Enable the LDT (local descriptor table)" - default y - help - Linux can allow user programs to install a per-process x86 --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0019-disable-MODIFY_LDT_SYSCALL-by-default.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0019-disable-MODIFY_LDT_SYSCALL-by-default.patch deleted file mode 100644 index 584025aaf34d..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0019-disable-MODIFY_LDT_SYSCALL-by-default.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 8ba7c14d933792448f918192fecad81fde249b7b Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Thu, 4 May 2017 18:16:16 -0400 -Subject: [PATCH 019/113] disable MODIFY_LDT_SYSCALL by default - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> -Signed-off-by: Levente Polyak <levente@leventepolyak.net> ---- - arch/x86/Kconfig | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig -index 7b9df510469b..63e1e9fc18dd 100644 ---- a/arch/x86/Kconfig -+++ b/arch/x86/Kconfig -@@ -2393,7 +2393,6 @@ config CMDLINE_OVERRIDE - - config MODIFY_LDT_SYSCALL - bool "Enable the LDT (local descriptor table)" -- default y - help - Linux can allow user programs to install a per-process x86 - Local Descriptor Table (LDT) using the modify_ldt(2) system --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0020-set-LEGACY_VSYSCALL_NONE-by-default.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0020-set-LEGACY_VSYSCALL_NONE-by-default.patch deleted file mode 100644 index 53eb35761de6..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0020-set-LEGACY_VSYSCALL_NONE-by-default.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 5d2790cf2628a95c5dc731e85c7d82eb490edb08 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Mon, 29 May 2017 07:08:42 -0400 -Subject: [PATCH 020/113] set LEGACY_VSYSCALL_NONE by default - ---- - arch/x86/Kconfig | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig -index 63e1e9fc18dd..4fd082de7420 100644 ---- a/arch/x86/Kconfig -+++ b/arch/x86/Kconfig -@@ -2296,7 +2296,7 @@ config COMPAT_VDSO - choice - prompt "vsyscall table for legacy applications" - depends on X86_64 -- default LEGACY_VSYSCALL_XONLY -+ default LEGACY_VSYSCALL_NONE - help - Legacy user code that does not know how to find the vDSO expects - to be able to issue three syscalls by calling fixed addresses in --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0021-stop-hiding-AIO-behind-EXPERT.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0021-stop-hiding-AIO-behind-EXPERT.patch deleted file mode 100644 index e935f1e25198..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0021-stop-hiding-AIO-behind-EXPERT.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 6625069c32a40b9618f4d5974f07b35de8c76b2f Mon Sep 17 00:00:00 2001 -From: Bernhard40 <32568352+Bernhard40@users.noreply.github.com> -Date: Fri, 6 Oct 2017 10:21:50 +0000 -Subject: [PATCH 021/113] stop hiding AIO behind EXPERT - ---- - init/Kconfig | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/init/Kconfig b/init/Kconfig -index 74680a15ceb4..8605f3e78e47 100644 ---- a/init/Kconfig -+++ b/init/Kconfig -@@ -1591,7 +1591,7 @@ config SHMEM - which may be appropriate on small systems without swap. - - config AIO -- bool "Enable AIO support" if EXPERT -+ bool "Enable AIO support" - default y - help - This option enables POSIX asynchronous I/O which may by used --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0022-disable-AIO-by-default.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0022-disable-AIO-by-default.patch deleted file mode 100644 index ef2e59c8b84f..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0022-disable-AIO-by-default.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 135b0c2b580a3b29e39d68ebd4cb6968363464fe Mon Sep 17 00:00:00 2001 -From: Bernhard40 <32568352+Bernhard40@users.noreply.github.com> -Date: Fri, 6 Oct 2017 10:24:10 +0000 -Subject: [PATCH 022/113] disable AIO by default - ---- - init/Kconfig | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/init/Kconfig b/init/Kconfig -index 8605f3e78e47..21f0b6926cf3 100644 ---- a/init/Kconfig -+++ b/init/Kconfig -@@ -1592,7 +1592,6 @@ config SHMEM - - config AIO - bool "Enable AIO support" -- default y - help - This option enables POSIX asynchronous I/O which may by used - by some high performance threaded applications. Disabling --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0023-remove-SYSVIPC-from-arm64-x86_64-defconfigs.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0023-remove-SYSVIPC-from-arm64-x86_64-defconfigs.patch deleted file mode 100644 index 4d9e336414dd..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0023-remove-SYSVIPC-from-arm64-x86_64-defconfigs.patch +++ /dev/null @@ -1,32 +0,0 @@ -From c5a80cfe5b6f64df3c8b2fae4713001fd8094577 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Sun, 25 Feb 2018 02:08:49 -0500 -Subject: [PATCH 023/113] remove SYSVIPC from arm64/x86_64 defconfigs - ---- - arch/arm64/configs/defconfig | 1 - - arch/x86/configs/x86_64_defconfig | 1 - - 2 files changed, 2 deletions(-) - -diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig -index 5cfe3cf6f2ac..f25871361bdc 100644 ---- a/arch/arm64/configs/defconfig -+++ b/arch/arm64/configs/defconfig -@@ -1,4 +1,3 @@ --CONFIG_SYSVIPC=y - CONFIG_POSIX_MQUEUE=y - CONFIG_AUDIT=y - CONFIG_NO_HZ_IDLE=y -diff --git a/arch/x86/configs/x86_64_defconfig b/arch/x86/configs/x86_64_defconfig -index 9936528e1939..981ee8c0e330 100644 ---- a/arch/x86/configs/x86_64_defconfig -+++ b/arch/x86/configs/x86_64_defconfig -@@ -1,5 +1,4 @@ - # CONFIG_LOCALVERSION_AUTO is not set --CONFIG_SYSVIPC=y - CONFIG_POSIX_MQUEUE=y - CONFIG_AUDIT=y - CONFIG_NO_HZ=y --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0024-disable-DEVPORT-by-default.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0024-disable-DEVPORT-by-default.patch deleted file mode 100644 index 81db083a942a..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0024-disable-DEVPORT-by-default.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 9d988d867cf28b220c4b613b85405c6db1e4cf34 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Sat, 27 May 2017 07:28:10 -0400 -Subject: [PATCH 024/113] disable DEVPORT by default - ---- - drivers/char/Kconfig | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig -index d229a2d0c017..68178c3a25de 100644 ---- a/drivers/char/Kconfig -+++ b/drivers/char/Kconfig -@@ -391,7 +391,6 @@ config MAX_RAW_DEVS - config DEVPORT - bool "/dev/port character device" - depends on ISA || PCI -- default y - help - Say Y here if you want to support the /dev/port device. The /dev/port - device is similar to /dev/mem, but for I/O ports. --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0025-disable-PROC_VMCORE-by-default.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0025-disable-PROC_VMCORE-by-default.patch deleted file mode 100644 index 61fb56ca60b4..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0025-disable-PROC_VMCORE-by-default.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 6635f4bbe167dd2138fbbb6a3e9861518f4c5b74 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Sat, 27 May 2017 07:29:45 -0400 -Subject: [PATCH 025/113] disable PROC_VMCORE by default - ---- - fs/proc/Kconfig | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/fs/proc/Kconfig b/fs/proc/Kconfig -index c930001056f9..6a0a51b3f593 100644 ---- a/fs/proc/Kconfig -+++ b/fs/proc/Kconfig -@@ -41,7 +41,6 @@ config PROC_KCORE - config PROC_VMCORE - bool "/proc/vmcore support" - depends on PROC_FS && CRASH_DUMP -- default y - help - Exports the dump image of crashed kernel in ELF format. - --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0026-disable-NFS_DEBUG-by-default.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0026-disable-NFS_DEBUG-by-default.patch deleted file mode 100644 index 29a8a6fe50c6..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0026-disable-NFS_DEBUG-by-default.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 2e80bbb8ba13e71a45394e0921cad61c3e301c8f Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Sun, 28 May 2017 03:03:46 -0400 -Subject: [PATCH 026/113] disable NFS_DEBUG by default - ---- - fs/nfs/Kconfig | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig -index e2a488d403a6..ce54c1c693a8 100644 ---- a/fs/nfs/Kconfig -+++ b/fs/nfs/Kconfig -@@ -195,7 +195,6 @@ config NFS_DEBUG - bool - depends on NFS_FS && SUNRPC_DEBUG - select CRC32 -- default y - - config NFS_DISABLE_UDP_SUPPORT - bool "NFS: Disable NFS UDP protocol support" --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0027-enable-DEBUG_WX-by-default.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0027-enable-DEBUG_WX-by-default.patch deleted file mode 100644 index 26182c55bd8d..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0027-enable-DEBUG_WX-by-default.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 13ebbd23324bfc02069a34f5653a74f584b7a4a3 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Mon, 29 May 2017 12:11:11 -0400 -Subject: [PATCH 027/113] enable DEBUG_WX by default - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - mm/Kconfig.debug | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/mm/Kconfig.debug b/mm/Kconfig.debug -index 864f129f1937..929d585bd267 100644 ---- a/mm/Kconfig.debug -+++ b/mm/Kconfig.debug -@@ -126,6 +126,7 @@ config DEBUG_WX - depends on ARCH_HAS_DEBUG_WX - depends on MMU - select PTDUMP_CORE -+ default y - help - Generate a warning if any W+X mappings are found at boot. - --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0028-disable-LEGACY_PTYS-by-default.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0028-disable-LEGACY_PTYS-by-default.patch deleted file mode 100644 index 6fb9b280fff3..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0028-disable-LEGACY_PTYS-by-default.patch +++ /dev/null @@ -1,24 +0,0 @@ -From a323baa5554e3094f9bdc305a0fd4800de8fd808 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Fri, 5 Jan 2018 13:21:16 -0500 -Subject: [PATCH 028/113] disable LEGACY_PTYS by default - ---- - drivers/tty/Kconfig | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/drivers/tty/Kconfig b/drivers/tty/Kconfig -index 93fd984eb2f5..d9086484d2de 100644 ---- a/drivers/tty/Kconfig -+++ b/drivers/tty/Kconfig -@@ -122,7 +122,6 @@ config UNIX98_PTYS - - config LEGACY_PTYS - bool "Legacy (BSD) PTY support" -- default y - help - A pseudo terminal (PTY) is a software device consisting of two - halves: a master and a slave. The slave device behaves identical to --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0029-disable-DEVMEM-by-default.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0029-disable-DEVMEM-by-default.patch deleted file mode 100644 index 756cdb9e893e..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0029-disable-DEVMEM-by-default.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 6921af5937c9d74c6f5ea18b6af69bf50e9c112e Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Fri, 5 Jan 2018 12:41:42 -0500 -Subject: [PATCH 029/113] disable DEVMEM by default - ---- - drivers/char/Kconfig | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig -index 68178c3a25de..2fd45f01e7a2 100644 ---- a/drivers/char/Kconfig -+++ b/drivers/char/Kconfig -@@ -327,7 +327,6 @@ config NSC_GPIO - - config DEVMEM - bool "/dev/mem virtual device support" -- default y - help - Say Y here if you want to support the /dev/mem device. - The /dev/mem device is used to access areas of physical --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0030-enable-IO_STRICT_DEVMEM-by-default.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0030-enable-IO_STRICT_DEVMEM-by-default.patch deleted file mode 100644 index 68234a544720..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0030-enable-IO_STRICT_DEVMEM-by-default.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 5576916518af221c6848a39466df67b6d5f6286d Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Fri, 5 Jan 2018 12:43:49 -0500 -Subject: [PATCH 030/113] enable IO_STRICT_DEVMEM by default - ---- - lib/Kconfig.debug | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug -index 45b169177fb9..a46f21a56125 100644 ---- a/lib/Kconfig.debug -+++ b/lib/Kconfig.debug -@@ -1668,6 +1668,7 @@ config STRICT_DEVMEM - config IO_STRICT_DEVMEM - bool "Filter I/O access to /dev/mem" - depends on STRICT_DEVMEM -+ default y - help - If this option is disabled, you allow userspace (root) access to all - io-memory regardless of whether a driver is actively using that --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0031-disable-COMPAT_BRK-by-default.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0031-disable-COMPAT_BRK-by-default.patch deleted file mode 100644 index b40cee775ff1..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0031-disable-COMPAT_BRK-by-default.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 014e9eef97e005f5032a4ab0fb57b57d01a4030b Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Sun, 7 May 2017 18:28:33 -0400 -Subject: [PATCH 031/113] disable COMPAT_BRK by default - ---- - init/Kconfig | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/init/Kconfig b/init/Kconfig -index 21f0b6926cf3..4f5827e10be3 100644 ---- a/init/Kconfig -+++ b/init/Kconfig -@@ -1866,7 +1866,6 @@ config SLUB_MEMCG_SYSFS_ON - - config COMPAT_BRK - bool "Disable heap randomization" -- default y - help - Randomizing heap placement makes heap exploits harder, but it - also breaks ancient binaries (including anything libc5 based). --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0032-use-maximum-supported-mmap-rnd-entropy-by-default.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0032-use-maximum-supported-mmap-rnd-entropy-by-default.patch deleted file mode 100644 index e2cf38edb18f..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0032-use-maximum-supported-mmap-rnd-entropy-by-default.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 298c0203615e31629f9a2c50ff3b650b168eec3c Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Sun, 7 May 2017 16:16:39 -0400 -Subject: [PATCH 032/113] use maximum supported mmap rnd entropy by default - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - arch/Kconfig | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/arch/Kconfig b/arch/Kconfig -index 69fe7133c765..8b5c346d5dd8 100644 ---- a/arch/Kconfig -+++ b/arch/Kconfig -@@ -752,7 +752,7 @@ config ARCH_MMAP_RND_BITS - int "Number of bits to use for ASLR of mmap base address" if EXPERT - range ARCH_MMAP_RND_BITS_MIN ARCH_MMAP_RND_BITS_MAX - default ARCH_MMAP_RND_BITS_DEFAULT if ARCH_MMAP_RND_BITS_DEFAULT -- default ARCH_MMAP_RND_BITS_MIN -+ default ARCH_MMAP_RND_BITS_MAX - depends on HAVE_ARCH_MMAP_RND_BITS - help - This value can be used to select the number of bits to use to -@@ -786,7 +786,7 @@ config ARCH_MMAP_RND_COMPAT_BITS - int "Number of bits to use for ASLR of mmap base address for compatible applications" if EXPERT - range ARCH_MMAP_RND_COMPAT_BITS_MIN ARCH_MMAP_RND_COMPAT_BITS_MAX - default ARCH_MMAP_RND_COMPAT_BITS_DEFAULT if ARCH_MMAP_RND_COMPAT_BITS_DEFAULT -- default ARCH_MMAP_RND_COMPAT_BITS_MIN -+ default ARCH_MMAP_RND_COMPAT_BITS_MAX - depends on HAVE_ARCH_MMAP_RND_COMPAT_BITS - help - This value can be used to select the number of bits to use to --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0033-enable-protected_-symlinks-hardlinks-by-default.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0033-enable-protected_-symlinks-hardlinks-by-default.patch deleted file mode 100644 index 4bfcfc063d6e..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0033-enable-protected_-symlinks-hardlinks-by-default.patch +++ /dev/null @@ -1,27 +0,0 @@ -From ee6fa41fbfd9a1c5f8285ddf1acf2409afc47f07 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Tue, 30 May 2017 10:47:23 -0400 -Subject: [PATCH 033/113] enable protected_{symlinks,hardlinks} by default - ---- - fs/namei.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/fs/namei.c b/fs/namei.c -index d4a6dd772303..59ff3ce21026 100644 ---- a/fs/namei.c -+++ b/fs/namei.c -@@ -932,8 +932,8 @@ static inline void put_link(struct nameidata *nd) - path_put(&last->link); - } - --int sysctl_protected_symlinks __read_mostly = 0; --int sysctl_protected_hardlinks __read_mostly = 0; -+int sysctl_protected_symlinks __read_mostly = 1; -+int sysctl_protected_hardlinks __read_mostly = 1; - int sysctl_protected_fifos __read_mostly; - int sysctl_protected_regular __read_mostly; - --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0034-enable-SECURITY-by-default.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0034-enable-SECURITY-by-default.patch deleted file mode 100644 index 4fe943c41cde..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0034-enable-SECURITY-by-default.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 5e504c79ed89f04712c33813ee796e3b803e8872 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Sun, 25 Feb 2018 02:13:48 -0500 -Subject: [PATCH 034/113] enable SECURITY by default - ---- - security/Kconfig | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/security/Kconfig b/security/Kconfig -index 3a2c68c7b50f..fa037a250821 100644 ---- a/security/Kconfig -+++ b/security/Kconfig -@@ -23,6 +23,7 @@ config SECURITY - bool "Enable different security models" - depends on SYSFS - depends on MULTIUSER -+ default y - help - This allows you to choose different security modules to be - configured into your kernel. --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0035-enable-SECURITY_YAMA-by-default.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0035-enable-SECURITY_YAMA-by-default.patch deleted file mode 100644 index 8fe1318f9f6d..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0035-enable-SECURITY_YAMA-by-default.patch +++ /dev/null @@ -1,25 +0,0 @@ -From aaa52818bc7880648b9fce16ca48cf665180f96f Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Mon, 29 May 2017 06:17:59 -0400 -Subject: [PATCH 035/113] enable SECURITY_YAMA by default - ---- - security/yama/Kconfig | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/security/yama/Kconfig b/security/yama/Kconfig -index a810304123ca..b809050b25d2 100644 ---- a/security/yama/Kconfig -+++ b/security/yama/Kconfig -@@ -2,7 +2,7 @@ - config SECURITY_YAMA - bool "Yama support" - depends on SECURITY -- default n -+ default y - help - This selects Yama, which extends DAC support with additional - system-wide security settings beyond regular Linux discretionary --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0036-enable-SECURITY_NETWORK-by-default.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0036-enable-SECURITY_NETWORK-by-default.patch deleted file mode 100644 index 80267ded3c3a..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0036-enable-SECURITY_NETWORK-by-default.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 48545330ffe33eb3e82e674a5f528b6abbd7330c Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Sun, 25 Feb 2018 02:14:02 -0500 -Subject: [PATCH 036/113] enable SECURITY_NETWORK by default - ---- - security/Kconfig | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/security/Kconfig b/security/Kconfig -index fa037a250821..81d0a08736aa 100644 ---- a/security/Kconfig -+++ b/security/Kconfig -@@ -49,6 +49,7 @@ config SECURITYFS - config SECURITY_NETWORK - bool "Socket and Networking Security Hooks" - depends on SECURITY -+ default y - help - This enables the socket and networking security hooks. - If enabled, a security module can use these hooks to --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0037-enable-AUDIT-by-default.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0037-enable-AUDIT-by-default.patch deleted file mode 100644 index 6789b4a7a696..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0037-enable-AUDIT-by-default.patch +++ /dev/null @@ -1,24 +0,0 @@ -From b533c40a16bd32ced2cc233d75f3f8a0eb7cad14 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Sun, 25 Feb 2018 02:15:24 -0500 -Subject: [PATCH 037/113] enable AUDIT by default - ---- - init/Kconfig | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/init/Kconfig b/init/Kconfig -index 4f5827e10be3..9b75a4921575 100644 ---- a/init/Kconfig -+++ b/init/Kconfig -@@ -419,6 +419,7 @@ config USELIB - config AUDIT - bool "Auditing support" - depends on NET -+ default y - help - Enable auditing infrastructure that can be used with another - kernel subsystem, such as SELinux (which requires this for --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0038-enable-SECURITY_SELINUX-by-default.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0038-enable-SECURITY_SELINUX-by-default.patch deleted file mode 100644 index 572487a584c2..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0038-enable-SECURITY_SELINUX-by-default.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 310b7f7802779cbaefa9d09edb668a5022305bd0 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Sun, 25 Feb 2018 02:16:49 -0500 -Subject: [PATCH 038/113] enable SECURITY_SELINUX by default - ---- - security/selinux/Kconfig | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/security/selinux/Kconfig b/security/selinux/Kconfig -index 9e921fc72538..76d7ed11513c 100644 ---- a/security/selinux/Kconfig -+++ b/security/selinux/Kconfig -@@ -3,7 +3,7 @@ config SECURITY_SELINUX - bool "NSA SELinux Support" - depends on SECURITY_NETWORK && AUDIT && NET && INET - select NETWORK_SECMARK -- default n -+ default y - help - This selects NSA Security-Enhanced Linux (SELinux). - You will also need a policy configuration and a labeled filesystem. --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0039-enable-SYN_COOKIES-by-default.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0039-enable-SYN_COOKIES-by-default.patch deleted file mode 100644 index ab0ff0a57ef7..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0039-enable-SYN_COOKIES-by-default.patch +++ /dev/null @@ -1,24 +0,0 @@ -From d2d0adc9e3bcf502bf71928752fc9ab0b589e458 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Sat, 6 Jan 2018 13:41:11 -0500 -Subject: [PATCH 039/113] enable SYN_COOKIES by default - ---- - net/ipv4/Kconfig | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig -index 87983e70f03f..989e005bf698 100644 ---- a/net/ipv4/Kconfig -+++ b/net/ipv4/Kconfig -@@ -267,6 +267,7 @@ config IP_PIMSM_V2 - - config SYN_COOKIES - bool "IP: TCP syncookie support" -+ default y - help - Normal TCP/IP networking is open to an attack known as "SYN - flooding". This denial-of-service attack prevents legitimate remote --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0040-enable-INIT_ON_ALLOC_DEFAULT_ON-by-default.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0040-enable-INIT_ON_ALLOC_DEFAULT_ON-by-default.patch deleted file mode 100644 index c6ae1f45435a..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0040-enable-INIT_ON_ALLOC_DEFAULT_ON-by-default.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 7e6d075eb0bad24cb984de968b98555c4130de6d Mon Sep 17 00:00:00 2001 -From: Levente Polyak <levente@leventepolyak.net> -Date: Thu, 19 Sep 2019 19:02:23 +0200 -Subject: [PATCH 040/113] enable INIT_ON_ALLOC_DEFAULT_ON by default - ---- - security/Kconfig.hardening | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/security/Kconfig.hardening b/security/Kconfig.hardening -index 269967c4fc1b..1e279f6d7633 100644 ---- a/security/Kconfig.hardening -+++ b/security/Kconfig.hardening -@@ -190,6 +190,7 @@ config STACKLEAK_RUNTIME_DISABLE - - config INIT_ON_ALLOC_DEFAULT_ON - bool "Enable heap memory zeroing on allocation by default" -+ default yes - help - This has the effect of setting "init_on_alloc=1" on the kernel - command line. This can be disabled with "init_on_alloc=0". --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0041-enable-INIT_ON_FREE_DEFAULT_ON-by-default.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0041-enable-INIT_ON_FREE_DEFAULT_ON-by-default.patch deleted file mode 100644 index 5711346bc582..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0041-enable-INIT_ON_FREE_DEFAULT_ON-by-default.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 5af0c8005ecc18cbbd2508502fcbe10d29ccffb3 Mon Sep 17 00:00:00 2001 -From: Levente Polyak <levente@leventepolyak.net> -Date: Thu, 19 Sep 2019 19:03:01 +0200 -Subject: [PATCH 041/113] enable INIT_ON_FREE_DEFAULT_ON by default - ---- - security/Kconfig.hardening | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/security/Kconfig.hardening b/security/Kconfig.hardening -index 1e279f6d7633..2fa447823405 100644 ---- a/security/Kconfig.hardening -+++ b/security/Kconfig.hardening -@@ -203,6 +203,7 @@ config INIT_ON_ALLOC_DEFAULT_ON - - config INIT_ON_FREE_DEFAULT_ON - bool "Enable heap memory zeroing on free by default" -+ default yes - help - This has the effect of setting "init_on_free=1" on the kernel - command line. This can be disabled with "init_on_free=0". --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0042-kconfig-select-DEBUG_FS_ALLOW_NONE-by-default-if-DEB.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0042-kconfig-select-DEBUG_FS_ALLOW_NONE-by-default-if-DEB.patch deleted file mode 100644 index 904c2462bf04..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0042-kconfig-select-DEBUG_FS_ALLOW_NONE-by-default-if-DEB.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 04c0c41e5e366e7197b87a8f6561af64f87c51ce Mon Sep 17 00:00:00 2001 -From: Levente Polyak <levente@leventepolyak.net> -Date: Sun, 27 Sep 2020 00:43:48 +0200 -Subject: [PATCH 042/113] kconfig: select DEBUG_FS_ALLOW_NONE by default if - DEBUG_FS is enabled - -Signed-off-by: Levente Polyak <levente@leventepolyak.net> ---- - lib/Kconfig.debug | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug -index a46f21a56125..4a1a32a059f4 100644 ---- a/lib/Kconfig.debug -+++ b/lib/Kconfig.debug -@@ -488,7 +488,7 @@ config DEBUG_FS - choice - prompt "Debugfs default access" - depends on DEBUG_FS -- default DEBUG_FS_ALLOW_ALL -+ default DEBUG_FS_ALLOW_NONE - help - This selects the default access restrictions for debugfs. - It can be overridden with kernel command line option --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0043-stop-hiding-SYSFS_SYSCALL-behind-EXPERT.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0043-stop-hiding-SYSFS_SYSCALL-behind-EXPERT.patch deleted file mode 100644 index 4e52cabbcfa0..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0043-stop-hiding-SYSFS_SYSCALL-behind-EXPERT.patch +++ /dev/null @@ -1,25 +0,0 @@ -From d1b970b059d3ff73991183053053ed2774ebc638 Mon Sep 17 00:00:00 2001 -From: Levente Polyak <levente@leventepolyak.net> -Date: Tue, 22 Dec 2020 23:35:53 +0100 -Subject: [PATCH 043/113] stop hiding SYSFS_SYSCALL behind EXPERT - ---- - init/Kconfig | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/init/Kconfig b/init/Kconfig -index 9b75a4921575..006d4d41e3af 100644 ---- a/init/Kconfig -+++ b/init/Kconfig -@@ -1434,7 +1434,7 @@ config SGETMASK_SYSCALL - If unsure, leave the default option here. - - config SYSFS_SYSCALL -- bool "Sysfs syscall support" if EXPERT -+ bool "Sysfs syscall support" - default y - help - sys_sysfs is an obsolete system call no longer supported in libc. --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0044-disable-SYSFS_SYSCALL-by-default.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0044-disable-SYSFS_SYSCALL-by-default.patch deleted file mode 100644 index 687b5d71f893..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0044-disable-SYSFS_SYSCALL-by-default.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 53e350265c1574a899183650400619c5874889d8 Mon Sep 17 00:00:00 2001 -From: Levente Polyak <levente@leventepolyak.net> -Date: Tue, 22 Dec 2020 23:36:54 +0100 -Subject: [PATCH 044/113] disable SYSFS_SYSCALL by default - ---- - init/Kconfig | 3 +-- - 1 file changed, 1 insertion(+), 2 deletions(-) - -diff --git a/init/Kconfig b/init/Kconfig -index 006d4d41e3af..3d6b1b23e2db 100644 ---- a/init/Kconfig -+++ b/init/Kconfig -@@ -1435,13 +1435,12 @@ config SGETMASK_SYSCALL - - config SYSFS_SYSCALL - bool "Sysfs syscall support" -- default y - help - sys_sysfs is an obsolete system call no longer supported in libc. - Note that disabling this option is more secure but might break - compatibility with some systems. - -- If unsure say Y here. -+ If unsure say N here. - - config FHANDLE - bool "open by fhandle syscalls" if EXPERT --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0045-stop-hiding-UID16-behind-EXPERT.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0045-stop-hiding-UID16-behind-EXPERT.patch deleted file mode 100644 index 3b3b9edf3b54..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0045-stop-hiding-UID16-behind-EXPERT.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 31ed255051d07e3cc4eba6046f2b2a7597025793 Mon Sep 17 00:00:00 2001 -From: Levente Polyak <levente@leventepolyak.net> -Date: Tue, 22 Dec 2020 23:40:09 +0100 -Subject: [PATCH 045/113] stop hiding UID16 behind EXPERT - ---- - init/Kconfig | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/init/Kconfig b/init/Kconfig -index 3d6b1b23e2db..2b6d0492def5 100644 ---- a/init/Kconfig -+++ b/init/Kconfig -@@ -1403,7 +1403,7 @@ menuconfig EXPERT - Only use this if you really know what you are doing. - - config UID16 -- bool "Enable 16-bit UID system calls" if EXPERT -+ bool "Enable 16-bit UID system calls" - depends on HAVE_UID16 && MULTIUSER - default y - help --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0046-disable-UID16-by-default.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0046-disable-UID16-by-default.patch deleted file mode 100644 index e0fa54022fa1..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0046-disable-UID16-by-default.patch +++ /dev/null @@ -1,24 +0,0 @@ -From b4176b366266bd6e1338016640c01bf499615352 Mon Sep 17 00:00:00 2001 -From: Levente Polyak <levente@leventepolyak.net> -Date: Tue, 22 Dec 2020 23:41:32 +0100 -Subject: [PATCH 046/113] disable UID16 by default - ---- - init/Kconfig | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/init/Kconfig b/init/Kconfig -index 2b6d0492def5..58df4930995f 100644 ---- a/init/Kconfig -+++ b/init/Kconfig -@@ -1405,7 +1405,6 @@ menuconfig EXPERT - config UID16 - bool "Enable 16-bit UID system calls" - depends on HAVE_UID16 && MULTIUSER -- default y - help - This enables the legacy 16-bit UID syscall wrappers. - --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0047-add-__read_only-for-non-init-related-usage.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0047-add-__read_only-for-non-init-related-usage.patch deleted file mode 100644 index 62d94d53777e..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0047-add-__read_only-for-non-init-related-usage.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 30acc7eb764b9d493b289216420d40b964d2bdad Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Sun, 7 May 2017 00:28:23 -0400 -Subject: [PATCH 047/113] add __read_only for non-init related usage - ---- - include/linux/cache.h | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/include/linux/cache.h b/include/linux/cache.h -index d742c57eaee5..f0222c070458 100644 ---- a/include/linux/cache.h -+++ b/include/linux/cache.h -@@ -37,6 +37,8 @@ - #define __ro_after_init __section(".data..ro_after_init") - #endif - -+#define __read_only __ro_after_init -+ - #ifndef ____cacheline_aligned - #define ____cacheline_aligned __attribute__((__aligned__(SMP_CACHE_BYTES))) - #endif --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0048-make-sysctl-constants-read-only.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0048-make-sysctl-constants-read-only.patch deleted file mode 100644 index 1d7c3a9cbde7..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0048-make-sysctl-constants-read-only.patch +++ /dev/null @@ -1,108 +0,0 @@ -From e072e215c7638643d97034e5256edfa2a7e99ca8 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Sun, 7 May 2017 00:43:03 -0400 -Subject: [PATCH 048/113] make sysctl constants read-only - -Most of this is extracted from the last publicly available version of -the PaX patches where it's part of KERNEXEC as __read_only. It has been -extended to a few more of these constants. ---- - kernel/sysctl.c | 54 ++++++++++++++++++++++++------------------------- - 1 file changed, 27 insertions(+), 27 deletions(-) - -diff --git a/kernel/sysctl.c b/kernel/sysctl.c -index afad085960b8..b2cd3dbbb17a 100644 ---- a/kernel/sysctl.c -+++ b/kernel/sysctl.c -@@ -108,33 +108,33 @@ - - /* Constants used for minimum and maximum */ - #ifdef CONFIG_LOCKUP_DETECTOR --static int sixty = 60; --#endif -- --static int __maybe_unused neg_one = -1; --static int __maybe_unused two = 2; --static int __maybe_unused four = 4; --static unsigned long zero_ul; --static unsigned long one_ul = 1; --static unsigned long long_max = LONG_MAX; --static int one_hundred = 100; --static int two_hundred = 200; --static int one_thousand = 1000; -+static int sixty __read_only = 60; -+#endif -+ -+static int __maybe_unused neg_one __read_only = -1; -+static int __maybe_unused two __read_only = 2; -+static int __maybe_unused four __read_only = 4; -+static unsigned long zero_ul __read_only; -+static unsigned long one_ul __read_only = 1; -+static unsigned long long_max __read_only = LONG_MAX; -+static int one_hundred __read_only = 100; -+static int two_hundred __read_only = 200; -+static int one_thousand __read_only = 1000; - #ifdef CONFIG_PRINTK --static int ten_thousand = 10000; -+static int ten_thousand __read_only = 10000; - #endif - #ifdef CONFIG_PERF_EVENTS --static int six_hundred_forty_kb = 640 * 1024; -+static int six_hundred_forty_kb __read_only = 640 * 1024; - #endif - - /* this is needed for the proc_doulongvec_minmax of vm_dirty_bytes */ --static unsigned long dirty_bytes_min = 2 * PAGE_SIZE; -+static unsigned long dirty_bytes_min __read_only = 2 * PAGE_SIZE; - - /* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */ --static int maxolduid = 65535; --static int minolduid; -+static int maxolduid __read_only = 65535; -+static int minolduid __read_only; - --static int ngroups_max = NGROUPS_MAX; -+static int ngroups_max __read_only = NGROUPS_MAX; - static const int cap_last_cap = CAP_LAST_CAP; - - /* -@@ -142,7 +142,7 @@ static const int cap_last_cap = CAP_LAST_CAP; - * and hung_task_check_interval_secs - */ - #ifdef CONFIG_DETECT_HUNG_TASK --static unsigned long hung_task_timeout_max = (LONG_MAX/HZ); -+static unsigned long hung_task_timeout_max __read_only = (LONG_MAX/HZ); - #endif - - #ifdef CONFIG_INOTIFY_USER -@@ -185,19 +185,19 @@ int sysctl_legacy_va_layout; - #endif - - #ifdef CONFIG_SCHED_DEBUG --static int min_sched_granularity_ns = 100000; /* 100 usecs */ --static int max_sched_granularity_ns = NSEC_PER_SEC; /* 1 second */ --static int min_wakeup_granularity_ns; /* 0 usecs */ --static int max_wakeup_granularity_ns = NSEC_PER_SEC; /* 1 second */ -+static int min_sched_granularity_ns __read_only = 100000; /* 100 usecs */ -+static int max_sched_granularity_ns __read_only = NSEC_PER_SEC; /* 1 second */ -+static int min_wakeup_granularity_ns __read_only; /* 0 usecs */ -+static int max_wakeup_granularity_ns __read_only = NSEC_PER_SEC; /* 1 second */ - #ifdef CONFIG_SMP --static int min_sched_tunable_scaling = SCHED_TUNABLESCALING_NONE; --static int max_sched_tunable_scaling = SCHED_TUNABLESCALING_END-1; -+static int min_sched_tunable_scaling __read_only = SCHED_TUNABLESCALING_NONE; -+static int max_sched_tunable_scaling __read_only = SCHED_TUNABLESCALING_END-1; - #endif /* CONFIG_SMP */ - #endif /* CONFIG_SCHED_DEBUG */ - - #ifdef CONFIG_COMPACTION --static int min_extfrag_threshold; --static int max_extfrag_threshold = 1000; -+static int min_extfrag_threshold __read_only; -+static int max_extfrag_threshold __read_only = 1000; - #endif - - #endif /* CONFIG_SYSCTL */ --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0049-mark-kernel_set_to_readonly-as-__ro_after_init.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0049-mark-kernel_set_to_readonly-as-__ro_after_init.patch deleted file mode 100644 index 21abe2cd07cc..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0049-mark-kernel_set_to_readonly-as-__ro_after_init.patch +++ /dev/null @@ -1,67 +0,0 @@ -From 2225770e9e617726c0479070670a5f5320ca1a68 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Fri, 12 May 2017 03:22:00 -0400 -Subject: [PATCH 049/113] mark kernel_set_to_readonly as __ro_after_init - -This change was extracted from PaX where it's part of KERNEXEC. - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - arch/x86/mm/init_32.c | 5 ++--- - arch/x86/mm/init_64.c | 5 ++--- - 2 files changed, 4 insertions(+), 6 deletions(-) - -diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c -index 7c055259de3a..77192cbc1dd7 100644 ---- a/arch/x86/mm/init_32.c -+++ b/arch/x86/mm/init_32.c -@@ -828,7 +828,7 @@ void arch_remove_memory(int nid, u64 start, u64 size, - } - #endif - --int kernel_set_to_readonly __read_mostly; -+int kernel_set_to_readonly __ro_after_init; - - static void mark_nxdata_nx(void) - { -@@ -852,12 +852,11 @@ void mark_rodata_ro(void) - unsigned long start = PFN_ALIGN(_text); - unsigned long size = (unsigned long)__end_rodata - start; - -+ kernel_set_to_readonly = 1; - set_pages_ro(virt_to_page(start), size >> PAGE_SHIFT); - pr_info("Write protecting kernel text and read-only data: %luk\n", - size >> 10); - -- kernel_set_to_readonly = 1; -- - #ifdef CONFIG_CPA_DEBUG - pr_info("Testing CPA: Reverting %lx-%lx\n", start, start + size); - set_pages_rw(virt_to_page(start), size >> PAGE_SHIFT); -diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c -index b5a3fa4033d3..63a0f8097d0a 100644 ---- a/arch/x86/mm/init_64.c -+++ b/arch/x86/mm/init_64.c -@@ -1322,7 +1322,7 @@ int __init deferred_page_init_max_threads(const struct cpumask *node_cpumask) - } - #endif - --int kernel_set_to_readonly; -+int kernel_set_to_readonly __ro_after_init; - - void mark_rodata_ro(void) - { -@@ -1335,9 +1335,8 @@ void mark_rodata_ro(void) - - printk(KERN_INFO "Write protecting the kernel read-only data: %luk\n", - (end - start) >> 10); -- set_memory_ro(start, (end - start) >> PAGE_SHIFT); -- - kernel_set_to_readonly = 1; -+ set_memory_ro(start, (end - start) >> PAGE_SHIFT); - - /* - * The rodata/data/bss/brk section (but not the kernel text!) --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0050-Revert-mark-kernel_set_to_readonly-as-__ro_after_ini.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0050-Revert-mark-kernel_set_to_readonly-as-__ro_after_ini.patch deleted file mode 100644 index da795428a267..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0050-Revert-mark-kernel_set_to_readonly-as-__ro_after_ini.patch +++ /dev/null @@ -1,70 +0,0 @@ -From 8f8a6e20ae25c4e2955b3c1918392ef54bb7dccf Mon Sep 17 00:00:00 2001 -From: Levente Polyak <levente@leventepolyak.net> -Date: Sun, 13 Jan 2019 21:42:45 +0100 -Subject: [PATCH 050/113] Revert "mark kernel_set_to_readonly as - __ro_after_init" - - This commit causes CPA conflicts, cf. - https://github.com/anthraxx/linux-hardened/issues/4. - - Signed-off-by: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr> ---- - arch/x86/mm/init_32.c | 5 +++-- - arch/x86/mm/init_64.c | 5 +++-- - 2 files changed, 6 insertions(+), 4 deletions(-) - -diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c -index 77192cbc1dd7..7c055259de3a 100644 ---- a/arch/x86/mm/init_32.c -+++ b/arch/x86/mm/init_32.c -@@ -828,7 +828,7 @@ void arch_remove_memory(int nid, u64 start, u64 size, - } - #endif - --int kernel_set_to_readonly __ro_after_init; -+int kernel_set_to_readonly __read_mostly; - - static void mark_nxdata_nx(void) - { -@@ -852,11 +852,12 @@ void mark_rodata_ro(void) - unsigned long start = PFN_ALIGN(_text); - unsigned long size = (unsigned long)__end_rodata - start; - -- kernel_set_to_readonly = 1; - set_pages_ro(virt_to_page(start), size >> PAGE_SHIFT); - pr_info("Write protecting kernel text and read-only data: %luk\n", - size >> 10); - -+ kernel_set_to_readonly = 1; -+ - #ifdef CONFIG_CPA_DEBUG - pr_info("Testing CPA: Reverting %lx-%lx\n", start, start + size); - set_pages_rw(virt_to_page(start), size >> PAGE_SHIFT); -diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c -index 63a0f8097d0a..b5a3fa4033d3 100644 ---- a/arch/x86/mm/init_64.c -+++ b/arch/x86/mm/init_64.c -@@ -1322,7 +1322,7 @@ int __init deferred_page_init_max_threads(const struct cpumask *node_cpumask) - } - #endif - --int kernel_set_to_readonly __ro_after_init; -+int kernel_set_to_readonly; - - void mark_rodata_ro(void) - { -@@ -1335,9 +1335,10 @@ void mark_rodata_ro(void) - - printk(KERN_INFO "Write protecting the kernel read-only data: %luk\n", - (end - start) >> 10); -- kernel_set_to_readonly = 1; - set_memory_ro(start, (end - start) >> PAGE_SHIFT); - -+ kernel_set_to_readonly = 1; -+ - /* - * The rodata/data/bss/brk section (but not the kernel text!) - * should also be not-executable. --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0051-mark-slub-runtime-configuration-as-__ro_after_init.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0051-mark-slub-runtime-configuration-as-__ro_after_init.patch deleted file mode 100644 index 0a3e389a276b..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0051-mark-slub-runtime-configuration-as-__ro_after_init.patch +++ /dev/null @@ -1,57 +0,0 @@ -From 198bdbf6f07004c19ed43beed00b9362a2b7c0d1 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Sun, 14 May 2017 19:01:58 -0400 -Subject: [PATCH 051/113] mark slub runtime configuration as __ro_after_init - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - mm/slub.c | 16 ++++++++-------- - 1 file changed, 8 insertions(+), 8 deletions(-) - -diff --git a/mm/slub.c b/mm/slub.c -index 071e41067ea6..e01d54dc46e1 100644 ---- a/mm/slub.c -+++ b/mm/slub.c -@@ -486,13 +486,13 @@ static inline void *restore_red_left(struct kmem_cache *s, void *p) - * Debug settings: - */ - #if defined(CONFIG_SLUB_DEBUG_ON) --static slab_flags_t slub_debug = DEBUG_DEFAULT_FLAGS; -+static slab_flags_t slub_debug __ro_after_init = DEBUG_DEFAULT_FLAGS; - #else --static slab_flags_t slub_debug; -+static slab_flags_t slub_debug __ro_after_init; - #endif - --static char *slub_debug_string; --static int disable_higher_order_debug; -+static char *slub_debug_string __ro_after_init; -+static int disable_higher_order_debug __ro_after_init; - - /* - * slub is about to manipulate internal object metadata. This memory lies -@@ -3363,9 +3363,9 @@ EXPORT_SYMBOL(kmem_cache_alloc_bulk); - * and increases the number of allocations possible without having to - * take the list_lock. - */ --static unsigned int slub_min_order; --static unsigned int slub_max_order = PAGE_ALLOC_COSTLY_ORDER; --static unsigned int slub_min_objects; -+static unsigned int slub_min_order __ro_after_init; -+static unsigned int slub_max_order __ro_after_init = PAGE_ALLOC_COSTLY_ORDER; -+static unsigned int slub_min_objects __ro_after_init; - - /* - * Calculate the order of allocation given an slab object size. -@@ -4883,7 +4883,7 @@ enum slab_stat_type { - #define SO_TOTAL (1 << SL_TOTAL) - - #ifdef CONFIG_MEMCG --static bool memcg_sysfs_enabled = IS_ENABLED(CONFIG_SLUB_MEMCG_SYSFS_ON); -+static bool memcg_sysfs_enabled __ro_after_init = IS_ENABLED(CONFIG_SLUB_MEMCG_SYSFS_ON); - - static int __init setup_slub_memcg_sysfs(char *str) - { --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0052-add-__ro_after_init-to-slab_nomerge-and-slab_state.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0052-add-__ro_after_init-to-slab_nomerge-and-slab_state.patch deleted file mode 100644 index 14654130eb71..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0052-add-__ro_after_init-to-slab_nomerge-and-slab_state.patch +++ /dev/null @@ -1,38 +0,0 @@ -From e047a42de28f9c44533b166e08fa308011eecdfa Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Wed, 3 May 2017 11:35:35 -0400 -Subject: [PATCH 052/113] add __ro_after_init to slab_nomerge and slab_state - -This was extracted from the PaX patch where it's part of the KERNEXEC -feature as __read_only. - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - mm/slab_common.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/mm/slab_common.c b/mm/slab_common.c -index f9ccd5dc13f3..bff04048559f 100644 ---- a/mm/slab_common.c -+++ b/mm/slab_common.c -@@ -30,7 +30,7 @@ - - #include "slab.h" - --enum slab_state slab_state; -+enum slab_state slab_state __ro_after_init; - LIST_HEAD(slab_caches); - DEFINE_MUTEX(slab_mutex); - struct kmem_cache *kmem_cache; -@@ -61,7 +61,7 @@ static DECLARE_WORK(slab_caches_to_rcu_destroy_work, - /* - * Merge control. If this is set then no merging of slab caches will occur. - */ --static bool slab_nomerge = !IS_ENABLED(CONFIG_SLAB_MERGE_DEFAULT); -+static bool slab_nomerge __ro_after_init = !IS_ENABLED(CONFIG_SLAB_MERGE_DEFAULT); - - static int __init setup_slab_nomerge(char *str) - { --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0053-mark-kmem_cache-as-__ro_after_init.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0053-mark-kmem_cache-as-__ro_after_init.patch deleted file mode 100644 index 263c05d35b31..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0053-mark-kmem_cache-as-__ro_after_init.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 27946a5aa907b739ad7618f5068ef3fbc16d6a1b Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Sun, 28 May 2017 18:51:30 -0400 -Subject: [PATCH 053/113] mark kmem_cache as __ro_after_init - ---- - mm/slab_common.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/mm/slab_common.c b/mm/slab_common.c -index bff04048559f..2b73c12d8fce 100644 ---- a/mm/slab_common.c -+++ b/mm/slab_common.c -@@ -33,7 +33,7 @@ - enum slab_state slab_state __ro_after_init; - LIST_HEAD(slab_caches); - DEFINE_MUTEX(slab_mutex); --struct kmem_cache *kmem_cache; -+struct kmem_cache *kmem_cache __ro_after_init; - - #ifdef CONFIG_HARDENED_USERCOPY - bool usercopy_fallback __ro_after_init = --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0054-mark-__supported_pte_mask-as-__ro_after_init.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0054-mark-__supported_pte_mask-as-__ro_after_init.patch deleted file mode 100644 index 2d9cf6d81bbd..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0054-mark-__supported_pte_mask-as-__ro_after_init.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 5b076434040e271325cfbe308697669866d0dbad Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Fri, 12 May 2017 00:06:16 -0400 -Subject: [PATCH 054/113] mark __supported_pte_mask as __ro_after_init - -These changes were extracted from PaX where it was part of KERNEXEC as -__read_only. - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - arch/x86/mm/init_32.c | 4 ++-- - arch/x86/mm/init_64.c | 4 ++-- - 2 files changed, 4 insertions(+), 4 deletions(-) - -diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c -index 7c055259de3a..291b7b4476a9 100644 ---- a/arch/x86/mm/init_32.c -+++ b/arch/x86/mm/init_32.c -@@ -546,9 +546,9 @@ static void __init pagetable_init(void) - - #define DEFAULT_PTE_MASK ~(_PAGE_NX | _PAGE_GLOBAL) - /* Bits supported by the hardware: */ --pteval_t __supported_pte_mask __read_mostly = DEFAULT_PTE_MASK; -+pteval_t __supported_pte_mask __ro_after_init = DEFAULT_PTE_MASK; - /* Bits allowed in normal kernel mappings: */ --pteval_t __default_kernel_pte_mask __read_mostly = DEFAULT_PTE_MASK; -+pteval_t __default_kernel_pte_mask __ro_after_init = DEFAULT_PTE_MASK; - EXPORT_SYMBOL_GPL(__supported_pte_mask); - /* Used in PAGE_KERNEL_* macros which are reasonably used out-of-tree: */ - EXPORT_SYMBOL(__default_kernel_pte_mask); -diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c -index b5a3fa4033d3..c3d771ffc178 100644 ---- a/arch/x86/mm/init_64.c -+++ b/arch/x86/mm/init_64.c -@@ -97,9 +97,9 @@ DEFINE_ENTRY(pte, pte, init) - */ - - /* Bits supported by the hardware: */ --pteval_t __supported_pte_mask __read_mostly = ~0; -+pteval_t __supported_pte_mask __ro_after_init = ~0; - /* Bits allowed in normal kernel mappings: */ --pteval_t __default_kernel_pte_mask __read_mostly = ~0; -+pteval_t __default_kernel_pte_mask __ro_after_init = ~0; - EXPORT_SYMBOL_GPL(__supported_pte_mask); - /* Used in PAGE_KERNEL_* macros which are reasonably used out-of-tree: */ - EXPORT_SYMBOL(__default_kernel_pte_mask); --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0055-mark-kobj_ns_type_register-as-only-used-for-init.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0055-mark-kobj_ns_type_register-as-only-used-for-init.patch deleted file mode 100644 index e67e1a04ba1e..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0055-mark-kobj_ns_type_register-as-only-used-for-init.patch +++ /dev/null @@ -1,45 +0,0 @@ -From a9c8d6781479778a5f4d3b6a37dcab43f7e4e5f0 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Tue, 4 Jul 2017 01:24:28 -0400 -Subject: [PATCH 055/113] mark kobj_ns_type_register as only used for init - -This allows kobj_ns_ops_tbl to be __ro_after_init. - -Extracted from PaX. ---- - include/linux/kobject_ns.h | 2 +- - lib/kobject.c | 4 ++-- - 2 files changed, 3 insertions(+), 3 deletions(-) - -diff --git a/include/linux/kobject_ns.h b/include/linux/kobject_ns.h -index 2b5b64256cf4..8cdce21dce0f 100644 ---- a/include/linux/kobject_ns.h -+++ b/include/linux/kobject_ns.h -@@ -45,7 +45,7 @@ struct kobj_ns_type_operations { - void (*drop_ns)(void *); - }; - --int kobj_ns_type_register(const struct kobj_ns_type_operations *ops); -+int __init kobj_ns_type_register(const struct kobj_ns_type_operations *ops); - int kobj_ns_type_registered(enum kobj_ns_type type); - const struct kobj_ns_type_operations *kobj_child_ns_ops(struct kobject *parent); - const struct kobj_ns_type_operations *kobj_ns_ops(struct kobject *kobj); -diff --git a/lib/kobject.c b/lib/kobject.c -index ea53b30cf483..5343bbeea5f8 100644 ---- a/lib/kobject.c -+++ b/lib/kobject.c -@@ -1023,9 +1023,9 @@ EXPORT_SYMBOL_GPL(kset_create_and_add); - - - static DEFINE_SPINLOCK(kobj_ns_type_lock); --static const struct kobj_ns_type_operations *kobj_ns_ops_tbl[KOBJ_NS_TYPES]; -+static const struct kobj_ns_type_operations *kobj_ns_ops_tbl[KOBJ_NS_TYPES] __ro_after_init; - --int kobj_ns_type_register(const struct kobj_ns_type_operations *ops) -+int __init kobj_ns_type_register(const struct kobj_ns_type_operations *ops) - { - enum kobj_ns_type type = ops->type; - int error; --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0056-mark-open_softirq-as-only-used-for-init.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0056-mark-open_softirq-as-only-used-for-init.patch deleted file mode 100644 index ab6fb5c02d7e..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0056-mark-open_softirq-as-only-used-for-init.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 5c392668b5b1de733d318a4a78a1cdbd5e4e8364 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Tue, 4 Jul 2017 01:32:30 -0400 -Subject: [PATCH 056/113] mark open_softirq as only used for init - ---- - include/linux/interrupt.h | 2 +- - kernel/softirq.c | 2 +- - 2 files changed, 2 insertions(+), 2 deletions(-) - -diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h -index ee8299eb1f52..f03b78ae5f0a 100644 ---- a/include/linux/interrupt.h -+++ b/include/linux/interrupt.h -@@ -569,7 +569,7 @@ static inline void do_softirq_own_stack(void) - } - #endif - --extern void open_softirq(int nr, void (*action)(struct softirq_action *)); -+extern void __init open_softirq(int nr, void (*action)(struct softirq_action *)); - extern void softirq_init(void); - extern void __raise_softirq_irqoff(unsigned int nr); - -diff --git a/kernel/softirq.c b/kernel/softirq.c -index 09229ad82209..0595a8248c4a 100644 ---- a/kernel/softirq.c -+++ b/kernel/softirq.c -@@ -486,7 +486,7 @@ void __raise_softirq_irqoff(unsigned int nr) - or_softirq_pending(1UL << nr); - } - --void open_softirq(int nr, void (*action)(struct softirq_action *)) -+void __init open_softirq(int nr, void (*action)(struct softirq_action *)) - { - softirq_vec[nr].action = action; - } --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0057-remove-unused-softirq_action-callback-parameter.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0057-remove-unused-softirq_action-callback-parameter.patch deleted file mode 100644 index bec6f980588d..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0057-remove-unused-softirq_action-callback-parameter.patch +++ /dev/null @@ -1,208 +0,0 @@ -From afc4f4480c3f45cc088ae887f06e0472e3846667 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Tue, 4 Jul 2017 01:41:11 -0400 -Subject: [PATCH 057/113] remove unused softirq_action callback parameter - -Extracted from PaX. ---- - block/blk-mq.c | 2 +- - include/linux/interrupt.h | 4 ++-- - kernel/rcu/tiny.c | 2 +- - kernel/rcu/tree.c | 2 +- - kernel/sched/fair.c | 2 +- - kernel/softirq.c | 15 +++++++-------- - kernel/time/hrtimer.c | 2 +- - kernel/time/timer.c | 2 +- - lib/irq_poll.c | 2 +- - net/core/dev.c | 4 ++-- - 10 files changed, 18 insertions(+), 19 deletions(-) - -diff --git a/block/blk-mq.c b/block/blk-mq.c -index 2a1eff60c797..75a0077ea1a9 100644 ---- a/block/blk-mq.c -+++ b/block/blk-mq.c -@@ -569,7 +569,7 @@ EXPORT_SYMBOL(blk_mq_end_request); - * Softirq action handler - move entries to local list and loop over them - * while passing them to the queue registered handler. - */ --static __latent_entropy void blk_done_softirq(struct softirq_action *h) -+static __latent_entropy void blk_done_softirq(void) - { - struct list_head *cpu_list, local_list; - -diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h -index f03b78ae5f0a..4381b79f76cf 100644 ---- a/include/linux/interrupt.h -+++ b/include/linux/interrupt.h -@@ -554,7 +554,7 @@ extern const char * const softirq_to_name[NR_SOFTIRQS]; - - struct softirq_action - { -- void (*action)(struct softirq_action *); -+ void (*action)(void); - }; - - asmlinkage void do_softirq(void); -@@ -569,7 +569,7 @@ static inline void do_softirq_own_stack(void) - } - #endif - --extern void __init open_softirq(int nr, void (*action)(struct softirq_action *)); -+extern void __init open_softirq(int nr, void (*action)(void)); - extern void softirq_init(void); - extern void __raise_softirq_irqoff(unsigned int nr); - -diff --git a/kernel/rcu/tiny.c b/kernel/rcu/tiny.c -index aa897c3f2e92..d8976886fd68 100644 ---- a/kernel/rcu/tiny.c -+++ b/kernel/rcu/tiny.c -@@ -101,7 +101,7 @@ static inline bool rcu_reclaim_tiny(struct rcu_head *head) - } - - /* Invoke the RCU callbacks whose grace period has elapsed. */ --static __latent_entropy void rcu_process_callbacks(struct softirq_action *unused) -+static __latent_entropy void rcu_process_callbacks(void) - { - struct rcu_head *next, *list; - unsigned long flags; -diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c -index 593df7edfe97..3285d81d8a26 100644 ---- a/kernel/rcu/tree.c -+++ b/kernel/rcu/tree.c -@@ -2722,7 +2722,7 @@ static __latent_entropy void rcu_core(void) - queue_work_on(rdp->cpu, rcu_gp_wq, &rdp->strict_work); - } - --static void rcu_core_si(struct softirq_action *h) -+static void rcu_core_si(void) - { - rcu_core(); - } -diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c -index ae7ceba8fd4f..d118be5f18b8 100644 ---- a/kernel/sched/fair.c -+++ b/kernel/sched/fair.c -@@ -10628,7 +10628,7 @@ static int newidle_balance(struct rq *this_rq, struct rq_flags *rf) - * run_rebalance_domains is triggered when needed from the scheduler tick. - * Also triggered for nohz idle balancing (with nohz_balancing_kick set). - */ --static __latent_entropy void run_rebalance_domains(struct softirq_action *h) -+static __latent_entropy void run_rebalance_domains(void) - { - struct rq *this_rq = this_rq(); - enum cpu_idle_type idle = this_rq->idle_balance ? -diff --git a/kernel/softirq.c b/kernel/softirq.c -index 0595a8248c4a..3a21b22227c1 100644 ---- a/kernel/softirq.c -+++ b/kernel/softirq.c -@@ -295,7 +295,7 @@ asmlinkage __visible void __softirq_entry __do_softirq(void) - kstat_incr_softirqs_this_cpu(vec_nr); - - trace_softirq_entry(vec_nr); -- h->action(h); -+ h->action(); - trace_softirq_exit(vec_nr); - if (unlikely(prev_count != preempt_count())) { - pr_err("huh, entered softirq %u %s %p with preempt_count %08x, exited with %08x?\n", -@@ -486,7 +486,7 @@ void __raise_softirq_irqoff(unsigned int nr) - or_softirq_pending(1UL << nr); - } - --void __init open_softirq(int nr, void (*action)(struct softirq_action *)) -+void __init open_softirq(int nr, void (*action)(void)) - { - softirq_vec[nr].action = action; - } -@@ -532,8 +532,7 @@ void __tasklet_hi_schedule(struct tasklet_struct *t) - } - EXPORT_SYMBOL(__tasklet_hi_schedule); - --static void tasklet_action_common(struct softirq_action *a, -- struct tasklet_head *tl_head, -+static void tasklet_action_common(struct tasklet_head *tl_head, - unsigned int softirq_nr) - { - struct tasklet_struct *list; -@@ -573,14 +572,14 @@ static void tasklet_action_common(struct softirq_action *a, - } - } - --static __latent_entropy void tasklet_action(struct softirq_action *a) -+static __latent_entropy void tasklet_action(void) - { -- tasklet_action_common(a, this_cpu_ptr(&tasklet_vec), TASKLET_SOFTIRQ); -+ tasklet_action_common(this_cpu_ptr(&tasklet_vec), TASKLET_SOFTIRQ); - } - --static __latent_entropy void tasklet_hi_action(struct softirq_action *a) -+static __latent_entropy void tasklet_hi_action(void) - { -- tasklet_action_common(a, this_cpu_ptr(&tasklet_hi_vec), HI_SOFTIRQ); -+ tasklet_action_common(this_cpu_ptr(&tasklet_hi_vec), HI_SOFTIRQ); - } - - void tasklet_setup(struct tasklet_struct *t, -diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c -index 387b4bef7dd1..8fe28c28a906 100644 ---- a/kernel/time/hrtimer.c -+++ b/kernel/time/hrtimer.c -@@ -1587,7 +1587,7 @@ static void __hrtimer_run_queues(struct hrtimer_cpu_base *cpu_base, ktime_t now, - } - } - --static __latent_entropy void hrtimer_run_softirq(struct softirq_action *h) -+static __latent_entropy void hrtimer_run_softirq(void) - { - struct hrtimer_cpu_base *cpu_base = this_cpu_ptr(&hrtimer_bases); - unsigned long flags; -diff --git a/kernel/time/timer.c b/kernel/time/timer.c -index c3ad64fb9d8b..217bc49a3856 100644 ---- a/kernel/time/timer.c -+++ b/kernel/time/timer.c -@@ -1753,7 +1753,7 @@ static inline void __run_timers(struct timer_base *base) - /* - * This function runs timers and the timer-tq in bottom half context. - */ --static __latent_entropy void run_timer_softirq(struct softirq_action *h) -+static __latent_entropy void run_timer_softirq(void) - { - struct timer_base *base = this_cpu_ptr(&timer_bases[BASE_STD]); - -diff --git a/lib/irq_poll.c b/lib/irq_poll.c -index 2f17b488d58e..b6e7996a0058 100644 ---- a/lib/irq_poll.c -+++ b/lib/irq_poll.c -@@ -75,7 +75,7 @@ void irq_poll_complete(struct irq_poll *iop) - } - EXPORT_SYMBOL(irq_poll_complete); - --static void __latent_entropy irq_poll_softirq(struct softirq_action *h) -+static void __latent_entropy irq_poll_softirq(void) - { - struct list_head *list = this_cpu_ptr(&blk_cpu_iopoll); - int rearm = 0, budget = irq_poll_budget; -diff --git a/net/core/dev.c b/net/core/dev.c -index 81e5d482c238..172fd10f4b01 100644 ---- a/net/core/dev.c -+++ b/net/core/dev.c -@@ -4856,7 +4856,7 @@ int netif_rx_any_context(struct sk_buff *skb) - } - EXPORT_SYMBOL(netif_rx_any_context); - --static __latent_entropy void net_tx_action(struct softirq_action *h) -+static __latent_entropy void net_tx_action(void) - { - struct softnet_data *sd = this_cpu_ptr(&softnet_data); - -@@ -6803,7 +6803,7 @@ static int napi_poll(struct napi_struct *n, struct list_head *repoll) - return work; - } - --static __latent_entropy void net_rx_action(struct softirq_action *h) -+static __latent_entropy void net_rx_action(void) - { - struct softnet_data *sd = this_cpu_ptr(&softnet_data); - unsigned long time_limit = jiffies + --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0058-mark-softirq_vec-as-__ro_after_init.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0058-mark-softirq_vec-as-__ro_after_init.patch deleted file mode 100644 index 016600649186..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0058-mark-softirq_vec-as-__ro_after_init.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 63b8a34267f8199af0898ec9ceeed076da78d138 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Tue, 4 Jul 2017 01:42:33 -0400 -Subject: [PATCH 058/113] mark softirq_vec as __ro_after_init - -Note: __cacheline_aligned_in_smp conflicts with __ro_after_init on x86. - -Extracted from PaX. ---- - kernel/softirq.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/kernel/softirq.c b/kernel/softirq.c -index 3a21b22227c1..6a02d63b135a 100644 ---- a/kernel/softirq.c -+++ b/kernel/softirq.c -@@ -52,7 +52,7 @@ DEFINE_PER_CPU_ALIGNED(irq_cpustat_t, irq_stat); - EXPORT_PER_CPU_SYMBOL(irq_stat); - #endif - --static struct softirq_action softirq_vec[NR_SOFTIRQS] __cacheline_aligned_in_smp; -+static struct softirq_action softirq_vec[NR_SOFTIRQS] __ro_after_init __aligned(PAGE_SIZE); - - DEFINE_PER_CPU(struct task_struct *, ksoftirqd); - --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0059-mm-slab-trigger-BUG-if-requested-object-is-not-a-sla.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0059-mm-slab-trigger-BUG-if-requested-object-is-not-a-sla.patch deleted file mode 100644 index 46a7e739985f..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0059-mm-slab-trigger-BUG-if-requested-object-is-not-a-sla.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 571b2ad3a286d61ad03c540f39254232e6b3a2c4 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Tue, 17 Sep 2019 18:00:54 +0200 -Subject: [PATCH 059/113] mm: slab: trigger BUG if requested object is not a - slab page - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> -Signed-off-by: Levente Polyak <levente@leventepolyak.net> -Signed-off-by: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr> ---- - mm/slab.h | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/mm/slab.h b/mm/slab.h -index f9977d6613d6..5adb48bb2e68 100644 ---- a/mm/slab.h -+++ b/mm/slab.h -@@ -435,9 +435,13 @@ static inline struct kmem_cache *virt_to_cache(const void *obj) - struct page *page; - - page = virt_to_head_page(obj); -+#ifdef CONFIG_BUG_ON_DATA_CORRUPTION -+ BUG_ON(!PageSlab(page)); -+#else - if (WARN_ONCE(!PageSlab(page), "%s: Object is not a Slab page!\n", - __func__)) - return NULL; -+#endif - return page->slab_cache; - } - --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0060-bug-on-kmem_cache_free-with-the-wrong-cache.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0060-bug-on-kmem_cache_free-with-the-wrong-cache.patch deleted file mode 100644 index 59b6d982192e..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0060-bug-on-kmem_cache_free-with-the-wrong-cache.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 0f86c29273194d587c300415e1ad0d1f10b44142 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Wed, 3 May 2017 11:50:53 -0400 -Subject: [PATCH 060/113] bug on kmem_cache_free with the wrong cache - -At least when CONFIG_BUG_ON_DATA_CORRUPTION is enabled. - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> -Signed-off-by: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr> -Signed-off-by: Levente Polyak <levente@leventepolyak.net> ---- - mm/slab.h | 11 ++++++++--- - 1 file changed, 8 insertions(+), 3 deletions(-) - -diff --git a/mm/slab.h b/mm/slab.h -index 5adb48bb2e68..9fef4285514a 100644 ---- a/mm/slab.h -+++ b/mm/slab.h -@@ -471,10 +471,15 @@ static inline struct kmem_cache *cache_from_obj(struct kmem_cache *s, void *x) - return s; - - cachep = virt_to_cache(x); -- if (WARN(cachep && cachep != s, -- "%s: Wrong slab cache. %s but object is from %s\n", -- __func__, s->name, cachep->name)) -+ if (cachep && cachep != s) { -+#ifdef CONFIG_BUG_ON_DATA_CORRUPTION -+ BUG(); -+#else -+ WARN(1, "%s: Wrong slab cache. %s but object is from %s\n", -+ __func__, s->name, cachep->name); -+#endif - print_tracking(cachep, x); -+ } - return cachep; - } - --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0061-bug-on-PageSlab-PageCompound-in-ksize.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0061-bug-on-PageSlab-PageCompound-in-ksize.patch deleted file mode 100644 index 493213c185e2..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0061-bug-on-PageSlab-PageCompound-in-ksize.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 7393e858694ce70187c84975acbd0bae812b4971 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Wed, 3 May 2017 11:57:35 -0400 -Subject: [PATCH 061/113] bug on !PageSlab && !PageCompound in ksize - -At least when CONFIG_BUG_ON_DATA_CORRUPTION is enabled. - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - mm/slub.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/mm/slub.c b/mm/slub.c -index e01d54dc46e1..07ce7cac2612 100644 ---- a/mm/slub.c -+++ b/mm/slub.c -@@ -4092,7 +4092,11 @@ size_t __ksize(const void *object) - page = virt_to_head_page(object); - - if (unlikely(!PageSlab(page))) { -+#ifdef CONFIG_BUG_ON_DATA_CORRUPTION -+ BUG_ON(!PageCompound(page)); -+#else - WARN_ON(!PageCompound(page)); -+#endif - return page_size(page); - } - --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0062-mm-add-support-for-verifying-page-sanitization.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0062-mm-add-support-for-verifying-page-sanitization.patch deleted file mode 100644 index 7736c1777364..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0062-mm-add-support-for-verifying-page-sanitization.patch +++ /dev/null @@ -1,70 +0,0 @@ -From bc7dde0b61e6e2338808b8ec67bd3215842b4679 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Wed, 3 May 2017 21:54:56 -0400 -Subject: [PATCH 062/113] mm: add support for verifying page sanitization - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> -Signed-off-by: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr> -Signed-off-by: Levente Polyak <levente@leventepolyak.net> ---- - include/linux/highmem.h | 7 +++++++ - mm/page_alloc.c | 6 ++++++ - security/Kconfig.hardening | 7 +++++++ - 3 files changed, 20 insertions(+) - -diff --git a/include/linux/highmem.h b/include/linux/highmem.h -index 14e6202ce47f..4348ad7f5c50 100644 ---- a/include/linux/highmem.h -+++ b/include/linux/highmem.h -@@ -284,6 +284,13 @@ static inline void clear_highpage(struct page *page) - kunmap_atomic(kaddr); - } - -+static inline void verify_zero_highpage(struct page *page) -+{ -+ void *kaddr = kmap_atomic(page); -+ BUG_ON(memchr_inv(kaddr, 0, PAGE_SIZE)); -+ kunmap_atomic(kaddr); -+} -+ - static inline void zero_user_segments(struct page *page, - unsigned start1, unsigned end1, - unsigned start2, unsigned end2) -diff --git a/mm/page_alloc.c b/mm/page_alloc.c -index 88639706ae17..e014e6df1f39 100644 ---- a/mm/page_alloc.c -+++ b/mm/page_alloc.c -@@ -2284,6 +2284,12 @@ static void prep_new_page(struct page *page, unsigned int order, gfp_t gfp_flags - { - post_alloc_hook(page, order, gfp_flags); - -+ if (IS_ENABLED(CONFIG_PAGE_SANITIZE_VERIFY) && want_init_on_free()) { -+ int i; -+ for (i = 0; i < (1 << order); i++) -+ verify_zero_highpage(page + i); -+ } -+ - if (!free_pages_prezeroed() && want_init_on_alloc(gfp_flags)) - kernel_init_free_pages(page, 1 << order); - -diff --git a/security/Kconfig.hardening b/security/Kconfig.hardening -index 2fa447823405..83ad70ae6bc3 100644 ---- a/security/Kconfig.hardening -+++ b/security/Kconfig.hardening -@@ -219,6 +219,13 @@ config INIT_ON_FREE_DEFAULT_ON - touching "cold" memory areas. Most cases see 3-5% impact. Some - synthetic workloads have measured as high as 8%. - -+config PAGE_SANITIZE_VERIFY -+ bool "Verify sanitized pages" -+ default y -+ help -+ When init_on_free is enabled, verify that newly allocated pages -+ are zeroed to detect write-after-free bugs. -+ - endmenu - - endmenu --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0063-slub-Extend-init_on_free-to-slab-caches-with-constru.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0063-slub-Extend-init_on_free-to-slab-caches-with-constru.patch deleted file mode 100644 index b25bd5bab8c3..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0063-slub-Extend-init_on_free-to-slab-caches-with-constru.patch +++ /dev/null @@ -1,75 +0,0 @@ -From a43cf7ac21ce15f4d84e2174d15d6cb425e9b512 Mon Sep 17 00:00:00 2001 -From: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr> -Date: Fri, 20 Sep 2019 14:02:42 +0200 -Subject: [PATCH 063/113] slub: Extend init_on_free to slab caches with - constructors - -This is the remaining non-upstream part of SLAB_SANITIZE, which was a -partial port, from Daniel Micay, of the feature from PaX without the -default fast mode based on passing SLAB_NO_SANITIZE in -performance-critical cases that are not particularly security sensitive. - -Signed-off-by: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr> ---- - mm/slab.h | 12 +++++++++--- - mm/slub.c | 14 +++++++++++++- - 2 files changed, 22 insertions(+), 4 deletions(-) - -diff --git a/mm/slab.h b/mm/slab.h -index 9fef4285514a..0fcd97a4eb6f 100644 ---- a/mm/slab.h -+++ b/mm/slab.h -@@ -641,9 +641,15 @@ static inline bool slab_want_init_on_alloc(gfp_t flags, struct kmem_cache *c) - - static inline bool slab_want_init_on_free(struct kmem_cache *c) - { -- if (static_branch_unlikely(&init_on_free)) -- return !(c->ctor || -- (c->flags & (SLAB_TYPESAFE_BY_RCU | SLAB_POISON))); -+ if (static_branch_unlikely(&init_on_free)) { -+#ifndef CONFIG_SLUB -+ if (c->ctor) -+ return false; -+#endif -+ if (c->flags & (SLAB_TYPESAFE_BY_RCU | SLAB_POISON)) -+ return false; -+ return true; -+ } - return false; - } - -diff --git a/mm/slub.c b/mm/slub.c -index 07ce7cac2612..ac22d6831b9b 100644 ---- a/mm/slub.c -+++ b/mm/slub.c -@@ -1571,7 +1571,8 @@ static inline bool slab_free_freelist_hook(struct kmem_cache *s, - : 0; - memset((char *)object + s->inuse, 0, - s->size - s->inuse - rsize); -- -+ if (s->ctor) -+ s->ctor(object); - } - /* If object's reuse doesn't have to be delayed */ - if (!slab_free_hook(s, object)) { -@@ -1580,6 +1581,17 @@ static inline bool slab_free_freelist_hook(struct kmem_cache *s, - *head = object; - if (!*tail) - *tail = object; -+ } else if (slab_want_init_on_free(s) && s->ctor) { -+ /* Objects that are put into quarantine by KASAN will -+ * still undergo free_consistency_checks() and thus -+ * need to show a valid freepointer to check_object(). -+ * -+ * Note that doing this for all caches (not just ctor -+ * ones, which have s->offset != NULL)) causes a GPF, -+ * due to KASAN poisoning and the way set_freepointer() -+ * eventually dereferences the freepointer. -+ */ -+ set_freepointer(s, object, NULL); - } - } while (object != old_tail); - --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0064-slub-Add-support-for-verifying-slab-sanitization.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0064-slub-Add-support-for-verifying-slab-sanitization.patch deleted file mode 100644 index ca874b24c2f9..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0064-slub-Add-support-for-verifying-slab-sanitization.patch +++ /dev/null @@ -1,116 +0,0 @@ -From 8f0488b0635cde0c47b48f2d37cdf7b24bdb7192 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Thu, 4 May 2017 15:58:57 -0400 -Subject: [PATCH 064/113] slub: Add support for verifying slab sanitization - -This is an extension to the sanitization feature in PaX for when -sacricifing more performance for security is acceptable. - -The initial version from Daniel Micay was relying on PAGE_SANITIZE. It -now relies on upstream's init_on_free. - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> -Signed-off-by: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr> -Signed-off-by: Levente Polyak <levente@leventepolyak.net> ---- - mm/slub.c | 36 ++++++++++++++++++++++++++++++++---- - security/Kconfig.hardening | 8 ++++++++ - 2 files changed, 40 insertions(+), 4 deletions(-) - -diff --git a/mm/slub.c b/mm/slub.c -index ac22d6831b9b..e8e0efa18bd3 100644 ---- a/mm/slub.c -+++ b/mm/slub.c -@@ -127,6 +127,12 @@ static inline bool kmem_cache_debug(struct kmem_cache *s) - return kmem_cache_debug_flags(s, SLAB_DEBUG_FLAGS); - } - -+static inline bool has_sanitize_verify(struct kmem_cache *s) -+{ -+ return IS_ENABLED(CONFIG_SLAB_SANITIZE_VERIFY) && -+ slab_want_init_on_free(s); -+} -+ - void *fixup_red_left(struct kmem_cache *s, void *p) - { - if (kmem_cache_debug_flags(s, SLAB_RED_ZONE)) -@@ -1571,7 +1577,7 @@ static inline bool slab_free_freelist_hook(struct kmem_cache *s, - : 0; - memset((char *)object + s->inuse, 0, - s->size - s->inuse - rsize); -- if (s->ctor) -+ if (!IS_ENABLED(CONFIG_SLAB_SANITIZE_VERIFY) && s->ctor) - s->ctor(object); - } - /* If object's reuse doesn't have to be delayed */ -@@ -1606,7 +1612,7 @@ static void *setup_object(struct kmem_cache *s, struct page *page, - { - setup_object_debug(s, page, object); - object = kasan_init_slab_obj(s, object); -- if (unlikely(s->ctor)) { -+ if (unlikely(s->ctor) && !has_sanitize_verify(s)) { - kasan_unpoison_object_data(s, object); - s->ctor(object); - kasan_poison_object_data(s, object); -@@ -2897,7 +2903,16 @@ static __always_inline void *slab_alloc_node(struct kmem_cache *s, - - maybe_wipe_obj_freeptr(s, object); - -- if (unlikely(slab_want_init_on_alloc(gfpflags, s)) && object) -+ if (has_sanitize_verify(s) && object) { -+ /* KASAN hasn't unpoisoned the object yet (this is done in the -+ * post-alloc hook), so let's do it temporarily. -+ */ -+ kasan_unpoison_object_data(s, object); -+ BUG_ON(memchr_inv(object, 0, s->object_size)); -+ if (s->ctor) -+ s->ctor(object); -+ kasan_poison_object_data(s, object); -+ } else if (unlikely(slab_want_init_on_alloc(gfpflags, s)) && object) - memset(object, 0, s->object_size); - - slab_post_alloc_hook(s, objcg, gfpflags, 1, &object); -@@ -3337,7 +3352,20 @@ int kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size, - local_irq_enable(); - - /* Clear memory outside IRQ disabled fastpath loop */ -- if (unlikely(slab_want_init_on_alloc(flags, s))) { -+ if (has_sanitize_verify(s)) { -+ int j; -+ -+ for (j = 0; j < i; j++) { -+ /* KASAN hasn't unpoisoned the object yet (this is done -+ * in the post-alloc hook), so let's do it temporarily. -+ */ -+ kasan_unpoison_object_data(s, p[j]); -+ BUG_ON(memchr_inv(p[j], 0, s->object_size)); -+ if (s->ctor) -+ s->ctor(p[j]); -+ kasan_poison_object_data(s, p[j]); -+ } -+ } else if (unlikely(slab_want_init_on_alloc(flags, s))) { - int j; - - for (j = 0; j < i; j++) -diff --git a/security/Kconfig.hardening b/security/Kconfig.hardening -index 83ad70ae6bc3..7dede18f1074 100644 ---- a/security/Kconfig.hardening -+++ b/security/Kconfig.hardening -@@ -226,6 +226,14 @@ config PAGE_SANITIZE_VERIFY - When init_on_free is enabled, verify that newly allocated pages - are zeroed to detect write-after-free bugs. - -+config SLAB_SANITIZE_VERIFY -+ bool "Verify sanitized SLAB allocations" -+ default y -+ depends on !KASAN -+ help -+ When init_on_free is enabled, verify that newly allocated slab -+ objects are zeroed to detect write-after-free bugs. -+ - endmenu - - endmenu --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0065-slub-add-multi-purpose-random-canaries.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0065-slub-add-multi-purpose-random-canaries.patch deleted file mode 100644 index 62df822d3148..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0065-slub-add-multi-purpose-random-canaries.patch +++ /dev/null @@ -1,264 +0,0 @@ -From 6a1b579e33c5de45bc28314b0d165953b7b7f0c1 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Wed, 3 May 2017 16:16:58 -0400 -Subject: [PATCH 065/113] slub: add multi-purpose random canaries - -From the configuration option: - - Place canaries at the end of kernel slab allocations, sacrificing - some performance and memory usage for security. - - Canaries can detect some forms of heap corruption when allocations - are freed and as part of the HARDENED_USERCOPY feature. It provides - basic use-after-free detection for HARDENED_USERCOPY. - - Canaries absorb small overflows (rendering them harmless), mitigate - non-NUL terminated C string overflows on 64-bit via a guaranteed zero - byte and provide basic double-free detection. - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - include/linux/slub_def.h | 5 +++ - init/Kconfig | 17 ++++++++++ - mm/slab.h | 2 +- - mm/slub.c | 69 ++++++++++++++++++++++++++++++++++++++-- - 4 files changed, 89 insertions(+), 4 deletions(-) - -diff --git a/include/linux/slub_def.h b/include/linux/slub_def.h -index 1be0ed5befa1..c71cf30b5987 100644 ---- a/include/linux/slub_def.h -+++ b/include/linux/slub_def.h -@@ -113,6 +113,11 @@ struct kmem_cache { - unsigned long random; - #endif - -+#ifdef CONFIG_SLAB_CANARY -+ unsigned long random_active; -+ unsigned long random_inactive; -+#endif -+ - #ifdef CONFIG_NUMA - /* - * Defragmentation by allocating from a remote node. -diff --git a/init/Kconfig b/init/Kconfig -index 58df4930995f..2af6689d9e71 100644 ---- a/init/Kconfig -+++ b/init/Kconfig -@@ -1943,6 +1943,23 @@ config SLAB_FREELIST_HARDENED - sanity-checking than others. This option is most effective with - CONFIG_SLUB. - -+config SLAB_CANARY -+ depends on SLUB -+ depends on !SLAB_MERGE_DEFAULT -+ bool "SLAB canaries" -+ default y -+ help -+ Place canaries at the end of kernel slab allocations, sacrificing -+ some performance and memory usage for security. -+ -+ Canaries can detect some forms of heap corruption when allocations -+ are freed and as part of the HARDENED_USERCOPY feature. It provides -+ basic use-after-free detection for HARDENED_USERCOPY. -+ -+ Canaries absorb small overflows (rendering them harmless), mitigate -+ non-NUL terminated C string overflows on 64-bit via a guaranteed zero -+ byte and provide basic double-free detection. -+ - config SHUFFLE_PAGE_ALLOCATOR - bool "Page allocator randomization" - default SLAB_FREELIST_RANDOM && ACPI_NUMA -diff --git a/mm/slab.h b/mm/slab.h -index 0fcd97a4eb6f..105dba485a7e 100644 ---- a/mm/slab.h -+++ b/mm/slab.h -@@ -504,7 +504,7 @@ static inline size_t slab_ksize(const struct kmem_cache *s) - * back there or track user information then we can - * only use the space before that information. - */ -- if (s->flags & (SLAB_TYPESAFE_BY_RCU | SLAB_STORE_USER)) -+ if ((s->flags & (SLAB_TYPESAFE_BY_RCU | SLAB_STORE_USER)) || IS_ENABLED(CONFIG_SLAB_CANARY)) - return s->inuse; - /* - * Else we can use all the padding etc for the allocation -diff --git a/mm/slub.c b/mm/slub.c -index e8e0efa18bd3..dd68308c94a9 100644 ---- a/mm/slub.c -+++ b/mm/slub.c -@@ -569,6 +569,33 @@ static inline unsigned int get_info_end(struct kmem_cache *s) - return s->inuse; - } - -+#ifdef CONFIG_SLAB_CANARY -+static inline unsigned long *get_canary(struct kmem_cache *s, void *object) -+{ -+ return object + get_info_end(s); -+} -+ -+static inline unsigned long get_canary_value(const void *canary, unsigned long value) -+{ -+ return (value ^ (unsigned long)canary) & CANARY_MASK; -+} -+ -+static inline void set_canary(struct kmem_cache *s, void *object, unsigned long value) -+{ -+ unsigned long *canary = get_canary(s, object); -+ *canary = get_canary_value(canary, value); -+} -+ -+static inline void check_canary(struct kmem_cache *s, void *object, unsigned long value) -+{ -+ unsigned long *canary = get_canary(s, object); -+ BUG_ON(*canary != get_canary_value(canary, value)); -+} -+#else -+#define set_canary(s, object, value) -+#define check_canary(s, object, value) -+#endif -+ - static struct track *get_track(struct kmem_cache *s, void *object, - enum track_item alloc) - { -@@ -576,6 +603,9 @@ static struct track *get_track(struct kmem_cache *s, void *object, - - p = object + get_info_end(s); - -+ if (IS_ENABLED(CONFIG_SLAB_CANARY)) -+ p = (void *)p + sizeof(void *); -+ - return p + alloc; - } - -@@ -717,6 +747,9 @@ static void print_trailer(struct kmem_cache *s, struct page *page, u8 *p) - - off = get_info_end(s); - -+ if (IS_ENABLED(CONFIG_SLAB_CANARY)) -+ off += sizeof(void *); -+ - if (s->flags & SLAB_STORE_USER) - off += 2 * sizeof(struct track); - -@@ -825,8 +858,9 @@ static int check_bytes_and_report(struct kmem_cache *s, struct page *page, - * Meta data starts here. - * - * A. Free pointer (if we cannot overwrite object on free) -- * B. Tracking data for SLAB_STORE_USER -- * C. Padding to reach required alignment boundary or at mininum -+ * B. Canary for SLAB_CANARY -+ * C. Tracking data for SLAB_STORE_USER -+ * D. Padding to reach required alignment boundary or at mininum - * one word if debugging is on to be able to detect writes - * before the word boundary. - * -@@ -844,6 +878,9 @@ static int check_pad_bytes(struct kmem_cache *s, struct page *page, u8 *p) - { - unsigned long off = get_info_end(s); /* The end of info */ - -+ if (IS_ENABLED(CONFIG_SLAB_CANARY)) -+ off += sizeof(void *); -+ - if (s->flags & SLAB_STORE_USER) - /* We also have user information there */ - off += 2 * sizeof(struct track); -@@ -1567,6 +1604,8 @@ static inline bool slab_free_freelist_hook(struct kmem_cache *s, - object = next; - next = get_freepointer(s, object); - -+ check_canary(s, object, s->random_active); -+ - if (slab_want_init_on_free(s)) { - /* - * Clear the object and the metadata, but don't touch -@@ -1580,6 +1619,9 @@ static inline bool slab_free_freelist_hook(struct kmem_cache *s, - if (!IS_ENABLED(CONFIG_SLAB_SANITIZE_VERIFY) && s->ctor) - s->ctor(object); - } -+ -+ set_canary(s, object, s->random_inactive); -+ - /* If object's reuse doesn't have to be delayed */ - if (!slab_free_hook(s, object)) { - /* Move object to the new freelist */ -@@ -1611,6 +1653,7 @@ static void *setup_object(struct kmem_cache *s, struct page *page, - void *object) - { - setup_object_debug(s, page, object); -+ set_canary(s, object, s->random_inactive); - object = kasan_init_slab_obj(s, object); - if (unlikely(s->ctor) && !has_sanitize_verify(s)) { - kasan_unpoison_object_data(s, object); -@@ -2915,6 +2958,11 @@ static __always_inline void *slab_alloc_node(struct kmem_cache *s, - } else if (unlikely(slab_want_init_on_alloc(gfpflags, s)) && object) - memset(object, 0, s->object_size); - -+ if (object) { -+ check_canary(s, object, s->random_inactive); -+ set_canary(s, object, s->random_active); -+ } -+ - slab_post_alloc_hook(s, objcg, gfpflags, 1, &object); - - return object; -@@ -3302,7 +3350,7 @@ int kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size, - void **p) - { - struct kmem_cache_cpu *c; -- int i; -+ int i, k; - struct obj_cgroup *objcg = NULL; - - /* memcg and kmem_cache debug support */ -@@ -3372,6 +3420,11 @@ int kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size, - memset(p[j], 0, s->object_size); - } - -+ for (k = 0; k < i; k++) { -+ check_canary(s, p[k], s->random_inactive); -+ set_canary(s, p[k], s->random_active); -+ } -+ - /* memcg and kmem_cache debug support */ - slab_post_alloc_hook(s, objcg, flags, size, p); - return i; -@@ -3573,6 +3626,7 @@ static void early_kmem_cache_node_alloc(int node) - init_object(kmem_cache_node, n, SLUB_RED_ACTIVE); - init_tracking(kmem_cache_node, n); - #endif -+ set_canary(kmem_cache_node, n, kmem_cache_node->random_active); - n = kasan_kmalloc(kmem_cache_node, n, sizeof(struct kmem_cache_node), - GFP_KERNEL); - page->freelist = get_freepointer(kmem_cache_node, n); -@@ -3753,6 +3807,9 @@ static int calculate_sizes(struct kmem_cache *s, int forced_order) - s->offset = ALIGN(freepointer_area / 2, sizeof(void *)); - } - -+ if (IS_ENABLED(CONFIG_SLAB_CANARY)) -+ size += sizeof(void *); -+ - #ifdef CONFIG_SLUB_DEBUG - if (flags & SLAB_STORE_USER) - /* -@@ -3826,6 +3883,10 @@ static int kmem_cache_open(struct kmem_cache *s, slab_flags_t flags) - #ifdef CONFIG_SLAB_FREELIST_HARDENED - s->random = get_random_long(); - #endif -+#ifdef CONFIG_SLAB_CANARY -+ s->random_active = get_random_long(); -+ s->random_inactive = get_random_long(); -+#endif - - if (!calculate_sizes(s, -1)) - goto error; -@@ -4099,6 +4160,8 @@ void __check_heap_object(const void *ptr, unsigned long n, struct page *page, - offset -= s->red_left_pad; - } - -+ check_canary(s, (void *)ptr - offset, s->random_active); -+ - /* Allow address range falling entirely within usercopy region. */ - if (offset >= s->useroffset && - offset - s->useroffset <= s->usersize && --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0066-security-perf-Allow-further-restriction-of-perf_even.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0066-security-perf-Allow-further-restriction-of-perf_even.patch deleted file mode 100644 index 261283f05ff3..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0066-security-perf-Allow-further-restriction-of-perf_even.patch +++ /dev/null @@ -1,122 +0,0 @@ -From b0162949f7d49b21bc7fe2bfab91e0b8c5da90f7 Mon Sep 17 00:00:00 2001 -From: Ben Hutchings <ben@decadent.org.uk> -Date: Mon, 11 Jan 2016 15:23:55 +0000 -Subject: [PATCH 066/113] security,perf: Allow further restriction of - perf_event_open - -When kernel.perf_event_open is set to 3 (or greater), disallow all -access to performance events by users without CAP_SYS_ADMIN. -Add a Kconfig symbol CONFIG_SECURITY_PERF_EVENTS_RESTRICT that -makes this value the default. - -This is based on a similar feature in grsecurity -(CONFIG_GRKERNSEC_PERF_HARDEN). This version doesn't include making -the variable read-only. It also allows enabling further restriction -at run-time regardless of whether the default is changed. - -Signed-off-by: Ben Hutchings <ben@decadent.org.uk> -Signed-off-by: Levente Polyak <levente@leventepolyak.net> -[thibaut.sautereau@ssi.gouv.fr: Adapt to work with the new CAP_PERFMON capability] -Signed-off-by: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr> ---- - Documentation/admin-guide/sysctl/kernel.rst | 2 ++ - include/linux/perf_event.h | 8 ++++++++ - kernel/events/core.c | 7 ++++++- - security/Kconfig | 9 +++++++++ - tools/perf/Documentation/security.txt | 1 + - 5 files changed, 26 insertions(+), 1 deletion(-) - -diff --git a/Documentation/admin-guide/sysctl/kernel.rst b/Documentation/admin-guide/sysctl/kernel.rst -index d4b32cc32bb7..4c20e6ded0af 100644 ---- a/Documentation/admin-guide/sysctl/kernel.rst -+++ b/Documentation/admin-guide/sysctl/kernel.rst -@@ -860,6 +860,8 @@ with respect to CAP_PERFMON use cases. - >=1 Disallow CPU event access by users without ``CAP_PERFMON``. - - >=2 Disallow kernel profiling by users without ``CAP_PERFMON``. -+ -+>=3 Disallow use of any event by users without ``CAP_PERFMON``. - === ================================================================== - - -diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h -index 96450f6fb1de..d020c26b612a 100644 ---- a/include/linux/perf_event.h -+++ b/include/linux/perf_event.h -@@ -1312,6 +1312,14 @@ static inline int perf_is_paranoid(void) - return sysctl_perf_event_paranoid > -1; - } - -+static inline int perf_allow_open(struct perf_event_attr *attr) -+{ -+ if (sysctl_perf_event_paranoid > 2 && !perfmon_capable()) -+ return -EACCES; -+ -+ return security_perf_event_open(attr, PERF_SECURITY_OPEN); -+} -+ - static inline int perf_allow_kernel(struct perf_event_attr *attr) - { - if (sysctl_perf_event_paranoid > 1 && !perfmon_capable()) -diff --git a/kernel/events/core.c b/kernel/events/core.c -index c3ba29d058b7..6efbf92763b1 100644 ---- a/kernel/events/core.c -+++ b/kernel/events/core.c -@@ -407,8 +407,13 @@ static cpumask_var_t perf_online_mask; - * 0 - disallow raw tracepoint access for unpriv - * 1 - disallow cpu events for unpriv - * 2 - disallow kernel profiling for unpriv -+ * 3 - disallow all unpriv perf event use - */ -+#ifdef CONFIG_SECURITY_PERF_EVENTS_RESTRICT -+int sysctl_perf_event_paranoid __read_mostly = 3; -+#else - int sysctl_perf_event_paranoid __read_mostly = 2; -+#endif - - /* Minimum for 512 kiB + 1 user control page */ - int sysctl_perf_event_mlock __read_mostly = 512 + (PAGE_SIZE / 1024); /* 'free' kiB per user */ -@@ -11638,7 +11643,7 @@ SYSCALL_DEFINE5(perf_event_open, - return -EINVAL; - - /* Do we allow access to perf_event_open(2) ? */ -- err = security_perf_event_open(&attr, PERF_SECURITY_OPEN); -+ err = perf_allow_open(&attr); - if (err) - return err; - -diff --git a/security/Kconfig b/security/Kconfig -index 81d0a08736aa..c797326308f1 100644 ---- a/security/Kconfig -+++ b/security/Kconfig -@@ -19,6 +19,15 @@ config SECURITY_DMESG_RESTRICT - - If you are unsure how to answer this question, answer N. - -+config SECURITY_PERF_EVENTS_RESTRICT -+ bool "Restrict unprivileged use of performance events" -+ depends on PERF_EVENTS -+ help -+ If you say Y here, the kernel.perf_event_paranoid sysctl -+ will be set to 3 by default, and no unprivileged use of the -+ perf_event_open syscall will be permitted unless it is -+ changed. -+ - config SECURITY - bool "Enable different security models" - depends on SYSFS -diff --git a/tools/perf/Documentation/security.txt b/tools/perf/Documentation/security.txt -index 4fe3b8b1958f..a7d88cc23a70 100644 ---- a/tools/perf/Documentation/security.txt -+++ b/tools/perf/Documentation/security.txt -@@ -148,6 +148,7 @@ Perf tool provides a message similar to the one below: - >= 0: Disallow raw and ftrace function tracepoint access - >= 1: Disallow CPU event access - >= 2: Disallow kernel profiling -+ >= 3: Disallow use of any event - To make the adjusted perf_event_paranoid setting permanent preserve it - in /etc/sysctl.conf (e.g. kernel.perf_event_paranoid = <setting>) - --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0067-enable-SECURITY_PERF_EVENTS_RESTRICT-by-default.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0067-enable-SECURITY_PERF_EVENTS_RESTRICT-by-default.patch deleted file mode 100644 index d6d9e17692d1..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0067-enable-SECURITY_PERF_EVENTS_RESTRICT-by-default.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 06a8f90667eaa999aaf2225fc4221fc455ad953a Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Thu, 4 May 2017 14:45:59 -0400 -Subject: [PATCH 067/113] enable SECURITY_PERF_EVENTS_RESTRICT by default - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - security/Kconfig | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/security/Kconfig b/security/Kconfig -index c797326308f1..2348ff7d4e1d 100644 ---- a/security/Kconfig -+++ b/security/Kconfig -@@ -22,6 +22,7 @@ config SECURITY_DMESG_RESTRICT - config SECURITY_PERF_EVENTS_RESTRICT - bool "Restrict unprivileged use of performance events" - depends on PERF_EVENTS -+ default y - help - If you say Y here, the kernel.perf_event_paranoid sysctl - will be set to 3 by default, and no unprivileged use of the --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0068-add-sysctl-to-disallow-unprivileged-CLONE_NEWUSER-by.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0068-add-sysctl-to-disallow-unprivileged-CLONE_NEWUSER-by.patch deleted file mode 100644 index b920225fc31c..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0068-add-sysctl-to-disallow-unprivileged-CLONE_NEWUSER-by.patch +++ /dev/null @@ -1,124 +0,0 @@ -From fb241fbe65be75b423445df03475adefcddb6830 Mon Sep 17 00:00:00 2001 -From: Serge Hallyn <serge.hallyn@canonical.com> -Date: Fri, 31 May 2013 19:12:12 +0100 -Subject: [PATCH 068/113] add sysctl to disallow unprivileged CLONE_NEWUSER by - default - -Signed-off-by: Serge Hallyn <serge.hallyn@ubuntu.com> -[bwh: Remove unneeded binary sysctl bits] -Signed-off-by: Daniel Micay <danielmicay@gmail.com> -[thibaut.sautereau@ssi.gouv.fr: Adapt to sysctl code refactoring] -Signed-off-by: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr> -Signed-off-by: Levente Polyak <levente@leventepolyak.net> ---- - include/linux/user_namespace.h | 4 ++++ - kernel/fork.c | 11 +++++++++++ - kernel/sysctl.c | 12 ++++++++++++ - kernel/user_namespace.c | 3 +++ - 4 files changed, 30 insertions(+) - -diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h -index 6ef1c7109fc4..2140091b0b8d 100644 ---- a/include/linux/user_namespace.h -+++ b/include/linux/user_namespace.h -@@ -106,6 +106,8 @@ void dec_ucount(struct ucounts *ucounts, enum ucount_type type); - - #ifdef CONFIG_USER_NS - -+extern int unprivileged_userns_clone; -+ - static inline struct user_namespace *get_user_ns(struct user_namespace *ns) - { - if (ns) -@@ -139,6 +141,8 @@ extern bool current_in_userns(const struct user_namespace *target_ns); - struct ns_common *ns_get_owner(struct ns_common *ns); - #else - -+#define unprivileged_userns_clone 0 -+ - static inline struct user_namespace *get_user_ns(struct user_namespace *ns) - { - return &init_user_ns; -diff --git a/kernel/fork.c b/kernel/fork.c -index c675fdbd3dce..cba344194fba 100644 ---- a/kernel/fork.c -+++ b/kernel/fork.c -@@ -82,6 +82,7 @@ - #include <linux/perf_event.h> - #include <linux/posix-timers.h> - #include <linux/user-return-notifier.h> -+#include <linux/user_namespace.h> - #include <linux/oom.h> - #include <linux/khugepaged.h> - #include <linux/signalfd.h> -@@ -1863,6 +1864,10 @@ static __latent_entropy struct task_struct *copy_process( - if ((clone_flags & (CLONE_NEWUSER|CLONE_FS)) == (CLONE_NEWUSER|CLONE_FS)) - return ERR_PTR(-EINVAL); - -+ if ((clone_flags & CLONE_NEWUSER) && !unprivileged_userns_clone) -+ if (!capable(CAP_SYS_ADMIN)) -+ return ERR_PTR(-EPERM); -+ - /* - * Thread groups must share signals as well, and detached threads - * can only be started up within the thread group. -@@ -2928,6 +2933,12 @@ int ksys_unshare(unsigned long unshare_flags) - if (unshare_flags & CLONE_NEWNS) - unshare_flags |= CLONE_FS; - -+ if ((unshare_flags & CLONE_NEWUSER) && !unprivileged_userns_clone) { -+ err = -EPERM; -+ if (!capable(CAP_SYS_ADMIN)) -+ goto bad_unshare_out; -+ } -+ - err = check_unshare_flags(unshare_flags); - if (err) - goto bad_unshare_out; -diff --git a/kernel/sysctl.c b/kernel/sysctl.c -index b2cd3dbbb17a..fccf24a08c8a 100644 ---- a/kernel/sysctl.c -+++ b/kernel/sysctl.c -@@ -103,6 +103,9 @@ - #ifdef CONFIG_LOCKUP_DETECTOR - #include <linux/nmi.h> - #endif -+#ifdef CONFIG_USER_NS -+#include <linux/user_namespace.h> -+#endif - - #if defined(CONFIG_SYSCTL) - -@@ -1902,6 +1905,15 @@ static struct ctl_table kern_table[] = { - .proc_handler = proc_dointvec, - }, - #endif -+#ifdef CONFIG_USER_NS -+ { -+ .procname = "unprivileged_userns_clone", -+ .data = &unprivileged_userns_clone, -+ .maxlen = sizeof(int), -+ .mode = 0644, -+ .proc_handler = proc_dointvec, -+ }, -+#endif - #ifdef CONFIG_PROC_SYSCTL - { - .procname = "tainted", -diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c -index e703d5d9cbe8..29a30cff5e60 100644 ---- a/kernel/user_namespace.c -+++ b/kernel/user_namespace.c -@@ -21,6 +21,9 @@ - #include <linux/bsearch.h> - #include <linux/sort.h> - -+/* sysctl */ -+int unprivileged_userns_clone; -+ - static struct kmem_cache *user_ns_cachep __read_mostly; - static DEFINE_MUTEX(userns_state_mutex); - --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0069-add-CONFIG-for-unprivileged_userns_clone.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0069-add-CONFIG-for-unprivileged_userns_clone.patch deleted file mode 100644 index da79ac4598de..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0069-add-CONFIG-for-unprivileged_userns_clone.patch +++ /dev/null @@ -1,66 +0,0 @@ -From 54f2484c6173d5d112777e65b69bd2c8dcd992ae Mon Sep 17 00:00:00 2001 -From: Levente Polyak <levente@leventepolyak.net> -Date: Wed, 31 Jul 2019 20:50:48 +0100 -Subject: [PATCH 069/113] add CONFIG for unprivileged_userns_clone - -When disabled, unprivileged users will not be able to create -new namespaces. Allowing users to create their own namespaces -has been part of several recent local privilege escalation -exploits, so if you need user namespaces but are -paranoid^Wsecurity-conscious you want to disable this. - -By default unprivileged user namespaces are disabled. - -Authored-by: Jan Alexander Steffens (heftig) <jan.steffens@gmail.com> -Edited-by: Levente Polyak (anthraxx) <levente@leventepolyak.net> ---- - init/Kconfig | 16 ++++++++++++++++ - kernel/user_namespace.c | 4 ++++ - 2 files changed, 20 insertions(+) - -diff --git a/init/Kconfig b/init/Kconfig -index 2af6689d9e71..a7b5a4cb7939 100644 ---- a/init/Kconfig -+++ b/init/Kconfig -@@ -1174,6 +1174,22 @@ config USER_NS - - If unsure, say N. - -+config USER_NS_UNPRIVILEGED -+ bool "Allow unprivileged users to create namespaces" -+ depends on USER_NS -+ default n -+ help -+ When disabled, unprivileged users will not be able to create -+ new namespaces. Allowing users to create their own namespaces -+ has been part of several recent local privilege escalation -+ exploits, so if you need user namespaces but are -+ paranoid^Wsecurity-conscious you want to disable this. -+ -+ This setting can be overridden at runtime via the -+ kernel.unprivileged_userns_clone sysctl. -+ -+ If unsure, say N. -+ - config PID_NS - bool "PID Namespaces" - default y -diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c -index 29a30cff5e60..5758274feaee 100644 ---- a/kernel/user_namespace.c -+++ b/kernel/user_namespace.c -@@ -22,7 +22,11 @@ - #include <linux/sort.h> - - /* sysctl */ -+#ifdef CONFIG_USER_NS_UNPRIVILEGED -+int unprivileged_userns_clone = 1; -+#else - int unprivileged_userns_clone; -+#endif - - static struct kmem_cache *user_ns_cachep __read_mostly; - static DEFINE_MUTEX(userns_state_mutex); --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0070-add-kmalloc-krealloc-alloc_size-attributes.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0070-add-kmalloc-krealloc-alloc_size-attributes.patch deleted file mode 100644 index a2ab6d14968a..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0070-add-kmalloc-krealloc-alloc_size-attributes.patch +++ /dev/null @@ -1,65 +0,0 @@ -From ccf251e3b0fe0dfc30650b5d373e8ad22c40f2a7 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Wed, 3 May 2017 12:02:56 -0400 -Subject: [PATCH 070/113] add kmalloc/krealloc alloc_size attributes - -Note that this is overly strict when combined with ksize users accessing -beyond the requested data size. - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - include/linux/slab.h | 10 +++++----- - 1 file changed, 5 insertions(+), 5 deletions(-) - -diff --git a/include/linux/slab.h b/include/linux/slab.h -index dd6897f62010..78f99835b91b 100644 ---- a/include/linux/slab.h -+++ b/include/linux/slab.h -@@ -181,7 +181,7 @@ int kmem_cache_shrink(struct kmem_cache *); - /* - * Common kmalloc functions provided by all allocators - */ --void * __must_check krealloc(const void *, size_t, gfp_t); -+void * __must_check krealloc(const void *, size_t, gfp_t) __attribute((alloc_size(2))); - void kfree(const void *); - void kfree_sensitive(const void *); - size_t __ksize(const void *); -@@ -386,7 +386,7 @@ static __always_inline unsigned int kmalloc_index(size_t size) - } - #endif /* !CONFIG_SLOB */ - --void *__kmalloc(size_t size, gfp_t flags) __assume_kmalloc_alignment __malloc; -+void *__kmalloc(size_t size, gfp_t flags) __assume_kmalloc_alignment __malloc __attribute__((alloc_size(1))); - void *kmem_cache_alloc(struct kmem_cache *, gfp_t flags) __assume_slab_alignment __malloc; - void kmem_cache_free(struct kmem_cache *, void *); - -@@ -410,7 +410,7 @@ static __always_inline void kfree_bulk(size_t size, void **p) - } - - #ifdef CONFIG_NUMA --void *__kmalloc_node(size_t size, gfp_t flags, int node) __assume_kmalloc_alignment __malloc; -+void *__kmalloc_node(size_t size, gfp_t flags, int node) __assume_kmalloc_alignment __malloc __attribute__((alloc_size(1))); - void *kmem_cache_alloc_node(struct kmem_cache *, gfp_t flags, int node) __assume_slab_alignment __malloc; - #else - static __always_inline void *__kmalloc_node(size_t size, gfp_t flags, int node) -@@ -535,7 +535,7 @@ static __always_inline void *kmalloc_large(size_t size, gfp_t flags) - * Try really hard to succeed the allocation but fail - * eventually. - */ --static __always_inline void *kmalloc(size_t size, gfp_t flags) -+static __always_inline __attribute__((alloc_size(1))) void *kmalloc(size_t size, gfp_t flags) - { - if (__builtin_constant_p(size)) { - #ifndef CONFIG_SLOB -@@ -557,7 +557,7 @@ static __always_inline void *kmalloc(size_t size, gfp_t flags) - return __kmalloc(size, flags); - } - --static __always_inline void *kmalloc_node(size_t size, gfp_t flags, int node) -+static __always_inline __attribute__((alloc_size(1))) void *kmalloc_node(size_t size, gfp_t flags, int node) - { - #ifndef CONFIG_SLOB - if (__builtin_constant_p(size) && --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0071-add-vmalloc-alloc_size-attributes.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0071-add-vmalloc-alloc_size-attributes.patch deleted file mode 100644 index 2280d4441b9b..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0071-add-vmalloc-alloc_size-attributes.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 765b15be971302f62d5d4952ce3db1c5369cb158 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Wed, 3 May 2017 12:04:03 -0400 -Subject: [PATCH 071/113] add vmalloc alloc_size attributes - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> -Signed-off-by: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr> -Signed-off-by: Levente Polyak <levente@leventepolyak.net> ---- - include/linux/vmalloc.h | 18 +++++++++--------- - 1 file changed, 9 insertions(+), 9 deletions(-) - -diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h -index 938eaf9517e2..7c069063c20d 100644 ---- a/include/linux/vmalloc.h -+++ b/include/linux/vmalloc.h -@@ -102,18 +102,18 @@ static inline void vmalloc_init(void) - static inline unsigned long vmalloc_nr_pages(void) { return 0; } - #endif - --extern void *vmalloc(unsigned long size); --extern void *vzalloc(unsigned long size); --extern void *vmalloc_user(unsigned long size); --extern void *vmalloc_node(unsigned long size, int node); --extern void *vzalloc_node(unsigned long size, int node); --extern void *vmalloc_32(unsigned long size); --extern void *vmalloc_32_user(unsigned long size); --extern void *__vmalloc(unsigned long size, gfp_t gfp_mask); -+extern void *vmalloc(unsigned long size) __attribute__((alloc_size(1))); -+extern void *vzalloc(unsigned long size) __attribute__((alloc_size(1))); -+extern void *vmalloc_user(unsigned long size) __attribute__((alloc_size(1))); -+extern void *vmalloc_node(unsigned long size, int node) __attribute__((alloc_size(1))); -+extern void *vzalloc_node(unsigned long size, int node) __attribute__((alloc_size(1))); -+extern void *vmalloc_32(unsigned long size) __attribute__((alloc_size(1))); -+extern void *vmalloc_32_user(unsigned long size) __attribute__((alloc_size(1))); -+extern void *__vmalloc(unsigned long size, gfp_t gfp_mask) __attribute__((alloc_size(1))); - extern void *__vmalloc_node_range(unsigned long size, unsigned long align, - unsigned long start, unsigned long end, gfp_t gfp_mask, - pgprot_t prot, unsigned long vm_flags, int node, -- const void *caller); -+ const void *caller) __attribute__((alloc_size(1))); - void *__vmalloc_node(unsigned long size, unsigned long align, gfp_t gfp_mask, - int node, const void *caller); - --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0072-add-kvmalloc-alloc_size-attribute.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0072-add-kvmalloc-alloc_size-attribute.patch deleted file mode 100644 index b3c8f0c0a801..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0072-add-kvmalloc-alloc_size-attribute.patch +++ /dev/null @@ -1,26 +0,0 @@ -From a558df65a5308d73eb0455e711d012a461b9efdb Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Tue, 4 Jul 2017 00:51:33 -0400 -Subject: [PATCH 072/113] add kvmalloc alloc_size attribute - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - include/linux/mm.h | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/include/linux/mm.h b/include/linux/mm.h -index cd5c313729ea..746f6d05bd81 100644 ---- a/include/linux/mm.h -+++ b/include/linux/mm.h -@@ -759,7 +759,7 @@ static inline int is_vmalloc_or_module_addr(const void *x) - } - #endif - --extern void *kvmalloc_node(size_t size, gfp_t flags, int node); -+extern void *kvmalloc_node(size_t size, gfp_t flags, int node) __attribute__((alloc_size(1))); - static inline void *kvmalloc(size_t size, gfp_t flags) - { - return kvmalloc_node(size, flags, NUMA_NO_NODE); --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0073-add-percpu-alloc_size-attributes.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0073-add-percpu-alloc_size-attributes.patch deleted file mode 100644 index 6900b23bdf50..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0073-add-percpu-alloc_size-attributes.patch +++ /dev/null @@ -1,37 +0,0 @@ -From bf3b905e708babea7cedc1e0afc4f5482e66b2b7 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Sun, 14 May 2017 16:39:36 -0400 -Subject: [PATCH 073/113] add percpu alloc_size attributes - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - include/linux/percpu.h | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/include/linux/percpu.h b/include/linux/percpu.h -index 5e76af742c80..9a6c682ec127 100644 ---- a/include/linux/percpu.h -+++ b/include/linux/percpu.h -@@ -123,7 +123,7 @@ extern int __init pcpu_page_first_chunk(size_t reserved_size, - pcpu_fc_populate_pte_fn_t populate_pte_fn); - #endif - --extern void __percpu *__alloc_reserved_percpu(size_t size, size_t align); -+extern void __percpu *__alloc_reserved_percpu(size_t size, size_t align) __attribute__((alloc_size(1))); - extern bool __is_kernel_percpu_address(unsigned long addr, unsigned long *can_addr); - extern bool is_kernel_percpu_address(unsigned long addr); - -@@ -131,8 +131,8 @@ extern bool is_kernel_percpu_address(unsigned long addr); - extern void __init setup_per_cpu_areas(void); - #endif - --extern void __percpu *__alloc_percpu_gfp(size_t size, size_t align, gfp_t gfp); --extern void __percpu *__alloc_percpu(size_t size, size_t align); -+extern void __percpu *__alloc_percpu_gfp(size_t size, size_t align, gfp_t gfp) __attribute__((alloc_size(1))); -+extern void __percpu *__alloc_percpu(size_t size, size_t align) __attribute__((alloc_size(1))); - extern void free_percpu(void __percpu *__pdata); - extern phys_addr_t per_cpu_ptr_to_phys(void *addr); - --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0074-add-alloc_pages_exact-alloc_size-attributes.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0074-add-alloc_pages_exact-alloc_size-attributes.patch deleted file mode 100644 index 5793fe518bff..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0074-add-alloc_pages_exact-alloc_size-attributes.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 5a0e958093741bc7210e07d3f4fb75faa40b44a0 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Sun, 14 May 2017 16:53:59 -0400 -Subject: [PATCH 074/113] add alloc_pages_exact alloc_size attributes - -Edited-by: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr> -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - include/linux/gfp.h | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/include/linux/gfp.h b/include/linux/gfp.h -index c603237e006c..893378b0262e 100644 ---- a/include/linux/gfp.h -+++ b/include/linux/gfp.h -@@ -568,9 +568,9 @@ static inline struct page *alloc_pages(gfp_t gfp_mask, unsigned int order) - extern unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order); - extern unsigned long get_zeroed_page(gfp_t gfp_mask); - --void *alloc_pages_exact(size_t size, gfp_t gfp_mask); -+void *alloc_pages_exact(size_t size, gfp_t gfp_mask) __attribute__((alloc_size(1))); - void free_pages_exact(void *virt, size_t size); --void * __meminit alloc_pages_exact_nid(int nid, size_t size, gfp_t gfp_mask); -+void * __meminit alloc_pages_exact_nid(int nid, size_t size, gfp_t gfp_mask) __attribute__((alloc_size(2))); - - #define __get_free_page(gfp_mask) \ - __get_free_pages((gfp_mask), 0) --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0075-Add-the-extra_latent_entropy-kernel-parameter.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0075-Add-the-extra_latent_entropy-kernel-parameter.patch deleted file mode 100644 index ebd1abcb5bc2..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0075-Add-the-extra_latent_entropy-kernel-parameter.patch +++ /dev/null @@ -1,104 +0,0 @@ -From b5355e1d89cc343036dec751091e8bdbc70b790a Mon Sep 17 00:00:00 2001 -From: Emese Revfy <re.emese@gmail.com> -Date: Tue, 31 May 2016 01:34:02 +0200 -Subject: [PATCH 075/113] Add the extra_latent_entropy kernel parameter - -When extra_latent_entropy is passed on the kernel command line, -entropy will be extracted from up to the first 4GB of RAM while the -runtime memory allocator is being initialized. - -Based on work created by the PaX Team. - -Signed-off-by: Emese Revfy <re.emese@gmail.com> -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - .../admin-guide/kernel-parameters.txt | 5 ++++ - mm/page_alloc.c | 25 +++++++++++++++++++ - scripts/gcc-plugins/Kconfig | 5 ++++ - 3 files changed, 35 insertions(+) - -diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt -index 26bfe7ae711b..e7ea794320e8 100644 ---- a/Documentation/admin-guide/kernel-parameters.txt -+++ b/Documentation/admin-guide/kernel-parameters.txt -@@ -3566,6 +3566,11 @@ - the specified number of seconds. This is to be used if - your oopses keep scrolling off the screen. - -+ extra_latent_entropy -+ Enable a very simple form of latent entropy extraction -+ from the first 4GB of memory as the bootmem allocator -+ passes the memory pages to the buddy allocator. -+ - pcbit= [HW,ISDN] - - pcd. [PARIDE] -diff --git a/mm/page_alloc.c b/mm/page_alloc.c -index e014e6df1f39..965d49be78ed 100644 ---- a/mm/page_alloc.c -+++ b/mm/page_alloc.c -@@ -70,6 +70,7 @@ - #include <linux/psi.h> - #include <linux/padata.h> - #include <linux/khugepaged.h> -+#include <linux/random.h> - - #include <asm/sections.h> - #include <asm/tlbflush.h> -@@ -136,6 +137,15 @@ struct pcpu_drain { - static DEFINE_MUTEX(pcpu_drain_mutex); - static DEFINE_PER_CPU(struct pcpu_drain, pcpu_drain); - -+bool __meminitdata extra_latent_entropy; -+ -+static int __init setup_extra_latent_entropy(char *str) -+{ -+ extra_latent_entropy = true; -+ return 0; -+} -+early_param("extra_latent_entropy", setup_extra_latent_entropy); -+ - #ifdef CONFIG_GCC_PLUGIN_LATENT_ENTROPY - volatile unsigned long latent_entropy __latent_entropy; - EXPORT_SYMBOL(latent_entropy); -@@ -1549,6 +1559,21 @@ void __free_pages_core(struct page *page, unsigned int order) - __ClearPageReserved(p); - set_page_count(p, 0); - -+ if (extra_latent_entropy && !PageHighMem(page) && page_to_pfn(page) < 0x100000) { -+ unsigned long hash = 0; -+ size_t index, end = PAGE_SIZE * nr_pages / sizeof hash; -+ const unsigned long *data = lowmem_page_address(page); -+ -+ for (index = 0; index < end; index++) -+ hash ^= hash + data[index]; -+#ifdef CONFIG_GCC_PLUGIN_LATENT_ENTROPY -+ latent_entropy ^= hash; -+ add_device_randomness((const void *)&latent_entropy, sizeof(latent_entropy)); -+#else -+ add_device_randomness((const void *)&hash, sizeof(hash)); -+#endif -+ } -+ - atomic_long_add(nr_pages, &page_zone(page)->managed_pages); - - /* -diff --git a/scripts/gcc-plugins/Kconfig b/scripts/gcc-plugins/Kconfig -index ae19fb0243b9..ad78375ece5e 100644 ---- a/scripts/gcc-plugins/Kconfig -+++ b/scripts/gcc-plugins/Kconfig -@@ -53,6 +53,11 @@ config GCC_PLUGIN_LATENT_ENTROPY - is some slowdown of the boot process (about 0.5%) and fork and - irq processing. - -+ When extra_latent_entropy is passed on the kernel command line, -+ entropy will be extracted from up to the first 4GB of RAM while the -+ runtime memory allocator is being initialized. This costs even more -+ slowdown of the boot process. -+ - Note that entropy extracted this way is not cryptographically - secure! - --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0076-ata-avoid-null-pointer-dereference-on-bug.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0076-ata-avoid-null-pointer-dereference-on-bug.patch deleted file mode 100644 index 2bc0b9064262..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0076-ata-avoid-null-pointer-dereference-on-bug.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 77619f5ebb01fd8bdac4673099bc5f89ed3ec7df Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Mon, 15 May 2017 23:45:34 -0400 -Subject: [PATCH 076/113] ata: avoid null pointer dereference on bug - -Extracted from PaX. - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - drivers/ata/libata-core.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c -index 61c762961ca8..02a83039c25b 100644 ---- a/drivers/ata/libata-core.c -+++ b/drivers/ata/libata-core.c -@@ -4540,7 +4540,7 @@ void ata_qc_free(struct ata_queued_cmd *qc) - struct ata_port *ap; - unsigned int tag; - -- WARN_ON_ONCE(qc == NULL); /* ata_qc_from_tag _might_ return NULL */ -+ BUG_ON(qc == NULL); /* ata_qc_from_tag _might_ return NULL */ - ap = qc->ap; - - qc->flags = 0; -@@ -4557,7 +4557,7 @@ void __ata_qc_complete(struct ata_queued_cmd *qc) - struct ata_port *ap; - struct ata_link *link; - -- WARN_ON_ONCE(qc == NULL); /* ata_qc_from_tag _might_ return NULL */ -+ BUG_ON(qc == NULL); /* ata_qc_from_tag _might_ return NULL */ - WARN_ON_ONCE(!(qc->flags & ATA_QCFLAG_ACTIVE)); - ap = qc->ap; - link = qc->dev->link; --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0077-sanity-check-for-negative-length-in-nla_memcpy.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0077-sanity-check-for-negative-length-in-nla_memcpy.patch deleted file mode 100644 index a7980a7cba24..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0077-sanity-check-for-negative-length-in-nla_memcpy.patch +++ /dev/null @@ -1,28 +0,0 @@ -From efd3c3591dfc72a35355e17461d2e839f16fbdbb Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Mon, 15 May 2017 23:51:12 -0400 -Subject: [PATCH 077/113] sanity check for negative length in nla_memcpy - -Extracted from PaX. - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - lib/nlattr.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/lib/nlattr.c b/lib/nlattr.c -index 74019c8ebf6b..c480b4e7ffef 100644 ---- a/lib/nlattr.c -+++ b/lib/nlattr.c -@@ -778,6 +778,8 @@ int nla_memcpy(void *dest, const struct nlattr *src, int count) - { - int minlen = min_t(int, count, nla_len(src)); - -+ BUG_ON(minlen < 0); -+ - memcpy(dest, nla_data(src), minlen); - if (count > minlen) - memset(dest + minlen, 0, count - minlen); --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0078-add-page-destructor-sanity-check.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0078-add-page-destructor-sanity-check.patch deleted file mode 100644 index 82954e6c4741..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0078-add-page-destructor-sanity-check.patch +++ /dev/null @@ -1,71 +0,0 @@ -From 2d537a637635831105f4113592892f0b4e1e31ea Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Mon, 15 May 2017 23:59:18 -0400 -Subject: [PATCH 078/113] add page destructor sanity check - -Taken from the public PaX patches. - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> -[thibaut.sautereau@ssi.gouv.fr: Restore get_compound_page_dtor()] -Signed-off-by: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr> -Reviewd-by: Levente Polyak <levente@leventepolyak.net> ---- - include/linux/mm.h | 9 +++++++-- - mm/swap.c | 12 +++++++++++- - 2 files changed, 18 insertions(+), 3 deletions(-) - -diff --git a/include/linux/mm.h b/include/linux/mm.h -index 746f6d05bd81..a463ffe84eb4 100644 ---- a/include/linux/mm.h -+++ b/include/linux/mm.h -@@ -894,10 +894,15 @@ static inline void set_compound_page_dtor(struct page *page, - page[1].compound_dtor = compound_dtor; - } - --static inline void destroy_compound_page(struct page *page) -+static inline compound_page_dtor *get_compound_page_dtor(struct page *page) - { - VM_BUG_ON_PAGE(page[1].compound_dtor >= NR_COMPOUND_DTORS, page); -- compound_page_dtors[page[1].compound_dtor](page); -+ return compound_page_dtors[page[1].compound_dtor]; -+} -+ -+static inline void destroy_compound_page(struct page *page) -+{ -+ (*get_compound_page_dtor(page))(page); - } - - static inline unsigned int compound_order(struct page *page) -diff --git a/mm/swap.c b/mm/swap.c -index 47a47681c86b..762095d95092 100644 ---- a/mm/swap.c -+++ b/mm/swap.c -@@ -102,6 +102,8 @@ static void __put_single_page(struct page *page) - - static void __put_compound_page(struct page *page) - { -+ compound_page_dtor *dtor; -+ - /* - * __page_cache_release() is supposed to be called for thp, not for - * hugetlb. This is because hugetlb page does never have PageLRU set -@@ -110,7 +112,15 @@ static void __put_compound_page(struct page *page) - */ - if (!PageHuge(page)) - __page_cache_release(page); -- destroy_compound_page(page); -+ dtor = get_compound_page_dtor(page); -+ if (!PageHuge(page)) -+ BUG_ON(dtor != free_compound_page -+#ifdef CONFIG_TRANSPARENT_HUGEPAGE -+ && dtor != free_transhuge_page -+#endif -+ ); -+ -+ (*dtor)(page); - } - - void __put_page(struct page *page) --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0079-PaX-shadow-cr4-sanity-check-essentially-a-revert.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0079-PaX-shadow-cr4-sanity-check-essentially-a-revert.patch deleted file mode 100644 index 74a08131fce2..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0079-PaX-shadow-cr4-sanity-check-essentially-a-revert.patch +++ /dev/null @@ -1,52 +0,0 @@ -From 464796164b4bb82bee57a88f0da25c61ea76a72b Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Tue, 16 May 2017 00:59:48 -0400 -Subject: [PATCH 079/113] PaX shadow cr4 sanity check (essentially a revert) - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> -Signed-off-by: Levente Polyak <levente@leventepolyak.net> ---- - arch/x86/kernel/cpu/common.c | 1 + - arch/x86/kernel/process.c | 1 + - arch/x86/mm/tlb.c | 1 + - 3 files changed, 3 insertions(+) - -diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c -index 35ad8480c464..edaeeab9df4b 100644 ---- a/arch/x86/kernel/cpu/common.c -+++ b/arch/x86/kernel/cpu/common.c -@@ -399,6 +399,7 @@ EXPORT_SYMBOL_GPL(native_write_cr4); - void cr4_update_irqsoff(unsigned long set, unsigned long clear) - { - unsigned long newval, cr4 = this_cpu_read(cpu_tlbstate.cr4); -+ BUG_ON(cr4 != __read_cr4()); - - lockdep_assert_irqs_disabled(); - -diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c -index 145a7ac0c19a..058941e9ae40 100644 ---- a/arch/x86/kernel/process.c -+++ b/arch/x86/kernel/process.c -@@ -596,6 +596,7 @@ void speculation_ctrl_update_current(void) - static inline void cr4_toggle_bits_irqsoff(unsigned long mask) - { - unsigned long newval, cr4 = this_cpu_read(cpu_tlbstate.cr4); -+ BUG_ON(cr4 != __read_cr4()); - - newval = cr4 ^ mask; - if (newval != cr4) { -diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c -index 569ac1d57f55..044d88da4aee 100644 ---- a/arch/x86/mm/tlb.c -+++ b/arch/x86/mm/tlb.c -@@ -1066,6 +1066,7 @@ STATIC_NOPV void native_flush_tlb_global(void) - raw_local_irq_save(flags); - - cr4 = this_cpu_read(cpu_tlbstate.cr4); -+ BUG_ON(cr4 != __read_cr4()); - /* toggle PGE */ - native_write_cr4(cr4 ^ X86_CR4_PGE); - /* write old PGE again and flush TLBs */ --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0080-add-writable-function-pointer-detection.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0080-add-writable-function-pointer-detection.patch deleted file mode 100644 index 2b9481298465..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0080-add-writable-function-pointer-detection.patch +++ /dev/null @@ -1,98 +0,0 @@ -From c8a90c462a2c97516e76c80f9fdf93f615303b5a Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Sun, 9 Jul 2017 17:53:23 -0400 -Subject: [PATCH 080/113] add writable function pointer detection - -Taken from the public PaX patches. - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - scripts/mod/modpost.c | 28 +++++++++++++++++++++++++--- - 1 file changed, 25 insertions(+), 3 deletions(-) - -diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c -index f882ce0d9327..50e9baefc4e7 100644 ---- a/scripts/mod/modpost.c -+++ b/scripts/mod/modpost.c -@@ -34,6 +34,7 @@ static int external_module = 0; - static int warn_unresolved = 0; - /* How a symbol is exported */ - static int sec_mismatch_count = 0; -+static int writable_fptr_count = 0; - static int sec_mismatch_fatal = 0; - /* ignore missing files */ - static int ignore_missing_files; -@@ -1007,6 +1008,7 @@ enum mismatch { - ANY_EXIT_TO_ANY_INIT, - EXPORT_TO_INIT_EXIT, - EXTABLE_TO_NON_TEXT, -+ DATA_TO_TEXT - }; - - /** -@@ -1133,6 +1135,12 @@ static const struct sectioncheck sectioncheck[] = { - .good_tosec = {ALL_TEXT_SECTIONS , NULL}, - .mismatch = EXTABLE_TO_NON_TEXT, - .handler = extable_mismatch_handler, -+}, -+/* Do not reference code from writable data */ -+{ -+ .fromsec = { DATA_SECTIONS, NULL }, -+ .bad_tosec = { ALL_TEXT_SECTIONS, NULL }, -+ .mismatch = DATA_TO_TEXT - } - }; - -@@ -1320,10 +1328,10 @@ static Elf_Sym *find_elf_symbol(struct elf_info *elf, Elf64_Sword addr, - continue; - if (!is_valid_name(elf, sym)) - continue; -- if (sym->st_value == addr) -- return sym; - /* Find a symbol nearby - addr are maybe negative */ - d = sym->st_value - addr; -+ if (d == 0) -+ return sym; - if (d < 0) - d = addr - sym->st_value; - if (d < distance) { -@@ -1458,7 +1466,10 @@ static void report_sec_mismatch(const char *modname, - char *prl_from; - char *prl_to; - -- sec_mismatch_count++; -+ if (mismatch->mismatch == DATA_TO_TEXT) -+ writable_fptr_count++; -+ else -+ sec_mismatch_count++; - - get_pretty_name(from_is_func, &from, &from_p); - get_pretty_name(to_is_func, &to, &to_p); -@@ -1580,6 +1591,14 @@ static void report_sec_mismatch(const char *modname, - fatal("There's a special handler for this mismatch type, " - "we should never get here."); - break; -+ case DATA_TO_TEXT: -+#if 0 -+ fprintf(stderr, -+ "The %s %s:%s references\n" -+ "the %s %s:%s%s\n", -+ from, fromsec, fromsym, to, tosec, tosym, to_p); -+#endif -+ break; - } - fprintf(stderr, "\n"); - } -@@ -2670,6 +2689,9 @@ int main(int argc, char **argv) - } - - free(buf.p); -+ if (writable_fptr_count) -+ warn("modpost: Found %d writable function pointer(s).\n", -+ writable_fptr_count); - - return err; - } --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0081-support-overriding-early-audit-kernel-cmdline.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0081-support-overriding-early-audit-kernel-cmdline.patch deleted file mode 100644 index f5ae97ad2705..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0081-support-overriding-early-audit-kernel-cmdline.patch +++ /dev/null @@ -1,26 +0,0 @@ -From c7c946e6ec27727494c6f146430b8b7d8e89ef1b Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Sun, 9 Jul 2017 17:20:29 -0400 -Subject: [PATCH 081/113] support overriding early audit kernel cmdline - ---- - kernel/audit.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/kernel/audit.c b/kernel/audit.c -index 68cee3bc8cfe..2059c66f7c9b 100644 ---- a/kernel/audit.c -+++ b/kernel/audit.c -@@ -1693,6 +1693,9 @@ static int __init audit_enable(char *str) - - if (audit_default == AUDIT_OFF) - audit_initialized = AUDIT_DISABLED; -+ else if (!audit_ever_enabled) -+ audit_initialized = AUDIT_UNINITIALIZED; -+ - if (audit_set_enabled(audit_default)) - pr_err("audit: error setting audit state (%d)\n", - audit_default); --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0082-FORTIFY_SOURCE-intra-object-overflow-checking.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0082-FORTIFY_SOURCE-intra-object-overflow-checking.patch deleted file mode 100644 index 1717c2b9ac10..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0082-FORTIFY_SOURCE-intra-object-overflow-checking.patch +++ /dev/null @@ -1,135 +0,0 @@ -From b5a43b9058570b8124fe98e9e98a60468a5f711d Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Sat, 3 Jun 2017 17:34:13 -0400 -Subject: [PATCH 082/113] FORTIFY_SOURCE intra-object overflow checking - -This adds supporting for detecting buffer overflows from inner objects -for the fortified string family functions. It's comparable to the -_FORTIFY_SOURCE=2 feature in glibc with the additional coverage of -intra-object read overflows for supported functions. - -The mem* family functions are left with only the inter-object overflow -checks as is the case with glibc _FORTIFY_SOURCE=2. - -This feature is currently hidden behind CONFIG_EXPERT because it's a lot -more likely to uncover benign / intended issues and will need a lot of -runtime testing. It's already useful for finding bugs but it may not yet -be a good idea to use it for hardening unless panics for benign issues -are seen as a lesser evil than the vulnerabilities it can catch. - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - include/linux/string.h | 26 ++++++++++++++++---------- - security/Kconfig | 10 ++++++++++ - 2 files changed, 26 insertions(+), 10 deletions(-) - -diff --git a/include/linux/string.h b/include/linux/string.h -index b1f3894a0a3e..4c5564a6ad80 100644 ---- a/include/linux/string.h -+++ b/include/linux/string.h -@@ -264,6 +264,12 @@ void __read_overflow2(void) __compiletime_error("detected read beyond size of ob - void __read_overflow3(void) __compiletime_error("detected read beyond size of object passed as 3rd parameter"); - void __write_overflow(void) __compiletime_error("detected write beyond size of object passed as 1st parameter"); - -+#ifdef CONFIG_FORTIFY_SOURCE_STRICT_STRING -+#define __string_size(p) __builtin_object_size(p, 1) -+#else -+#define __string_size(p) __builtin_object_size(p, 0) -+#endif -+ - #if !defined(__NO_FORTIFY) && defined(__OPTIMIZE__) && defined(CONFIG_FORTIFY_SOURCE) - - #ifdef CONFIG_KASAN -@@ -292,7 +298,7 @@ extern char *__underlying_strncpy(char *p, const char *q, __kernel_size_t size) - - __FORTIFY_INLINE char *strncpy(char *p, const char *q, __kernel_size_t size) - { -- size_t p_size = __builtin_object_size(p, 0); -+ size_t p_size = __string_size(p); - if (__builtin_constant_p(size) && p_size < size) - __write_overflow(); - if (p_size < size) -@@ -302,7 +308,7 @@ __FORTIFY_INLINE char *strncpy(char *p, const char *q, __kernel_size_t size) - - __FORTIFY_INLINE char *strcat(char *p, const char *q) - { -- size_t p_size = __builtin_object_size(p, 0); -+ size_t p_size = __string_size(p); - if (p_size == (size_t)-1) - return __underlying_strcat(p, q); - if (strlcat(p, q, p_size) >= p_size) -@@ -313,7 +319,7 @@ __FORTIFY_INLINE char *strcat(char *p, const char *q) - __FORTIFY_INLINE __kernel_size_t strlen(const char *p) - { - __kernel_size_t ret; -- size_t p_size = __builtin_object_size(p, 0); -+ size_t p_size = __string_size(p); - - /* Work around gcc excess stack consumption issue */ - if (p_size == (size_t)-1 || -@@ -328,7 +334,7 @@ __FORTIFY_INLINE __kernel_size_t strlen(const char *p) - extern __kernel_size_t __real_strnlen(const char *, __kernel_size_t) __RENAME(strnlen); - __FORTIFY_INLINE __kernel_size_t strnlen(const char *p, __kernel_size_t maxlen) - { -- size_t p_size = __builtin_object_size(p, 0); -+ size_t p_size = __string_size(p); - __kernel_size_t ret = __real_strnlen(p, maxlen < p_size ? maxlen : p_size); - if (p_size <= ret && maxlen != ret) - fortify_panic(__func__); -@@ -340,8 +346,8 @@ extern size_t __real_strlcpy(char *, const char *, size_t) __RENAME(strlcpy); - __FORTIFY_INLINE size_t strlcpy(char *p, const char *q, size_t size) - { - size_t ret; -- size_t p_size = __builtin_object_size(p, 0); -- size_t q_size = __builtin_object_size(q, 0); -+ size_t p_size = __string_size(p); -+ size_t q_size = __string_size(q); - if (p_size == (size_t)-1 && q_size == (size_t)-1) - return __real_strlcpy(p, q, size); - ret = strlen(q); -@@ -361,8 +367,8 @@ __FORTIFY_INLINE size_t strlcpy(char *p, const char *q, size_t size) - __FORTIFY_INLINE char *strncat(char *p, const char *q, __kernel_size_t count) - { - size_t p_len, copy_len; -- size_t p_size = __builtin_object_size(p, 0); -- size_t q_size = __builtin_object_size(q, 0); -+ size_t p_size = __string_size(p); -+ size_t q_size = __string_size(q); - if (p_size == (size_t)-1 && q_size == (size_t)-1) - return __underlying_strncat(p, q, count); - p_len = strlen(p); -@@ -475,8 +481,8 @@ __FORTIFY_INLINE void *kmemdup(const void *p, size_t size, gfp_t gfp) - /* defined after fortified strlen and memcpy to reuse them */ - __FORTIFY_INLINE char *strcpy(char *p, const char *q) - { -- size_t p_size = __builtin_object_size(p, 0); -- size_t q_size = __builtin_object_size(q, 0); -+ size_t p_size = __string_size(p); -+ size_t q_size = __string_size(q); - if (p_size == (size_t)-1 && q_size == (size_t)-1) - return __underlying_strcpy(p, q); - memcpy(p, q, strlen(q) + 1); -diff --git a/security/Kconfig b/security/Kconfig -index 2348ff7d4e1d..f3c995bd79cf 100644 ---- a/security/Kconfig -+++ b/security/Kconfig -@@ -208,6 +208,16 @@ config FORTIFY_SOURCE - Detect overflows of buffers in common string and memory functions - where the compiler can determine and validate the buffer sizes. - -+config FORTIFY_SOURCE_STRICT_STRING -+ bool "Harden common functions against buffer overflows" -+ depends on FORTIFY_SOURCE -+ depends on EXPERT -+ help -+ Perform stricter overflow checks catching overflows within objects -+ for common C string functions rather than only between objects. -+ -+ This is not yet intended for production use, only bug finding. -+ - config STATIC_USERMODEHELPER - bool "Force all usermode helper calls through a single binary" - help --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0083-Revert-mm-revert-x86_64-and-arm64-ELF_ET_DYN_BASE-ba.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0083-Revert-mm-revert-x86_64-and-arm64-ELF_ET_DYN_BASE-ba.patch deleted file mode 100644 index 6e3e58ed378d..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0083-Revert-mm-revert-x86_64-and-arm64-ELF_ET_DYN_BASE-ba.patch +++ /dev/null @@ -1,54 +0,0 @@ -From a24e2080e304e3b7ba674bb8dd591fb86302af83 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Sat, 26 Aug 2017 20:16:03 -0400 -Subject: [PATCH 083/113] Revert "mm: revert x86_64 and arm64 ELF_ET_DYN_BASE - base changes" - -This reverts commit aab425db4279aeb83b7911693f0cccbd3644c9fd. ---- - arch/arm64/include/asm/elf.h | 8 ++------ - arch/x86/include/asm/elf.h | 4 ++-- - 2 files changed, 4 insertions(+), 8 deletions(-) - -diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h -index 8d1c8dcb87fd..26d27c7a2c2e 100644 ---- a/arch/arm64/include/asm/elf.h -+++ b/arch/arm64/include/asm/elf.h -@@ -124,14 +124,10 @@ - - /* - * This is the base location for PIE (ET_DYN with INTERP) loads. On -- * 64-bit, this is above 4GB to leave the entire 32-bit address -+ * 64-bit, this is raised to 4GB to leave the entire 32-bit address - * space open for things that want to use the area for 32-bit pointers. - */ --#ifdef CONFIG_ARM64_FORCE_52BIT --#define ELF_ET_DYN_BASE (2 * TASK_SIZE_64 / 3) --#else --#define ELF_ET_DYN_BASE (2 * DEFAULT_MAP_WINDOW_64 / 3) --#endif /* CONFIG_ARM64_FORCE_52BIT */ -+#define ELF_ET_DYN_BASE 0x100000000UL - - #ifndef __ASSEMBLY__ - -diff --git a/arch/x86/include/asm/elf.h b/arch/x86/include/asm/elf.h -index b9a5d488f1a5..b55054566ece 100644 ---- a/arch/x86/include/asm/elf.h -+++ b/arch/x86/include/asm/elf.h -@@ -246,11 +246,11 @@ extern int force_personality32; - - /* - * This is the base location for PIE (ET_DYN with INTERP) loads. On -- * 64-bit, this is above 4GB to leave the entire 32-bit address -+ * 64-bit, this is raised to 4GB to leave the entire 32-bit address - * space open for things that want to use the area for 32-bit pointers. - */ - #define ELF_ET_DYN_BASE (mmap_is_ia32() ? 0x000400000UL : \ -- (DEFAULT_MAP_WINDOW / 3 * 2)) -+ 0x100000000UL) - - /* This yields a mask that user programs can use to figure out what - instruction set this CPU supports. This could be done in user space, --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0084-x86_64-move-vdso-to-mmap-region-from-stack-region.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0084-x86_64-move-vdso-to-mmap-region-from-stack-region.patch deleted file mode 100644 index c7c941239fd4..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0084-x86_64-move-vdso-to-mmap-region-from-stack-region.patch +++ /dev/null @@ -1,118 +0,0 @@ -From bb18120691acbc0ac0ec0b87f5132019ff5a39fd Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Thu, 11 May 2017 16:52:00 -0400 -Subject: [PATCH 084/113] x86_64: move vdso to mmap region from stack region - -This removes the only executable code from the stack region and gives -the vdso the same randomized base as other mmap mappings including the -linker and other shared objects. It results in a sane amount of entropy -being provided and there's little to no advantage in separating this -from the existing executable code there. - -It's sensible for userspace to reserve the initial mmap base as a region -for executable code with a random gap for other mmap allocations, along -with providing randomization within that region. However, there isn't -much the kernel can do to help due to how dynamic linkers load the -shared objects. - -This was extracted from the PaX RANDMMAP feature. - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - arch/x86/entry/vdso/vma.c | 48 +----------------------------------- - arch/x86/include/asm/elf.h | 1 - - arch/x86/kernel/sys_x86_64.c | 7 ------ - 3 files changed, 1 insertion(+), 55 deletions(-) - -diff --git a/arch/x86/entry/vdso/vma.c b/arch/x86/entry/vdso/vma.c -index 9185cb1d13b9..543912071557 100644 ---- a/arch/x86/entry/vdso/vma.c -+++ b/arch/x86/entry/vdso/vma.c -@@ -315,55 +315,9 @@ static int map_vdso(const struct vdso_image *image, unsigned long addr) - } - - #ifdef CONFIG_X86_64 --/* -- * Put the vdso above the (randomized) stack with another randomized -- * offset. This way there is no hole in the middle of address space. -- * To save memory make sure it is still in the same PTE as the stack -- * top. This doesn't give that many random bits. -- * -- * Note that this algorithm is imperfect: the distribution of the vdso -- * start address within a PMD is biased toward the end. -- * -- * Only used for the 64-bit and x32 vdsos. -- */ --static unsigned long vdso_addr(unsigned long start, unsigned len) --{ -- unsigned long addr, end; -- unsigned offset; -- -- /* -- * Round up the start address. It can start out unaligned as a result -- * of stack start randomization. -- */ -- start = PAGE_ALIGN(start); -- -- /* Round the lowest possible end address up to a PMD boundary. */ -- end = (start + len + PMD_SIZE - 1) & PMD_MASK; -- if (end >= TASK_SIZE_MAX) -- end = TASK_SIZE_MAX; -- end -= len; -- -- if (end > start) { -- offset = get_random_int() % (((end - start) >> PAGE_SHIFT) + 1); -- addr = start + (offset << PAGE_SHIFT); -- } else { -- addr = start; -- } -- -- /* -- * Forcibly align the final address in case we have a hardware -- * issue that requires alignment for performance reasons. -- */ -- addr = align_vdso_addr(addr); -- -- return addr; --} -- - static int map_vdso_randomized(const struct vdso_image *image) - { -- unsigned long addr = vdso_addr(current->mm->start_stack, image->size-image->sym_vvar_start); -- -- return map_vdso(image, addr); -+ return map_vdso(image, 0); - } - #endif - -diff --git a/arch/x86/include/asm/elf.h b/arch/x86/include/asm/elf.h -index b55054566ece..58292600112d 100644 ---- a/arch/x86/include/asm/elf.h -+++ b/arch/x86/include/asm/elf.h -@@ -398,5 +398,4 @@ struct va_alignment { - } ____cacheline_aligned; - - extern struct va_alignment va_align; --extern unsigned long align_vdso_addr(unsigned long); - #endif /* _ASM_X86_ELF_H */ -diff --git a/arch/x86/kernel/sys_x86_64.c b/arch/x86/kernel/sys_x86_64.c -index 504fa5425bce..c4e35a3b3733 100644 ---- a/arch/x86/kernel/sys_x86_64.c -+++ b/arch/x86/kernel/sys_x86_64.c -@@ -52,13 +52,6 @@ static unsigned long get_align_bits(void) - return va_align.bits & get_align_mask(); - } - --unsigned long align_vdso_addr(unsigned long addr) --{ -- unsigned long align_mask = get_align_mask(); -- addr = (addr + align_mask) & ~align_mask; -- return addr | get_align_bits(); --} -- - static int __init control_va_addr_alignment(char *str) - { - /* guard against enabling this on other CPU families */ --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0085-x86-determine-stack-entropy-based-on-mmap-entropy.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0085-x86-determine-stack-entropy-based-on-mmap-entropy.patch deleted file mode 100644 index 8d9aa61d1a0a..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0085-x86-determine-stack-entropy-based-on-mmap-entropy.patch +++ /dev/null @@ -1,60 +0,0 @@ -From 126dd08ead6bc733aeda03b5437be681dcbe79e4 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Sun, 21 May 2017 20:30:44 -0400 -Subject: [PATCH 085/113] x86: determine stack entropy based on mmap entropy - -Stack mapping entropy is currently hard-wired to 11 bits of entropy on -32-bit and 22 bits of entropy on 64-bit. The stack itself gains an extra -8 bits of entropy from lower bit randomization within 16 byte alignment -constraints. The argument block could have all lower bits randomized but -it currently only gets the mapping randomization. - -Rather than hard-wiring values this switches to using the mmap entropy -configuration like the mmap base and executable base, resulting in a -range of 8 to 16 bits on 32-bit and 28 to 32 bits on 64-bit depending on -kernel configuration and overridable via the sysctl entries. - -It's worth noting that since these kernel configuration options default -to the minimum supported entropy value, the entropy on 32-bit will drop -from 11 to 8 bits for builds using the defaults. However, following the -configuration seems like the right thing to do regardless. At the very -least, changing the defaults for COMPAT (32-bit processes on 64-bit) -should be considered due to the larger address space compared to real -32-bit. - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - arch/x86/include/asm/elf.h | 10 +++++++--- - 1 file changed, 7 insertions(+), 3 deletions(-) - -diff --git a/arch/x86/include/asm/elf.h b/arch/x86/include/asm/elf.h -index 58292600112d..608cca19cf8c 100644 ---- a/arch/x86/include/asm/elf.h -+++ b/arch/x86/include/asm/elf.h -@@ -330,8 +330,8 @@ extern bool mmap_address_hint_valid(unsigned long addr, unsigned long len); - - #ifdef CONFIG_X86_32 - --#define __STACK_RND_MASK(is32bit) (0x7ff) --#define STACK_RND_MASK (0x7ff) -+#define __STACK_RND_MASK(is32bit) ((1UL << mmap_rnd_bits) - 1) -+#define STACK_RND_MASK ((1UL << mmap_rnd_bits) - 1) - - #define ARCH_DLINFO ARCH_DLINFO_IA32 - -@@ -340,7 +340,11 @@ extern bool mmap_address_hint_valid(unsigned long addr, unsigned long len); - #else /* CONFIG_X86_32 */ - - /* 1GB for 64bit, 8MB for 32bit */ --#define __STACK_RND_MASK(is32bit) ((is32bit) ? 0x7ff : 0x3fffff) -+#ifdef CONFIG_COMPAT -+#define __STACK_RND_MASK(is32bit) ((is32bit) ? (1UL << mmap_rnd_compat_bits) - 1 : (1UL << mmap_rnd_bits) - 1) -+#else -+#define __STACK_RND_MASK(is32bit) ((1UL << mmap_rnd_bits) - 1) -+#endif - #define STACK_RND_MASK __STACK_RND_MASK(mmap_is_ia32()) - - #define ARCH_DLINFO \ --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0086-arm64-determine-stack-entropy-based-on-mmap-entropy.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0086-arm64-determine-stack-entropy-based-on-mmap-entropy.patch deleted file mode 100644 index 2abbe7353112..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0086-arm64-determine-stack-entropy-based-on-mmap-entropy.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 930f572c37938def097762704a8ba0f599deae6c Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Mon, 22 May 2017 05:06:20 -0400 -Subject: [PATCH 086/113] arm64: determine stack entropy based on mmap entropy - -Stack mapping entropy is currently hard-wired to 11 bits of entropy on -32-bit and 18 bits of entropy on 64-bit. The stack itself gains an extra -8 bits of entropy from lower bit randomization within 16 byte alignment -constraints. The argument block could have all lower bits randomized but -it currently only gets the mapping randomization. - -Rather than hard-wiring values this switches to using the mmap entropy -configuration like the mmap base and executable base, resulting in a -range of 8 to 16 bits on 32-bit and 18 to 24 bits on 64-bit (with 4k -pages and 3 level page tables) depending on kernel configuration and -overridable via the sysctl entries. - -It's worth noting that since these kernel configuration options default -to the minimum supported entropy value, the entropy on 32-bit will drop -from 11 to 8 bits for builds using the defaults. However, following the -configuration seems like the right thing to do regardless. At the very -least, changing the defaults for COMPAT (32-bit processes on 64-bit) -should be considered due to the larger address space compared to real -32-bit. - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - arch/arm64/include/asm/elf.h | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h -index 26d27c7a2c2e..32c1609a1158 100644 ---- a/arch/arm64/include/asm/elf.h -+++ b/arch/arm64/include/asm/elf.h -@@ -185,10 +185,10 @@ extern int arch_setup_additional_pages(struct linux_binprm *bprm, - /* 1GB of VA */ - #ifdef CONFIG_COMPAT - #define STACK_RND_MASK (test_thread_flag(TIF_32BIT) ? \ -- 0x7ff >> (PAGE_SHIFT - 12) : \ -- 0x3ffff >> (PAGE_SHIFT - 12)) -+ ((1UL << mmap_rnd_compat_bits) - 1) >> (PAGE_SHIFT - 12) : \ -+ ((1UL << mmap_rnd_bits) - 1) >> (PAGE_SHIFT - 12)) - #else --#define STACK_RND_MASK (0x3ffff >> (PAGE_SHIFT - 12)) -+#define STACK_RND_MASK (((1UL << mmap_rnd_bits) - 1) >> (PAGE_SHIFT - 12)) - #endif - - #ifdef __AARCH64EB__ --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0087-randomize-lower-bits-of-the-argument-block.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0087-randomize-lower-bits-of-the-argument-block.patch deleted file mode 100644 index 1745bc6a925a..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0087-randomize-lower-bits-of-the-argument-block.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 51e7598866f4a7df48daada469670254b564b0b1 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Thu, 11 May 2017 16:02:49 -0400 -Subject: [PATCH 087/113] randomize lower bits of the argument block - -This was based on the PaX RANDUSTACK feature in grsecurity, where all of -the lower bits are randomized. PaX keeps 16-byte alignment. - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> -[levente@leventepolyak.net: do not randomize with ADDR_NO_RANDOMIZE personality] -Signed-off-by: Levente Polyak <levente@leventepolyak.net> ---- - fs/exec.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/fs/exec.c b/fs/exec.c -index ca89e0e3ef10..d2a03d32e195 100644 ---- a/fs/exec.c -+++ b/fs/exec.c -@@ -34,6 +34,7 @@ - #include <linux/swap.h> - #include <linux/string.h> - #include <linux/init.h> -+#include <linux/sched.h> - #include <linux/sched/mm.h> - #include <linux/sched/coredump.h> - #include <linux/sched/signal.h> -@@ -64,6 +65,7 @@ - #include <linux/compat.h> - #include <linux/vmalloc.h> - #include <linux/io_uring.h> -+#include <linux/random.h> - - #include <linux/uaccess.h> - #include <asm/mmu_context.h> -@@ -280,6 +282,8 @@ static int __bprm_mm_init(struct linux_binprm *bprm) - mm->stack_vm = mm->total_vm = 1; - mmap_write_unlock(mm); - bprm->p = vma->vm_end - sizeof(void *); -+ if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space) -+ bprm->p ^= get_random_int() & ~PAGE_MASK; - return 0; - err: - mmap_write_unlock(mm); --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0088-x86_64-match-arm64-brk-randomization-entropy.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0088-x86_64-match-arm64-brk-randomization-entropy.patch deleted file mode 100644 index 19067999acb9..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0088-x86_64-match-arm64-brk-randomization-entropy.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 66c0580a1686bae0d9a90043711e497955118610 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Tue, 30 May 2017 07:19:48 -0400 -Subject: [PATCH 088/113] x86_64: match arm64 brk randomization entropy - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - arch/x86/kernel/process.c | 7 ++++++- - 1 file changed, 6 insertions(+), 1 deletion(-) - -diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c -index 058941e9ae40..61460d55dd72 100644 ---- a/arch/x86/kernel/process.c -+++ b/arch/x86/kernel/process.c -@@ -43,6 +43,8 @@ - #include <asm/io_bitmap.h> - #include <asm/proto.h> - #include <asm/frame.h> -+#include <asm/elf.h> -+#include <linux/sizes.h> - - #include "process.h" - -@@ -906,7 +908,10 @@ unsigned long arch_align_stack(unsigned long sp) - - unsigned long arch_randomize_brk(struct mm_struct *mm) - { -- return randomize_page(mm->brk, 0x02000000); -+ if (mmap_is_ia32()) -+ return randomize_page(mm->brk, SZ_32M); -+ else -+ return randomize_page(mm->brk, SZ_1G); - } - - /* --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0089-support-randomizing-the-lower-bits-of-brk.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0089-support-randomizing-the-lower-bits-of-brk.patch deleted file mode 100644 index 2da8c5b8f0f1..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0089-support-randomizing-the-lower-bits-of-brk.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 1d0de8a103f3e898d99012d8521f4860340fb536 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Tue, 30 May 2017 18:03:30 -0400 -Subject: [PATCH 089/113] support randomizing the lower bits of brk - -This adds support for arch_randomize_brk implementations not performing -page alignment in order to randomize the lower bits of the brk heap. - -This idea is taken from PaX but the approach is different. This reuses -the existing code and avoids forcing early creation of the heap mapping, -avoiding mapping it if it's not used which is the case with many modern -allocators based solely on mmap. - -The malloc implementation can be relied upon to align this as needed to -the requirements it has, so using 16 byte alignment here is unnecessary. - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - mm/mmap.c | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/mm/mmap.c b/mm/mmap.c -index 5c8b4485860d..0e26c225bb53 100644 ---- a/mm/mmap.c -+++ b/mm/mmap.c -@@ -231,6 +231,13 @@ SYSCALL_DEFINE1(brk, unsigned long, brk) - - newbrk = PAGE_ALIGN(brk); - oldbrk = PAGE_ALIGN(mm->brk); -+ /* properly handle unaligned min_brk as an empty heap */ -+ if (min_brk & ~PAGE_MASK) { -+ if (brk == min_brk) -+ newbrk -= PAGE_SIZE; -+ if (mm->brk == min_brk) -+ oldbrk -= PAGE_SIZE; -+ } - if (oldbrk == newbrk) { - mm->brk = brk; - goto success; --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0090-mm-randomize-lower-bits-of-brk.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0090-mm-randomize-lower-bits-of-brk.patch deleted file mode 100644 index 0c0ef1329ac0..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0090-mm-randomize-lower-bits-of-brk.patch +++ /dev/null @@ -1,31 +0,0 @@ -From f088fbb3c145b152d7894fae612dc65e533802f7 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Thu, 1 Jun 2017 03:22:38 -0400 -Subject: [PATCH 090/113] mm: randomize lower bits of brk - -Per PaX, but for this alternate brk randomization approach. - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - mm/util.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/mm/util.c b/mm/util.c -index 4ddb6e186dd5..4ca72f952329 100644 ---- a/mm/util.c -+++ b/mm/util.c -@@ -336,9 +336,9 @@ unsigned long arch_randomize_brk(struct mm_struct *mm) - { - /* Is the current task 32bit ? */ - if (!IS_ENABLED(CONFIG_64BIT) || is_compat_task()) -- return randomize_page(mm->brk, SZ_32M); -+ return mm->brk + get_random_long() % SZ_32M; - -- return randomize_page(mm->brk, SZ_1G); -+ return mm->brk + get_random_long() % SZ_1G; - } - - unsigned long arch_mmap_rnd(void) --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0091-x86-randomize-lower-bits-of-brk.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0091-x86-randomize-lower-bits-of-brk.patch deleted file mode 100644 index b266aa24cdd8..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0091-x86-randomize-lower-bits-of-brk.patch +++ /dev/null @@ -1,31 +0,0 @@ -From c6844260df07efd637b315c8ca67ec36fb3005d0 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Thu, 1 Jun 2017 03:23:06 -0400 -Subject: [PATCH 091/113] x86: randomize lower bits of brk - -Per PaX, but for this alternate brk randomization approach. - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - arch/x86/kernel/process.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c -index 61460d55dd72..0d4c3887229d 100644 ---- a/arch/x86/kernel/process.c -+++ b/arch/x86/kernel/process.c -@@ -909,9 +909,9 @@ unsigned long arch_align_stack(unsigned long sp) - unsigned long arch_randomize_brk(struct mm_struct *mm) - { - if (mmap_is_ia32()) -- return randomize_page(mm->brk, SZ_32M); -+ return mm->brk + get_random_long() % SZ_32M; - else -- return randomize_page(mm->brk, SZ_1G); -+ return mm->brk + get_random_long() % SZ_1G; - } - - /* --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0092-mm-guarantee-brk-gap-is-at-least-one-page.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0092-mm-guarantee-brk-gap-is-at-least-one-page.patch deleted file mode 100644 index a8d4f1d61ecc..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0092-mm-guarantee-brk-gap-is-at-least-one-page.patch +++ /dev/null @@ -1,31 +0,0 @@ -From f8919940be09063ec29f0e0ea9da1469d58f2cc1 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Thu, 1 Jun 2017 03:23:39 -0400 -Subject: [PATCH 092/113] mm: guarantee brk gap is at least one page - -Per PaX, but for this alternate brk randomization approach. - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - mm/util.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/mm/util.c b/mm/util.c -index 4ca72f952329..62ed34dfceb7 100644 ---- a/mm/util.c -+++ b/mm/util.c -@@ -336,9 +336,9 @@ unsigned long arch_randomize_brk(struct mm_struct *mm) - { - /* Is the current task 32bit ? */ - if (!IS_ENABLED(CONFIG_64BIT) || is_compat_task()) -- return mm->brk + get_random_long() % SZ_32M; -+ return mm->brk + get_random_long() % SZ_32M + PAGE_SIZE; - -- return mm->brk + get_random_long() % SZ_1G; -+ return mm->brk + get_random_long() % SZ_1G + PAGE_SIZE; - } - - unsigned long arch_mmap_rnd(void) --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0093-x86-guarantee-brk-gap-is-at-least-one-page.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0093-x86-guarantee-brk-gap-is-at-least-one-page.patch deleted file mode 100644 index 00b4d1fa0aef..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0093-x86-guarantee-brk-gap-is-at-least-one-page.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 6b7efcb39595358c65649b973aef2913ad0d799e Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Thu, 1 Jun 2017 03:23:48 -0400 -Subject: [PATCH 093/113] x86: guarantee brk gap is at least one page - -Per PaX, but for this alternate brk randomization approach. - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - arch/x86/kernel/process.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c -index 0d4c3887229d..161e25d02fd5 100644 ---- a/arch/x86/kernel/process.c -+++ b/arch/x86/kernel/process.c -@@ -909,9 +909,9 @@ unsigned long arch_align_stack(unsigned long sp) - unsigned long arch_randomize_brk(struct mm_struct *mm) - { - if (mmap_is_ia32()) -- return mm->brk + get_random_long() % SZ_32M; -+ return mm->brk + get_random_long() % SZ_32M + PAGE_SIZE; - else -- return mm->brk + get_random_long() % SZ_1G; -+ return mm->brk + get_random_long() % SZ_1G + PAGE_SIZE; - } - - /* --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0094-x86_64-bound-mmap-between-legacy-modern-bases.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0094-x86_64-bound-mmap-between-legacy-modern-bases.patch deleted file mode 100644 index 3140177e5960..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0094-x86_64-bound-mmap-between-legacy-modern-bases.patch +++ /dev/null @@ -1,37 +0,0 @@ -From d7a9ef8618009dccbcd086c2f3d21c4a29b6b498 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Tue, 4 Jul 2017 14:50:54 -0400 -Subject: [PATCH 094/113] x86_64: bound mmap between legacy/modern bases - ---- - arch/x86/kernel/sys_x86_64.c | 7 ++----- - 1 file changed, 2 insertions(+), 5 deletions(-) - -diff --git a/arch/x86/kernel/sys_x86_64.c b/arch/x86/kernel/sys_x86_64.c -index c4e35a3b3733..e30ec4c750d1 100644 ---- a/arch/x86/kernel/sys_x86_64.c -+++ b/arch/x86/kernel/sys_x86_64.c -@@ -113,10 +113,7 @@ static void find_start_end(unsigned long addr, unsigned long flags, - } - - *begin = get_mmap_base(1); -- if (in_32bit_syscall()) -- *end = task_size_32bit(); -- else -- *end = task_size_64bit(addr > DEFAULT_MAP_WINDOW); -+ *end = get_mmap_base(0); - } - - unsigned long -@@ -193,7 +190,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, - - info.flags = VM_UNMAPPED_AREA_TOPDOWN; - info.length = len; -- info.low_limit = PAGE_SIZE; -+ info.low_limit = get_mmap_base(1); - info.high_limit = get_mmap_base(0); - - /* --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0095-restrict-device-timing-side-channels.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0095-restrict-device-timing-side-channels.patch deleted file mode 100644 index d276152c9a94..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0095-restrict-device-timing-side-channels.patch +++ /dev/null @@ -1,174 +0,0 @@ -From ce7b0fe63b30677aeaeb161e21c0d552a800ea70 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Tue, 16 May 2017 18:26:10 -0400 -Subject: [PATCH 095/113] restrict device timing side channels - -Based on the public grsecurity patches. - -Signed-off-by: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr> -Signed-off-by: Levente Polyak <levente@leventepolyak.net> ---- - fs/inode.c | 4 ++++ - fs/stat.c | 20 +++++++++++++++----- - include/linux/capability.h | 5 +++++ - include/linux/fs.h | 11 +++++++++++ - include/linux/fsnotify.h | 4 ++++ - kernel/capability.c | 6 ++++++ - kernel/sysctl.c | 9 +++++++++ - 7 files changed, 54 insertions(+), 5 deletions(-) - -diff --git a/fs/inode.c b/fs/inode.c -index 5eea9912a0b9..f86f383a3e1d 100644 ---- a/fs/inode.c -+++ b/fs/inode.c -@@ -116,6 +116,10 @@ int proc_nr_inodes(struct ctl_table *table, int write, - } - #endif - -+/* sysctl */ -+int device_sidechannel_restrict __read_mostly = 1; -+EXPORT_SYMBOL(device_sidechannel_restrict); -+ - static int no_open(struct inode *inode, struct file *file) - { - return -ENXIO; -diff --git a/fs/stat.c b/fs/stat.c -index dacecdda2e79..14173d0f777d 100644 ---- a/fs/stat.c -+++ b/fs/stat.c -@@ -43,8 +43,13 @@ void generic_fillattr(struct inode *inode, struct kstat *stat) - stat->gid = inode->i_gid; - stat->rdev = inode->i_rdev; - stat->size = i_size_read(inode); -- stat->atime = inode->i_atime; -- stat->mtime = inode->i_mtime; -+ if (is_sidechannel_device(inode) && !capable_noaudit(CAP_MKNOD)) { -+ stat->atime = inode->i_ctime; -+ stat->mtime = inode->i_ctime; -+ } else { -+ stat->atime = inode->i_atime; -+ stat->mtime = inode->i_mtime; -+ } - stat->ctime = inode->i_ctime; - stat->blksize = i_blocksize(inode); - stat->blocks = inode->i_blocks; -@@ -83,9 +88,14 @@ int vfs_getattr_nosec(const struct path *path, struct kstat *stat, - if (IS_DAX(inode)) - stat->attributes |= STATX_ATTR_DAX; - -- if (inode->i_op->getattr) -- return inode->i_op->getattr(path, stat, request_mask, -- query_flags); -+ if (inode->i_op->getattr) { -+ int retval = inode->i_op->getattr(path, stat, request_mask, query_flags); -+ if (!retval && is_sidechannel_device(inode) && !capable_noaudit(CAP_MKNOD)) { -+ stat->atime = stat->ctime; -+ stat->mtime = stat->ctime; -+ } -+ return retval; -+ } - - generic_fillattr(inode, stat); - return 0; -diff --git a/include/linux/capability.h b/include/linux/capability.h -index 1e7fe311cabe..a5b6d4c9acf5 100644 ---- a/include/linux/capability.h -+++ b/include/linux/capability.h -@@ -208,6 +208,7 @@ extern bool has_capability_noaudit(struct task_struct *t, int cap); - extern bool has_ns_capability_noaudit(struct task_struct *t, - struct user_namespace *ns, int cap); - extern bool capable(int cap); -+extern bool capable_noaudit(int cap); - extern bool ns_capable(struct user_namespace *ns, int cap); - extern bool ns_capable_noaudit(struct user_namespace *ns, int cap); - extern bool ns_capable_setid(struct user_namespace *ns, int cap); -@@ -234,6 +235,10 @@ static inline bool capable(int cap) - { - return true; - } -+static inline bool capable_noaudit(int cap) -+{ -+ return true; -+} - static inline bool ns_capable(struct user_namespace *ns, int cap) - { - return true; -diff --git a/include/linux/fs.h b/include/linux/fs.h -index 8bde32cf9711..83d50b0a2a18 100644 ---- a/include/linux/fs.h -+++ b/include/linux/fs.h -@@ -3475,4 +3475,15 @@ static inline int inode_drain_writes(struct inode *inode) - return filemap_write_and_wait(inode->i_mapping); - } - -+extern int device_sidechannel_restrict; -+ -+static inline bool is_sidechannel_device(const struct inode *inode) -+{ -+ umode_t mode; -+ if (!device_sidechannel_restrict) -+ return false; -+ mode = inode->i_mode; -+ return ((S_ISCHR(mode) || S_ISBLK(mode)) && (mode & (S_IROTH | S_IWOTH))); -+} -+ - #endif /* _LINUX_FS_H */ -diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h -index f8acddcf54fb..7b109980327f 100644 ---- a/include/linux/fsnotify.h -+++ b/include/linux/fsnotify.h -@@ -83,10 +83,14 @@ static inline void fsnotify_dentry(struct dentry *dentry, __u32 mask) - static inline int fsnotify_file(struct file *file, __u32 mask) - { - const struct path *path = &file->f_path; -+ struct inode *inode = file_inode(file); - - if (file->f_mode & FMODE_NONOTIFY) - return 0; - -+ if (mask & (FS_ACCESS | FS_MODIFY) && is_sidechannel_device(inode)) -+ return 0; -+ - return fsnotify_parent(path->dentry, mask, path, FSNOTIFY_EVENT_PATH); - } - -diff --git a/kernel/capability.c b/kernel/capability.c -index de7eac903a2a..5602178f3d21 100644 ---- a/kernel/capability.c -+++ b/kernel/capability.c -@@ -449,6 +449,12 @@ bool capable(int cap) - return ns_capable(&init_user_ns, cap); - } - EXPORT_SYMBOL(capable); -+ -+bool capable_noaudit(int cap) -+{ -+ return ns_capable_noaudit(&init_user_ns, cap); -+} -+EXPORT_SYMBOL(capable_noaudit); - #endif /* CONFIG_MULTIUSER */ - - /** -diff --git a/kernel/sysctl.c b/kernel/sysctl.c -index fccf24a08c8a..7fda9f61ea1a 100644 ---- a/kernel/sysctl.c -+++ b/kernel/sysctl.c -@@ -2272,6 +2272,15 @@ static struct ctl_table kern_table[] = { - .extra2 = &two, - }, - #endif -+ { -+ .procname = "device_sidechannel_restrict", -+ .data = &device_sidechannel_restrict, -+ .maxlen = sizeof(int), -+ .mode = 0644, -+ .proc_handler = proc_dointvec_minmax_sysadmin, -+ .extra1 = SYSCTL_ZERO, -+ .extra2 = SYSCTL_ONE, -+ }, - { - .procname = "ngroups_max", - .data = &ngroups_max, --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0096-sysctl-expose-proc_dointvec_minmax_sysadmin-as-API-f.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0096-sysctl-expose-proc_dointvec_minmax_sysadmin-as-API-f.patch deleted file mode 100644 index 629f8256d952..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0096-sysctl-expose-proc_dointvec_minmax_sysadmin-as-API-f.patch +++ /dev/null @@ -1,95 +0,0 @@ -From 6a1b1cc37d5d3aa6a23ef6aab6b4726720cd225c Mon Sep 17 00:00:00 2001 -From: Levente Polyak <levente@leventepolyak.net> -Date: Sun, 6 Sep 2020 20:28:32 +0200 -Subject: [PATCH 096/113] sysctl: expose proc_dointvec_minmax_sysadmin as API - function - -Orthogonal to the other sysctl proc functions expose the variant that is -checking CAP_SYS_ADMIN on write for consumption in external subsystem's -sysctl tables. - -Signed-off-by: Levente Polyak <levente@leventepolyak.net> ---- - include/linux/sysctl.h | 2 ++ - kernel/sysctl.c | 31 ++++++++++++++++++++++++++++--- - 2 files changed, 30 insertions(+), 3 deletions(-) - -diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h -index 51298a4f4623..b835c57330f2 100644 ---- a/include/linux/sysctl.h -+++ b/include/linux/sysctl.h -@@ -53,6 +53,8 @@ int proc_douintvec(struct ctl_table *, int, void *, size_t *, loff_t *); - int proc_dointvec_minmax(struct ctl_table *, int, void *, size_t *, loff_t *); - int proc_douintvec_minmax(struct ctl_table *table, int write, void *buffer, - size_t *lenp, loff_t *ppos); -+int proc_dointvec_minmax_sysadmin(struct ctl_table *table, int write, -+ void *buffer, size_t *lenp, loff_t *ppos); - int proc_dointvec_jiffies(struct ctl_table *, int, void *, size_t *, loff_t *); - int proc_dointvec_userhz_jiffies(struct ctl_table *, int, void *, size_t *, - loff_t *); -diff --git a/kernel/sysctl.c b/kernel/sysctl.c -index 7fda9f61ea1a..13b619e46ade 100644 ---- a/kernel/sysctl.c -+++ b/kernel/sysctl.c -@@ -890,8 +890,27 @@ static int proc_taint(struct ctl_table *table, int write, - return err; - } - --#ifdef CONFIG_PRINTK --static int proc_dointvec_minmax_sysadmin(struct ctl_table *table, int write, -+/** -+ * proc_dointvec_minmax_sysadmin - read a vector of integers with min/max values -+ * checking CAP_SYS_ADMIN on write -+ * @table: the sysctl table -+ * @write: %TRUE if this is a write to the sysctl file -+ * @buffer: the user buffer -+ * @lenp: the size of the user buffer -+ * @ppos: file position -+ * -+ * Reads/writes up to table->maxlen/sizeof(unsigned int) integer -+ * values from/to the user buffer, treated as an ASCII string. -+ * -+ * This routine will ensure the values are within the range specified by -+ * table->extra1 (min) and table->extra2 (max). -+ * -+ * Writing is only allowed when root has CAP_SYS_ADMIN. -+ * -+ * Returns 0 on success, -EPERM on permission failure or -EINVAL on write -+ * when the range check fails. -+ */ -+int proc_dointvec_minmax_sysadmin(struct ctl_table *table, int write, - void *buffer, size_t *lenp, loff_t *ppos) - { - if (write && !capable(CAP_SYS_ADMIN)) -@@ -899,7 +918,6 @@ static int proc_dointvec_minmax_sysadmin(struct ctl_table *table, int write, - - return proc_dointvec_minmax(table, write, buffer, lenp, ppos); - } --#endif - - /** - * struct do_proc_dointvec_minmax_conv_param - proc_dointvec_minmax() range checking structure -@@ -1585,6 +1603,12 @@ int proc_douintvec_minmax(struct ctl_table *table, int write, - return -ENOSYS; - } - -+int proc_dointvec_minmax_sysadmin(struct ctl_table *table, int write, -+ void *buffer, size_t *lenp, loff_t *ppos) -+{ -+ return -ENOSYS; -+} -+ - int proc_dointvec_jiffies(struct ctl_table *table, int write, - void *buffer, size_t *lenp, loff_t *ppos) - { -@@ -3436,6 +3460,7 @@ EXPORT_SYMBOL(proc_douintvec); - EXPORT_SYMBOL(proc_dointvec_jiffies); - EXPORT_SYMBOL(proc_dointvec_minmax); - EXPORT_SYMBOL_GPL(proc_douintvec_minmax); -+EXPORT_SYMBOL(proc_dointvec_minmax_sysadmin); - EXPORT_SYMBOL(proc_dointvec_userhz_jiffies); - EXPORT_SYMBOL(proc_dointvec_ms_jiffies); - EXPORT_SYMBOL(proc_dostring); --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0097-usb-add-toggle-for-disabling-newly-added-USB-devices.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0097-usb-add-toggle-for-disabling-newly-added-USB-devices.patch deleted file mode 100644 index 8a965de850f9..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0097-usb-add-toggle-for-disabling-newly-added-USB-devices.patch +++ /dev/null @@ -1,92 +0,0 @@ -From 4091a85d5aefe21c2a671e2b8f72f887b6199c54 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Tue, 16 May 2017 17:51:48 -0400 -Subject: [PATCH 097/113] usb: add toggle for disabling newly added USB devices - -Based on the public grsecurity patches. - -[thibaut.sautereau@ssi.gouv.fr: Adapt to sysctl code refactoring] -Signed-off-by: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr> -Signed-off-by: Levente Polyak <levente@leventepolyak.net> ---- - drivers/usb/core/hub.c | 9 +++++++++ - include/linux/usb.h | 3 +++ - kernel/sysctl.c | 14 ++++++++++++++ - 3 files changed, 26 insertions(+) - -diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c -index 17202b2ee063..9385c745d55e 100644 ---- a/drivers/usb/core/hub.c -+++ b/drivers/usb/core/hub.c -@@ -5054,6 +5054,9 @@ static int descriptors_changed(struct usb_device *udev, - return changed; - } - -+/* sysctl */ -+int deny_new_usb __read_mostly = 0; -+ - static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus, - u16 portchange) - { -@@ -5114,6 +5117,12 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus, - goto done; - return; - } -+ -+ if (deny_new_usb) { -+ dev_err(&port_dev->dev, "denied insert of USB device on port %d\n", port1); -+ goto done; -+ } -+ - if (hub_is_superspeed(hub->hdev)) - unit_load = 150; - else -diff --git a/include/linux/usb.h b/include/linux/usb.h -index 7d72c4e0713c..8e7549e3012a 100644 ---- a/include/linux/usb.h -+++ b/include/linux/usb.h -@@ -2035,6 +2035,9 @@ extern void usb_led_activity(enum usb_led_event ev); - static inline void usb_led_activity(enum usb_led_event ev) {} - #endif - -+/* sysctl */ -+extern int deny_new_usb; -+ - #endif /* __KERNEL__ */ - - #endif -diff --git a/kernel/sysctl.c b/kernel/sysctl.c -index 13b619e46ade..f867606fbd80 100644 ---- a/kernel/sysctl.c -+++ b/kernel/sysctl.c -@@ -106,6 +106,9 @@ - #ifdef CONFIG_USER_NS - #include <linux/user_namespace.h> - #endif -+#if IS_ENABLED(CONFIG_USB) -+#include <linux/usb.h> -+#endif - - #if defined(CONFIG_SYSCTL) - -@@ -2305,6 +2308,17 @@ static struct ctl_table kern_table[] = { - .extra1 = SYSCTL_ZERO, - .extra2 = SYSCTL_ONE, - }, -+#if IS_ENABLED(CONFIG_USB) -+ { -+ .procname = "deny_new_usb", -+ .data = &deny_new_usb, -+ .maxlen = sizeof(int), -+ .mode = 0644, -+ .proc_handler = proc_dointvec_minmax_sysadmin, -+ .extra1 = SYSCTL_ZERO, -+ .extra2 = SYSCTL_ONE, -+ }, -+#endif - { - .procname = "ngroups_max", - .data = &ngroups_max, --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0098-usb-implement-dedicated-subsystem-sysctl-tables.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0098-usb-implement-dedicated-subsystem-sysctl-tables.patch deleted file mode 100644 index 8e747bc33d43..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0098-usb-implement-dedicated-subsystem-sysctl-tables.patch +++ /dev/null @@ -1,195 +0,0 @@ -From 9aaa0c74187b97e2ba307931d2c8c28df024fbb0 Mon Sep 17 00:00:00 2001 -From: Levente Polyak <levente@leventepolyak.net> -Date: Sun, 6 Sep 2020 21:08:16 +0200 -Subject: [PATCH 098/113] usb: implement dedicated subsystem sysctl tables - -This moves the usb related sysctl knobs to an own usb local sysctl table -in order to clean up the global sysctl as well as allow the knob to be -exported and referenced appropriately when building the usb components -as dedicated modules. - -Signed-off-by: Levente Polyak <levente@leventepolyak.net> ---- - drivers/usb/core/Makefile | 1 + - drivers/usb/core/hub.c | 3 --- - drivers/usb/core/sysctl.c | 44 +++++++++++++++++++++++++++++++++++++++ - drivers/usb/core/usb.c | 9 ++++++++ - include/linux/usb.h | 10 ++++++++- - kernel/sysctl.c | 14 ------------- - 6 files changed, 63 insertions(+), 18 deletions(-) - create mode 100644 drivers/usb/core/sysctl.c - -diff --git a/drivers/usb/core/Makefile b/drivers/usb/core/Makefile -index 18e874b0441e..fc7a3a9aa72a 100644 ---- a/drivers/usb/core/Makefile -+++ b/drivers/usb/core/Makefile -@@ -11,6 +11,7 @@ usbcore-y += phy.o port.o - usbcore-$(CONFIG_OF) += of.o - usbcore-$(CONFIG_USB_PCI) += hcd-pci.o - usbcore-$(CONFIG_ACPI) += usb-acpi.o -+usbcore-$(CONFIG_SYSCTL) += sysctl.o - - obj-$(CONFIG_USB) += usbcore.o - -diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c -index 9385c745d55e..b62b3da81ac4 100644 ---- a/drivers/usb/core/hub.c -+++ b/drivers/usb/core/hub.c -@@ -5054,9 +5054,6 @@ static int descriptors_changed(struct usb_device *udev, - return changed; - } - --/* sysctl */ --int deny_new_usb __read_mostly = 0; -- - static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus, - u16 portchange) - { -diff --git a/drivers/usb/core/sysctl.c b/drivers/usb/core/sysctl.c -new file mode 100644 -index 000000000000..3fa188ac8f67 ---- /dev/null -+++ b/drivers/usb/core/sysctl.c -@@ -0,0 +1,44 @@ -+#include <linux/errno.h> -+#include <linux/init.h> -+#include <linux/kmemleak.h> -+#include <linux/sysctl.h> -+#include <linux/usb.h> -+ -+static struct ctl_table usb_table[] = { -+ { -+ .procname = "deny_new_usb", -+ .data = &deny_new_usb, -+ .maxlen = sizeof(int), -+ .mode = 0644, -+ .proc_handler = proc_dointvec_minmax_sysadmin, -+ .extra1 = SYSCTL_ZERO, -+ .extra2 = SYSCTL_ONE, -+ }, -+ { } -+}; -+ -+static struct ctl_table usb_root_table[] = { -+ { .procname = "kernel", -+ .mode = 0555, -+ .child = usb_table }, -+ { } -+}; -+ -+static struct ctl_table_header *usb_table_header; -+ -+int __init usb_init_sysctl(void) -+{ -+ usb_table_header = register_sysctl_table(usb_root_table); -+ if (!usb_table_header) { -+ pr_warn("usb: sysctl registration failed\n"); -+ return -ENOMEM; -+ } -+ -+ kmemleak_not_leak(usb_table_header); -+ return 0; -+} -+ -+void usb_exit_sysctl(void) -+{ -+ unregister_sysctl_table(usb_table_header); -+} -diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c -index 9b4ac4415f1a..93b4b798bdcc 100644 ---- a/drivers/usb/core/usb.c -+++ b/drivers/usb/core/usb.c -@@ -72,6 +72,9 @@ MODULE_PARM_DESC(autosuspend, "default autosuspend delay"); - #define usb_autosuspend_delay 0 - #endif - -+int deny_new_usb __read_mostly = 0; -+EXPORT_SYMBOL(deny_new_usb); -+ - static bool match_endpoint(struct usb_endpoint_descriptor *epd, - struct usb_endpoint_descriptor **bulk_in, - struct usb_endpoint_descriptor **bulk_out, -@@ -978,6 +981,9 @@ static int __init usb_init(void) - usb_debugfs_init(); - - usb_acpi_register(); -+ retval = usb_init_sysctl(); -+ if (retval) -+ goto sysctl_init_failed; - retval = bus_register(&usb_bus_type); - if (retval) - goto bus_register_failed; -@@ -1012,6 +1018,8 @@ static int __init usb_init(void) - bus_notifier_failed: - bus_unregister(&usb_bus_type); - bus_register_failed: -+ usb_exit_sysctl(); -+sysctl_init_failed: - usb_acpi_unregister(); - usb_debugfs_cleanup(); - out: -@@ -1035,6 +1043,7 @@ static void __exit usb_exit(void) - usb_hub_cleanup(); - bus_unregister_notifier(&usb_bus_type, &usb_bus_nb); - bus_unregister(&usb_bus_type); -+ usb_exit_sysctl(); - usb_acpi_unregister(); - usb_debugfs_cleanup(); - idr_destroy(&usb_bus_idr); -diff --git a/include/linux/usb.h b/include/linux/usb.h -index 8e7549e3012a..653265115e56 100644 ---- a/include/linux/usb.h -+++ b/include/linux/usb.h -@@ -2035,8 +2035,16 @@ extern void usb_led_activity(enum usb_led_event ev); - static inline void usb_led_activity(enum usb_led_event ev) {} - #endif - --/* sysctl */ -+/* sysctl.c */ - extern int deny_new_usb; -+#ifdef CONFIG_SYSCTL -+extern int usb_init_sysctl(void); -+extern void usb_exit_sysctl(void); -+#else -+static inline int usb_init_sysctl(void) { return 0; } -+static inline void usb_exit_sysctl(void) { } -+#endif /* CONFIG_SYSCTL */ -+ - - #endif /* __KERNEL__ */ - -diff --git a/kernel/sysctl.c b/kernel/sysctl.c -index f867606fbd80..13b619e46ade 100644 ---- a/kernel/sysctl.c -+++ b/kernel/sysctl.c -@@ -106,9 +106,6 @@ - #ifdef CONFIG_USER_NS - #include <linux/user_namespace.h> - #endif --#if IS_ENABLED(CONFIG_USB) --#include <linux/usb.h> --#endif - - #if defined(CONFIG_SYSCTL) - -@@ -2308,17 +2305,6 @@ static struct ctl_table kern_table[] = { - .extra1 = SYSCTL_ZERO, - .extra2 = SYSCTL_ONE, - }, --#if IS_ENABLED(CONFIG_USB) -- { -- .procname = "deny_new_usb", -- .data = &deny_new_usb, -- .maxlen = sizeof(int), -- .mode = 0644, -- .proc_handler = proc_dointvec_minmax_sysadmin, -- .extra1 = SYSCTL_ZERO, -- .extra2 = SYSCTL_ONE, -- }, --#endif - { - .procname = "ngroups_max", - .data = &ngroups_max, --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0099-hard-wire-legacy-checkreqprot-option-to-0.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0099-hard-wire-legacy-checkreqprot-option-to-0.patch deleted file mode 100644 index 49bbec9b2623..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0099-hard-wire-legacy-checkreqprot-option-to-0.patch +++ /dev/null @@ -1,133 +0,0 @@ -From 96e5b1d593f3af1ee253cc9fc99a5fb2c456a51f Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Sun, 25 Feb 2018 03:26:45 -0500 -Subject: [PATCH 099/113] hard-wire legacy checkreqprot option to 0 - -The userspace API is left intact for compatibility. - -Signed-off-by: Levente Polyak <levente@leventepolyak.net> ---- - .../admin-guide/kernel-parameters.txt | 11 --------- - security/selinux/Kconfig | 23 ------------------- - security/selinux/hooks.c | 16 +------------ - security/selinux/selinuxfs.c | 12 +--------- - 4 files changed, 2 insertions(+), 60 deletions(-) - -diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt -index e7ea794320e8..0e8e3fdd7005 100644 ---- a/Documentation/admin-guide/kernel-parameters.txt -+++ b/Documentation/admin-guide/kernel-parameters.txt -@@ -518,17 +518,6 @@ - nosocket -- Disable socket memory accounting. - nokmem -- Disable kernel memory accounting. - -- checkreqprot [SELINUX] Set initial checkreqprot flag value. -- Format: { "0" | "1" } -- See security/selinux/Kconfig help text. -- 0 -- check protection applied by kernel (includes -- any implied execute protection). -- 1 -- check protection requested by application. -- Default value is set via a kernel config option. -- Value can be changed at runtime via -- /sys/fs/selinux/checkreqprot. -- Setting checkreqprot to 1 is deprecated. -- - cio_ignore= [S390] - See Documentation/s390/common_io.rst for details. - clk_ignore_unused -diff --git a/security/selinux/Kconfig b/security/selinux/Kconfig -index 76d7ed11513c..ae851a826c26 100644 ---- a/security/selinux/Kconfig -+++ b/security/selinux/Kconfig -@@ -70,29 +70,6 @@ config SECURITY_SELINUX_AVC_STATS - /sys/fs/selinux/avc/cache_stats, which may be monitored via - tools such as avcstat. - --config SECURITY_SELINUX_CHECKREQPROT_VALUE -- int "NSA SELinux checkreqprot default value" -- depends on SECURITY_SELINUX -- range 0 1 -- default 0 -- help -- This option sets the default value for the 'checkreqprot' flag -- that determines whether SELinux checks the protection requested -- by the application or the protection that will be applied by the -- kernel (including any implied execute for read-implies-exec) for -- mmap and mprotect calls. If this option is set to 0 (zero), -- SELinux will default to checking the protection that will be applied -- by the kernel. If this option is set to 1 (one), SELinux will -- default to checking the protection requested by the application. -- The checkreqprot flag may be changed from the default via the -- 'checkreqprot=' boot parameter. It may also be changed at runtime -- via /sys/fs/selinux/checkreqprot if authorized by policy. -- -- WARNING: this option is deprecated and will be removed in a future -- kernel release. -- -- If you are unsure how to answer this question, answer 0. -- - config SECURITY_SELINUX_SIDTAB_HASH_BITS - int "NSA SELinux sidtab hashtable size" - depends on SECURITY_SELINUX -diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c -index c46312710e73..541c65650c5e 100644 ---- a/security/selinux/hooks.c -+++ b/security/selinux/hooks.c -@@ -136,21 +136,7 @@ static int __init selinux_enabled_setup(char *str) - __setup("selinux=", selinux_enabled_setup); - #endif - --static unsigned int selinux_checkreqprot_boot = -- CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE; -- --static int __init checkreqprot_setup(char *str) --{ -- unsigned long checkreqprot; -- -- if (!kstrtoul(str, 0, &checkreqprot)) { -- selinux_checkreqprot_boot = checkreqprot ? 1 : 0; -- if (checkreqprot) -- pr_warn("SELinux: checkreqprot set to 1 via kernel parameter. This is deprecated and will be rejected in a future kernel release.\n"); -- } -- return 1; --} --__setup("checkreqprot=", checkreqprot_setup); -+static const unsigned int selinux_checkreqprot_boot; - - /** - * selinux_secmark_enabled - Check to see if SECMARK is currently enabled -diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c -index 4bde570d56a2..cc5caffc07fa 100644 ---- a/security/selinux/selinuxfs.c -+++ b/security/selinux/selinuxfs.c -@@ -725,7 +725,6 @@ static ssize_t sel_read_checkreqprot(struct file *filp, char __user *buf, - static ssize_t sel_write_checkreqprot(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) - { -- struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info; - char *page; - ssize_t length; - unsigned int new_value; -@@ -749,18 +748,9 @@ static ssize_t sel_write_checkreqprot(struct file *file, const char __user *buf, - return PTR_ERR(page); - - length = -EINVAL; -- if (sscanf(page, "%u", &new_value) != 1) -+ if (sscanf(page, "%u", &new_value) != 1 || new_value) - goto out; - -- if (new_value) { -- char comm[sizeof(current->comm)]; -- -- memcpy(comm, current->comm, sizeof(comm)); -- pr_warn_once("SELinux: %s (%d) set checkreqprot to 1. This is deprecated and will be rejected in a future kernel release.\n", -- comm, current->pid); -- } -- -- checkreqprot_set(fsi->state, (new_value ? 1 : 0)); - length = count; - out: - kfree(page); --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0100-security-tty-Add-owner-user-namespace-to-tty_struct.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0100-security-tty-Add-owner-user-namespace-to-tty_struct.patch deleted file mode 100644 index 3c1ffe524cbd..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0100-security-tty-Add-owner-user-namespace-to-tty_struct.patch +++ /dev/null @@ -1,70 +0,0 @@ -From 64560b691de1cbd35e117bb91b97508c2e5ed711 Mon Sep 17 00:00:00 2001 -From: Matt Brown <matt@nmatt.com> -Date: Mon, 29 May 2017 17:37:59 -0400 -Subject: [PATCH 100/113] security: tty: Add owner user namespace to tty_struct - -This patch adds struct user_namespace *owner_user_ns to the tty_struct. -Then it is set to current_user_ns() in the alloc_tty_struct function. - -This is done to facilitate capability checks against the original user -namespace that allocated the tty. - -E.g. ns_capable(tty->owner_user_ns,CAP_SYS_ADMIN) - -This combined with the use of user namespace's will allow hardening -protections to be built to mitigate container escapes that utilize TTY -ioctls such as TIOCSTI. - -See: https://bugzilla.redhat.com/show_bug.cgi?id=1411256 - -Acked-by: Serge Hallyn <serge@hallyn.com> -Reviewed-by: Kees Cook <keescook@chromium.org> -Signed-off-by: Matt Brown <matt@nmatt.com> ---- - drivers/tty/tty_io.c | 2 ++ - include/linux/tty.h | 2 ++ - 2 files changed, 4 insertions(+) - -diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c -index 2f8223b2ffa4..4575de4e7520 100644 ---- a/drivers/tty/tty_io.c -+++ b/drivers/tty/tty_io.c -@@ -171,6 +171,7 @@ static void free_tty_struct(struct tty_struct *tty) - put_device(tty->dev); - kfree(tty->write_buf); - tty->magic = 0xDEADDEAD; -+ put_user_ns(tty->owner_user_ns); - kfree(tty); - } - -@@ -3017,6 +3018,7 @@ struct tty_struct *alloc_tty_struct(struct tty_driver *driver, int idx) - tty->index = idx; - tty_line_name(driver, idx, tty->name); - tty->dev = tty_get_device(tty); -+ tty->owner_user_ns = get_user_ns(current_user_ns()); - - return tty; - } -diff --git a/include/linux/tty.h b/include/linux/tty.h -index bc8caac390fc..29fd018fc255 100644 ---- a/include/linux/tty.h -+++ b/include/linux/tty.h -@@ -14,6 +14,7 @@ - #include <uapi/linux/tty.h> - #include <linux/rwsem.h> - #include <linux/llist.h> -+#include <linux/user_namespace.h> - - - /* -@@ -342,6 +343,7 @@ struct tty_struct { - /* If the tty has a pending do_SAK, queue it here - akpm */ - struct work_struct SAK_work; - struct tty_port *port; -+ struct user_namespace *owner_user_ns; - } __randomize_layout; - - /* Each of a tty's open files has private_data pointing to tty_file_private */ --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0101-security-tty-make-TIOCSTI-ioctl-require-CAP_SYS_ADMI.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0101-security-tty-make-TIOCSTI-ioctl-require-CAP_SYS_ADMI.patch deleted file mode 100644 index 530cbeba09ca..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0101-security-tty-make-TIOCSTI-ioctl-require-CAP_SYS_ADMI.patch +++ /dev/null @@ -1,197 +0,0 @@ -From 102a2f9c70766abff55a0ae7f83d12a959647ae6 Mon Sep 17 00:00:00 2001 -From: Matt Brown <matt@nmatt.com> -Date: Mon, 29 May 2017 17:38:00 -0400 -Subject: [PATCH 101/113] security: tty: make TIOCSTI ioctl require - CAP_SYS_ADMIN - -This introduces the tiocsti_restrict sysctl, whose default is controlled -via CONFIG_SECURITY_TIOCSTI_RESTRICT. When activated, this control -restricts all TIOCSTI ioctl calls from non CAP_SYS_ADMIN users. - -This patch depends on patch 1/2 - -This patch was inspired from GRKERNSEC_HARDEN_TTY. - -This patch would have prevented -https://bugzilla.redhat.com/show_bug.cgi?id=1411256 under the following -conditions: -* non-privileged container -* container run inside new user namespace - -Possible effects on userland: - -There could be a few user programs that would be effected by this -change. -See: <https://codesearch.debian.net/search?q=ioctl%5C%28.*TIOCSTI> -notable programs are: agetty, csh, xemacs and tcsh - -However, I still believe that this change is worth it given that the -Kconfig defaults to n. This will be a feature that is turned on for the -same reason that people activate it when using grsecurity. Users of this -opt-in feature will realize that they are choosing security over some OS -features like unprivileged TIOCSTI ioctls, as should be clear in the -Kconfig help message. - -Threat Model/Patch Rational: - ->From grsecurity's config for GRKERNSEC_HARDEN_TTY. - - | There are very few legitimate uses for this functionality and it - | has made vulnerabilities in several 'su'-like programs possible in - | the past. Even without these vulnerabilities, it provides an - | attacker with an easy mechanism to move laterally among other - | processes within the same user's compromised session. - -So if one process within a tty session becomes compromised it can follow -that additional processes, that are thought to be in different security -boundaries, can be compromised as a result. When using a program like su -or sudo, these additional processes could be in a tty session where TTY -file descriptors are indeed shared over privilege boundaries. - -This is also an excellent writeup about the issue: -<http://www.halfdog.net/Security/2012/TtyPushbackPrivilegeEscalation/> - -When user namespaces are in use, the check for the capability -CAP_SYS_ADMIN is done against the user namespace that originally opened -the tty. - -Acked-by: Serge Hallyn <serge@hallyn.com> -Reviewed-by: Kees Cook <keescook@chromium.org> -Signed-off-by: Matt Brown <matt@nmatt.com> -Signed-off-by: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr> -Signed-off-by: Levente Polyak <levente@leventepolyak.net> ---- - Documentation/admin-guide/sysctl/kernel.rst | 20 ++++++++++++++++++++ - drivers/tty/tty_io.c | 8 ++++++++ - include/linux/tty.h | 2 ++ - kernel/sysctl.c | 14 ++++++++++++++ - security/Kconfig | 13 +++++++++++++ - 5 files changed, 57 insertions(+) - -diff --git a/Documentation/admin-guide/sysctl/kernel.rst b/Documentation/admin-guide/sysctl/kernel.rst -index 4c20e6ded0af..3cd263f8ac46 100644 ---- a/Documentation/admin-guide/sysctl/kernel.rst -+++ b/Documentation/admin-guide/sysctl/kernel.rst -@@ -1385,6 +1385,26 @@ If a value outside of this range is written to ``threads-max`` an - ``EINVAL`` error occurs. - - -+tiocsti_restrict -+================ -+ -+This toggle indicates whether unprivileged users are prevented from using the -+``TIOCSTI`` ioctl to inject commands into other processes which share a tty -+session. -+ -+= ============================================================================ -+0 No restriction, except the default one of only being able to inject commands -+ into one's own tty. -+1 Users must have ``CAP_SYS_ADMIN`` to use the ``TIOCSTI`` ioctl. -+= ============================================================================ -+ -+When user namespaces are in use, the check for ``CAP_SYS_ADMIN`` is done -+against the user namespace that originally opened the tty. -+ -+The kernel config option ``CONFIG_SECURITY_TIOCSTI_RESTRICT`` sets the default -+value of ``tiocsti_restrict``. -+ -+ - traceoff_on_warning - =================== - -diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c -index 4575de4e7520..9c385bfe255a 100644 ---- a/drivers/tty/tty_io.c -+++ b/drivers/tty/tty_io.c -@@ -2185,11 +2185,19 @@ static int tty_fasync(int fd, struct file *filp, int on) - * FIXME: may race normal receive processing - */ - -+int tiocsti_restrict = IS_ENABLED(CONFIG_SECURITY_TIOCSTI_RESTRICT); -+ - static int tiocsti(struct tty_struct *tty, char __user *p) - { - char ch, mbz = 0; - struct tty_ldisc *ld; - -+ if (tiocsti_restrict && -+ !ns_capable(tty->owner_user_ns, CAP_SYS_ADMIN)) { -+ dev_warn_ratelimited(tty->dev, -+ "Denied TIOCSTI ioctl for non-privileged process\n"); -+ return -EPERM; -+ } - if ((current->signal->tty != tty) && !capable(CAP_SYS_ADMIN)) - return -EPERM; - if (get_user(ch, p)) -diff --git a/include/linux/tty.h b/include/linux/tty.h -index 29fd018fc255..743e3964a03a 100644 ---- a/include/linux/tty.h -+++ b/include/linux/tty.h -@@ -353,6 +353,8 @@ struct tty_file_private { - struct list_head list; - }; - -+extern int tiocsti_restrict; -+ - /* tty magic number */ - #define TTY_MAGIC 0x5401 - -diff --git a/kernel/sysctl.c b/kernel/sysctl.c -index 13b619e46ade..8fd007fbec4c 100644 ---- a/kernel/sysctl.c -+++ b/kernel/sysctl.c -@@ -106,6 +106,9 @@ - #ifdef CONFIG_USER_NS - #include <linux/user_namespace.h> - #endif -+#if defined CONFIG_TTY -+#include <linux/tty.h> -+#endif - - #if defined(CONFIG_SYSCTL) - -@@ -2295,6 +2298,17 @@ static struct ctl_table kern_table[] = { - .extra1 = SYSCTL_ZERO, - .extra2 = &two, - }, -+#endif -+#if defined CONFIG_TTY -+ { -+ .procname = "tiocsti_restrict", -+ .data = &tiocsti_restrict, -+ .maxlen = sizeof(int), -+ .mode = 0644, -+ .proc_handler = proc_dointvec_minmax_sysadmin, -+ .extra1 = SYSCTL_ZERO, -+ .extra2 = SYSCTL_ONE, -+ }, - #endif - { - .procname = "device_sidechannel_restrict", -diff --git a/security/Kconfig b/security/Kconfig -index f3c995bd79cf..c8ea5a6ecce0 100644 ---- a/security/Kconfig -+++ b/security/Kconfig -@@ -29,6 +29,19 @@ config SECURITY_PERF_EVENTS_RESTRICT - perf_event_open syscall will be permitted unless it is - changed. - -+config SECURITY_TIOCSTI_RESTRICT -+ bool "Restrict unprivileged use of tiocsti command injection" -+ default n -+ help -+ This enforces restrictions on unprivileged users injecting commands -+ into other processes which share a tty session using the TIOCSTI -+ ioctl. This option makes TIOCSTI use require CAP_SYS_ADMIN. -+ -+ If this option is not selected, no restrictions will be enforced -+ unless the tiocsti_restrict sysctl is explicitly set to (1). -+ -+ If you are unsure how to answer this question, answer N. -+ - config SECURITY - bool "Enable different security models" - depends on SYSFS --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0102-enable-SECURITY_TIOCSTI_RESTRICT-by-default.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0102-enable-SECURITY_TIOCSTI_RESTRICT-by-default.patch deleted file mode 100644 index 91b69f34130d..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0102-enable-SECURITY_TIOCSTI_RESTRICT-by-default.patch +++ /dev/null @@ -1,26 +0,0 @@ -From de6705ab90abfa7d2638503747f2e39bd2a6968a Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Wed, 3 May 2017 23:36:14 -0400 -Subject: [PATCH 102/113] enable SECURITY_TIOCSTI_RESTRICT by default - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - security/Kconfig | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/security/Kconfig b/security/Kconfig -index c8ea5a6ecce0..615205c0113b 100644 ---- a/security/Kconfig -+++ b/security/Kconfig -@@ -31,7 +31,7 @@ config SECURITY_PERF_EVENTS_RESTRICT - - config SECURITY_TIOCSTI_RESTRICT - bool "Restrict unprivileged use of tiocsti command injection" -- default n -+ default y - help - This enforces restrictions on unprivileged users injecting commands - into other processes which share a tty session using the TIOCSTI --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0103-disable-unprivileged-eBPF-access-by-default.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0103-disable-unprivileged-eBPF-access-by-default.patch deleted file mode 100644 index 004b73121835..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0103-disable-unprivileged-eBPF-access-by-default.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 53965dd6981a73b1d92f428d2f952bf1b265f535 Mon Sep 17 00:00:00 2001 -From: Levente Polyak <levente@leventepolyak.net> -Date: Mon, 7 May 2018 20:37:07 +0200 -Subject: [PATCH 103/113] disable unprivileged eBPF access by default - ---- - kernel/bpf/syscall.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c -index 9433ab9995cd..348c36273f1a 100644 ---- a/kernel/bpf/syscall.c -+++ b/kernel/bpf/syscall.c -@@ -50,7 +50,7 @@ static DEFINE_SPINLOCK(map_idr_lock); - static DEFINE_IDR(link_idr); - static DEFINE_SPINLOCK(link_idr_lock); - --int sysctl_unprivileged_bpf_disabled __read_mostly; -+int sysctl_unprivileged_bpf_disabled __read_mostly = 1; - - static const struct bpf_map_ops * const bpf_map_types[] = { - #define BPF_PROG_TYPE(_id, _name, prog_ctx_type, kern_ctx_type) --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0104-enable-BPF-JIT-hardening-by-default-if-available.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0104-enable-BPF-JIT-hardening-by-default-if-available.patch deleted file mode 100644 index 926435a4c3f9..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0104-enable-BPF-JIT-hardening-by-default-if-available.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 9bb1000bb74b15393f36de9291b3d930a51cf004 Mon Sep 17 00:00:00 2001 -From: Levente Polyak <levente@leventepolyak.net> -Date: Mon, 7 May 2018 20:37:55 +0200 -Subject: [PATCH 104/113] enable BPF JIT hardening by default (if available) - ---- - kernel/bpf/core.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c -index 55454d2278b1..de02792dc2fc 100644 ---- a/kernel/bpf/core.c -+++ b/kernel/bpf/core.c -@@ -524,7 +524,7 @@ void bpf_prog_kallsyms_del_all(struct bpf_prog *fp) - /* All BPF JIT sysctl knobs here. */ - int bpf_jit_enable __read_mostly = IS_BUILTIN(CONFIG_BPF_JIT_DEFAULT_ON); - int bpf_jit_kallsyms __read_mostly = IS_BUILTIN(CONFIG_BPF_JIT_DEFAULT_ON); --int bpf_jit_harden __read_mostly; -+int bpf_jit_harden __read_mostly = 2; - long bpf_jit_limit __read_mostly; - - static void --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0105-enable-protected_-fifos-regular-by-default.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0105-enable-protected_-fifos-regular-by-default.patch deleted file mode 100644 index d5b253dcabd8..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0105-enable-protected_-fifos-regular-by-default.patch +++ /dev/null @@ -1,27 +0,0 @@ -From fbd4dde75d88472ce6684656b08d571ebe39ec04 Mon Sep 17 00:00:00 2001 -From: Levente Polyak <levente@leventepolyak.net> -Date: Sun, 4 Nov 2018 18:48:53 +0100 -Subject: [PATCH 105/113] enable protected_{fifos,regular} by default - ---- - fs/namei.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/fs/namei.c b/fs/namei.c -index 59ff3ce21026..72f912c68975 100644 ---- a/fs/namei.c -+++ b/fs/namei.c -@@ -934,8 +934,8 @@ static inline void put_link(struct nameidata *nd) - - int sysctl_protected_symlinks __read_mostly = 1; - int sysctl_protected_hardlinks __read_mostly = 1; --int sysctl_protected_fifos __read_mostly; --int sysctl_protected_regular __read_mostly; -+int sysctl_protected_fifos __read_mostly = 2; -+int sysctl_protected_regular __read_mostly = 2; - - /** - * may_follow_link - Check symlink following for unsafe situations --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0106-modpost-Add-CONFIG_DEBUG_WRITABLE_FUNCTION_POINTERS_.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0106-modpost-Add-CONFIG_DEBUG_WRITABLE_FUNCTION_POINTERS_.patch deleted file mode 100644 index b67177ade4f4..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0106-modpost-Add-CONFIG_DEBUG_WRITABLE_FUNCTION_POINTERS_.patch +++ /dev/null @@ -1,129 +0,0 @@ -From ecdfd1bbfb546fbe3fc329f08f13f5b2b758995a Mon Sep 17 00:00:00 2001 -From: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr> -Date: Mon, 6 May 2019 17:07:11 +0200 -Subject: [PATCH 106/113] modpost: Add - CONFIG_DEBUG_WRITABLE_FUNCTION_POINTERS_VERBOSE - -With 46c7dd56d541 ("modpost: always show verbose warning for section -mismatch"), sec_mismatch_verbose was removed which would have printed -errors for all writable function pointers during compilation if it -hadn't been "#if 0"ed out for quite some time now. - -Let's introduce a new DEBUG_WRITABLE_FUNCTION_POINTERS_VERBOSE Kconfig -option to cleanly control this linux-hardened functionality. - -Signed-off-by: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr> -Signed-off-by: Levente Polyak <levente@leventepolyak.net> ---- - lib/Kconfig.debug | 3 +++ - scripts/Makefile.modpost | 1 + - scripts/mod/modpost.c | 25 ++++++++++++++++--------- - 3 files changed, 20 insertions(+), 9 deletions(-) - -diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug -index 4a1a32a059f4..5fce84adc315 100644 ---- a/lib/Kconfig.debug -+++ b/lib/Kconfig.debug -@@ -374,6 +374,9 @@ config DEBUG_FORCE_FUNCTION_ALIGN_32B - - It is mainly for debug and performance tuning use. - -+config DEBUG_WRITABLE_FUNCTION_POINTERS_VERBOSE -+ bool "Enable verbose reporting of writable function pointers" -+ - # - # Select this config option from the architecture Kconfig, if it - # is preferred to always offer frame pointers as a config -diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost -index f54b6ac37ac2..e53b3057d4cb 100644 ---- a/scripts/Makefile.modpost -+++ b/scripts/Makefile.modpost -@@ -47,6 +47,7 @@ MODPOST = scripts/mod/modpost \ - $(if $(CONFIG_MODVERSIONS),-m) \ - $(if $(CONFIG_MODULE_SRCVERSION_ALL),-a) \ - $(if $(CONFIG_SECTION_MISMATCH_WARN_ONLY),,-E) \ -+ $(if $(CONFIG_DEBUG_WRITABLE_FUNCTION_POINTERS_VERBOSE),-f) \ - $(if $(KBUILD_MODPOST_WARN),-w) \ - -o $@ - -diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c -index 50e9baefc4e7..2cbc4e8a6295 100644 ---- a/scripts/mod/modpost.c -+++ b/scripts/mod/modpost.c -@@ -34,8 +34,9 @@ static int external_module = 0; - static int warn_unresolved = 0; - /* How a symbol is exported */ - static int sec_mismatch_count = 0; --static int writable_fptr_count = 0; - static int sec_mismatch_fatal = 0; -+static int writable_fptr_count = 0; -+static int writable_fptr_verbose = 0; - /* ignore missing files */ - static int ignore_missing_files; - /* If set to 1, only warn (instead of error) about missing ns imports */ -@@ -1466,10 +1467,13 @@ static void report_sec_mismatch(const char *modname, - char *prl_from; - char *prl_to; - -- if (mismatch->mismatch == DATA_TO_TEXT) -+ if (mismatch->mismatch == DATA_TO_TEXT) { - writable_fptr_count++; -- else -+ if (!writable_fptr_verbose) -+ return; -+ } else { - sec_mismatch_count++; -+ } - - get_pretty_name(from_is_func, &from, &from_p); - get_pretty_name(to_is_func, &to, &to_p); -@@ -1592,12 +1596,10 @@ static void report_sec_mismatch(const char *modname, - "we should never get here."); - break; - case DATA_TO_TEXT: --#if 0 - fprintf(stderr, - "The %s %s:%s references\n" - "the %s %s:%s%s\n", - from, fromsec, fromsym, to, tosec, tosym, to_p); --#endif - break; - } - fprintf(stderr, "\n"); -@@ -2578,7 +2580,7 @@ int main(int argc, char **argv) - struct dump_list *dump_read_start = NULL; - struct dump_list **dump_read_iter = &dump_read_start; - -- while ((opt = getopt(argc, argv, "ei:mnT:o:awENd:")) != -1) { -+ while ((opt = getopt(argc, argv, "ei:fmnT:o:awENd:")) != -1) { - switch (opt) { - case 'e': - external_module = 1; -@@ -2589,6 +2591,9 @@ int main(int argc, char **argv) - (*dump_read_iter)->file = optarg; - dump_read_iter = &(*dump_read_iter)->next; - break; -+ case 'f': -+ writable_fptr_verbose = 1; -+ break; - case 'm': - modversions = 1; - break; -@@ -2689,9 +2694,11 @@ int main(int argc, char **argv) - } - - free(buf.p); -- if (writable_fptr_count) -- warn("modpost: Found %d writable function pointer(s).\n", -- writable_fptr_count); -+ if (writable_fptr_count && !writable_fptr_verbose) -+ warn("modpost: Found %d writable function pointer%s.\n" -+ "To see full details build your kernel with:\n" -+ "'make CONFIG_DEBUG_WRITABLE_FUNCTION_POINTERS_VERBOSE=y'\n", -+ writable_fptr_count, (writable_fptr_count == 1 ? "" : "s")); - - return err; - } --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0107-mm-Fix-extra_latent_entropy.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0107-mm-Fix-extra_latent_entropy.patch deleted file mode 100644 index fa0be65319bb..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0107-mm-Fix-extra_latent_entropy.patch +++ /dev/null @@ -1,103 +0,0 @@ -From 1bba3073f24209ab48e1e9ea0721da8860a7a714 Mon Sep 17 00:00:00 2001 -From: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr> -Date: Tue, 7 May 2019 11:46:21 +0200 -Subject: [PATCH 107/113] mm: Fix extra_latent_entropy - -Commit a9cd410a3d29 ("mm/page_alloc.c: memory hotplug: free pages as -higher order") changed `static void __init __free_pages_boot_core()` -into `void __free_pages_core()`, causing the following section mismatch -warning at compile time: - - WARNING: vmlinux.o(.text+0x180fe4): Section mismatch in reference from the function __free_pages_core() to the variable .meminit.data:extra_latent_entropy - The function __free_pages_core() references the variable __meminitdata extra_latent_entropy. - This is often because __free_pages_core lacks a __meminitdata annotation or the annotation of extra_latent_entropy is wrong. - -This commit is an attempt at fixing this issue. I'm not sure it's OK as -we are accessing pages that are still managed by the bootmem allocator. -The prefetching part is not an issue as it only affects struct pages. - -Signed-off-by: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr> ---- - mm/page_alloc.c | 38 ++++++++++++++++++++++---------------- - 1 file changed, 22 insertions(+), 16 deletions(-) - -diff --git a/mm/page_alloc.c b/mm/page_alloc.c -index 965d49be78ed..cb7501769331 100644 ---- a/mm/page_alloc.c -+++ b/mm/page_alloc.c -@@ -1539,6 +1539,25 @@ static void __free_pages_ok(struct page *page, unsigned int order, - local_irq_restore(flags); - } - -+static void __init __gather_extra_latent_entropy(struct page *page, -+ unsigned int nr_pages) -+{ -+ if (extra_latent_entropy && !PageHighMem(page) && page_to_pfn(page) < 0x100000) { -+ unsigned long hash = 0; -+ size_t index, end = PAGE_SIZE * nr_pages / sizeof hash; -+ const unsigned long *data = lowmem_page_address(page); -+ -+ for (index = 0; index < end; index++) -+ hash ^= hash + data[index]; -+#ifdef CONFIG_GCC_PLUGIN_LATENT_ENTROPY -+ latent_entropy ^= hash; -+ add_device_randomness((const void *)&latent_entropy, sizeof(latent_entropy)); -+#else -+ add_device_randomness((const void *)&hash, sizeof(hash)); -+#endif -+ } -+} -+ - void __free_pages_core(struct page *page, unsigned int order) - { - unsigned int nr_pages = 1 << order; -@@ -1558,22 +1577,6 @@ void __free_pages_core(struct page *page, unsigned int order) - } - __ClearPageReserved(p); - set_page_count(p, 0); -- -- if (extra_latent_entropy && !PageHighMem(page) && page_to_pfn(page) < 0x100000) { -- unsigned long hash = 0; -- size_t index, end = PAGE_SIZE * nr_pages / sizeof hash; -- const unsigned long *data = lowmem_page_address(page); -- -- for (index = 0; index < end; index++) -- hash ^= hash + data[index]; --#ifdef CONFIG_GCC_PLUGIN_LATENT_ENTROPY -- latent_entropy ^= hash; -- add_device_randomness((const void *)&latent_entropy, sizeof(latent_entropy)); --#else -- add_device_randomness((const void *)&hash, sizeof(hash)); --#endif -- } -- - atomic_long_add(nr_pages, &page_zone(page)->managed_pages); - - /* -@@ -1632,6 +1635,7 @@ void __init memblock_free_pages(struct page *page, unsigned long pfn, - { - if (early_page_uninitialised(pfn)) - return; -+ __gather_extra_latent_entropy(page, 1 << order); - __free_pages_core(page, order); - } - -@@ -1723,6 +1727,7 @@ static void __init deferred_free_range(unsigned long pfn, - if (nr_pages == pageblock_nr_pages && - (pfn & (pageblock_nr_pages - 1)) == 0) { - set_pageblock_migratetype(page, MIGRATE_MOVABLE); -+ __gather_extra_latent_entropy(page, 1 << pageblock_order); - __free_pages_core(page, pageblock_order); - return; - } -@@ -1730,6 +1735,7 @@ static void __init deferred_free_range(unsigned long pfn, - for (i = 0; i < nr_pages; i++, page++, pfn++) { - if ((pfn & (pageblock_nr_pages - 1)) == 0) - set_pageblock_migratetype(page, MIGRATE_MOVABLE); -+ __gather_extra_latent_entropy(page, 1); - __free_pages_core(page, 0); - } - } --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0108-add-CONFIG-for-unprivileged_userfaultfd.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0108-add-CONFIG-for-unprivileged_userfaultfd.patch deleted file mode 100644 index 24faee727e29..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0108-add-CONFIG-for-unprivileged_userfaultfd.patch +++ /dev/null @@ -1,68 +0,0 @@ -From 6703e6f3a33b514c317309e399ef121dcbf77720 Mon Sep 17 00:00:00 2001 -From: Levente Polyak <levente@leventepolyak.net> -Date: Wed, 2 Oct 2019 01:22:17 +0200 -Subject: [PATCH 108/113] add CONFIG for unprivileged_userfaultfd - -When disabled, unprivileged users will not be able to use the userfaultfd -syscall. Userfaultfd provide attackers with a way to stall a kernel -thread in the middle of memory accesses from userspace by initiating an -access on an unmapped page. To avoid various heap grooming and heap -spraying techniques for exploiting use-after-free flaws this should be -disabled by default. - -This setting can be overridden at runtime via the -vm.unprivileged_userfaultfd sysctl. - -Signed-off-by: Levente Polyak <levente@leventepolyak.net> ---- - fs/userfaultfd.c | 4 ++++ - init/Kconfig | 17 +++++++++++++++++ - 2 files changed, 21 insertions(+) - -diff --git a/fs/userfaultfd.c b/fs/userfaultfd.c -index 000b457ad087..06d35ecdcbc8 100644 ---- a/fs/userfaultfd.c -+++ b/fs/userfaultfd.c -@@ -28,7 +28,11 @@ - #include <linux/security.h> - #include <linux/hugetlb.h> - -+#ifdef CONFIG_USERFAULTFD_UNPRIVILEGED - int sysctl_unprivileged_userfaultfd __read_mostly = 1; -+#else -+int sysctl_unprivileged_userfaultfd __read_mostly; -+#endif - - static struct kmem_cache *userfaultfd_ctx_cachep __read_mostly; - -diff --git a/init/Kconfig b/init/Kconfig -index a7b5a4cb7939..2feea719cc25 100644 ---- a/init/Kconfig -+++ b/init/Kconfig -@@ -1745,6 +1745,23 @@ config USERFAULTFD - Enable the userfaultfd() system call that allows to intercept and - handle page faults in userland. - -+config USERFAULTFD_UNPRIVILEGED -+ bool "Allow unprivileged users to use the userfaultfd syscall" -+ depends on USERFAULTFD -+ default n -+ help -+ When disabled, unprivileged users will not be able to use the userfaultfd -+ syscall. Userfaultfd provide attackers with a way to stall a kernel -+ thread in the middle of memory accesses from userspace by initiating an -+ access on an unmapped page. To avoid various heap grooming and heap -+ spraying techniques for exploiting use-after-free flaws this should be -+ disabled by default. -+ -+ This setting can be overridden at runtime via the -+ vm.unprivileged_userfaultfd sysctl. -+ -+ If unsure, say N. -+ - config ARCH_HAS_MEMBARRIER_CALLBACKS - bool - --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0109-slub-Extend-init_on_alloc-to-slab-caches-with-constr.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0109-slub-Extend-init_on_alloc-to-slab-caches-with-constr.patch deleted file mode 100644 index 51e144c1d45a..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0109-slub-Extend-init_on_alloc-to-slab-caches-with-constr.patch +++ /dev/null @@ -1,81 +0,0 @@ -From 97f8e6d6060fdced726b7f7f344e78be66129cdf Mon Sep 17 00:00:00 2001 -From: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr> -Date: Fri, 29 Nov 2019 16:27:14 +0100 -Subject: [PATCH 109/113] slub: Extend init_on_alloc to slab caches with - constructors - -Signed-off-by: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr> -Signed-off-by: Levente Polyak <levente@leventepolyak.net> ---- - mm/slab.h | 2 ++ - mm/slub.c | 23 ++++++++++++++++++----- - 2 files changed, 20 insertions(+), 5 deletions(-) - -diff --git a/mm/slab.h b/mm/slab.h -index 105dba485a7e..2138deacf719 100644 ---- a/mm/slab.h -+++ b/mm/slab.h -@@ -630,8 +630,10 @@ static inline void cache_random_seq_destroy(struct kmem_cache *cachep) { } - static inline bool slab_want_init_on_alloc(gfp_t flags, struct kmem_cache *c) - { - if (static_branch_unlikely(&init_on_alloc)) { -+#ifndef CONFIG_SLUB - if (c->ctor) - return false; -+#endif - if (c->flags & (SLAB_TYPESAFE_BY_RCU | SLAB_POISON)) - return flags & __GFP_ZERO; - return true; -diff --git a/mm/slub.c b/mm/slub.c -index dd68308c94a9..802f9051bc1a 100644 ---- a/mm/slub.c -+++ b/mm/slub.c -@@ -1635,9 +1635,10 @@ static inline bool slab_free_freelist_hook(struct kmem_cache *s, - * need to show a valid freepointer to check_object(). - * - * Note that doing this for all caches (not just ctor -- * ones, which have s->offset != NULL)) causes a GPF, -- * due to KASAN poisoning and the way set_freepointer() -- * eventually dereferences the freepointer. -+ * ones, which have s->offset >= object_size)) causes a -+ * GPF, due to KASAN poisoning and the way -+ * set_freepointer() eventually dereferences the -+ * freepointer. - */ - set_freepointer(s, object, NULL); - } -@@ -2955,8 +2956,14 @@ static __always_inline void *slab_alloc_node(struct kmem_cache *s, - if (s->ctor) - s->ctor(object); - kasan_poison_object_data(s, object); -- } else if (unlikely(slab_want_init_on_alloc(gfpflags, s)) && object) -+ } else if (unlikely(slab_want_init_on_alloc(gfpflags, s)) && object) { - memset(object, 0, s->object_size); -+ if (s->ctor) { -+ kasan_unpoison_object_data(s, object); -+ s->ctor(object); -+ kasan_poison_object_data(s, object); -+ } -+ } - - if (object) { - check_canary(s, object, s->random_inactive); -@@ -3416,8 +3423,14 @@ int kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size, - } else if (unlikely(slab_want_init_on_alloc(flags, s))) { - int j; - -- for (j = 0; j < i; j++) -+ for (j = 0; j < i; j++) { - memset(p[j], 0, s->object_size); -+ if (s->ctor) { -+ kasan_unpoison_object_data(s, p[j]); -+ s->ctor(p[j]); -+ kasan_poison_object_data(s, p[j]); -+ } -+ } - } - - for (k = 0; k < i; k++) { --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0110-net-tcp-add-option-to-disable-TCP-simultaneous-conne.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0110-net-tcp-add-option-to-disable-TCP-simultaneous-conne.patch deleted file mode 100644 index 8be926e38809..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0110-net-tcp-add-option-to-disable-TCP-simultaneous-conne.patch +++ /dev/null @@ -1,151 +0,0 @@ -From de77132795adf97420e9b14c463d7cb2c188fd43 Mon Sep 17 00:00:00 2001 -From: madaidan <50278627+madaidan@users.noreply.github.com> -Date: Sun, 9 Feb 2020 00:03:41 +0000 -Subject: [PATCH 110/113] net: tcp: add option to disable TCP simultaneous - connect - -This is modified from Brad Spengler/PaX Team's code in the last public -patch of grsecurity/PaX based on my understanding of the code. Changes -or omissions from the original code are mine and don't reflect the -original grsecurity/PaX code. - -TCP simultaneous connect adds a weakness in Linux's implementation of -TCP that allows two clients to connect to each other without either -entering a listening state. The weakness allows an attacker to easily -prevent a client from connecting to a known server provided the source -port for the connection is guessed correctly. - -As the weakness could be used to prevent an antivirus or IPS from -fetching updates, or prevent an SSL gateway from fetching a CRL, it -should be eliminated. - -This creates a net.ipv4.tcp_simult_connect sysctl that when disabled, -disables TCP simultaneous connect. - -Reviewd-by: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr> -Reviewd-by: Levente Polyak <levente@leventepolyak.net> -Signed-off-by: Levente Polyak <levente@leventepolyak.net> ---- - Documentation/networking/ip-sysctl.rst | 18 ++++++++++++++++++ - include/net/tcp.h | 1 + - net/ipv4/Kconfig | 23 +++++++++++++++++++++++ - net/ipv4/sysctl_net_ipv4.c | 9 +++++++++ - net/ipv4/tcp_input.c | 3 ++- - 5 files changed, 53 insertions(+), 1 deletion(-) - -diff --git a/Documentation/networking/ip-sysctl.rst b/Documentation/networking/ip-sysctl.rst -index 25e6673a085a..76f1892d65ed 100644 ---- a/Documentation/networking/ip-sysctl.rst -+++ b/Documentation/networking/ip-sysctl.rst -@@ -665,6 +665,24 @@ tcp_comp_sack_nr - INTEGER - - Default : 44 - -+tcp_simult_connect - BOOLEAN -+ Enable TCP simultaneous connect that adds a weakness in Linux's strict -+ implementation of TCP that allows two clients to connect to each other -+ without either entering a listening state. The weakness allows an attacker -+ to easily prevent a client from connecting to a known server provided the -+ source port for the connection is guessed correctly. -+ -+ As the weakness could be used to prevent an antivirus or IPS from fetching -+ updates, or prevent an SSL gateway from fetching a CRL, it should be -+ eliminated by disabling this option. Though Linux is one of few operating -+ systems supporting simultaneous connect, it has no legitimate use in -+ practice and is rarely supported by firewalls. -+ -+ Disabling this may break TCP STUNT which is used by some applications for -+ NAT traversal. -+ -+ Default: Value of CONFIG_TCP_SIMULT_CONNECT_DEFAULT_ON -+ - tcp_slow_start_after_idle - BOOLEAN - If set, provide RFC2861 behavior and time out the congestion - window after an idle period. An idle period is defined at -diff --git a/include/net/tcp.h b/include/net/tcp.h -index d4ef5bf94168..34d0d5438108 100644 ---- a/include/net/tcp.h -+++ b/include/net/tcp.h -@@ -245,6 +245,7 @@ void tcp_time_wait(struct sock *sk, int state, int timeo); - /* sysctl variables for tcp */ - extern int sysctl_tcp_max_orphans; - extern long sysctl_tcp_mem[3]; -+extern int sysctl_tcp_simult_connect; - - #define TCP_RACK_LOSS_DETECTION 0x1 /* Use RACK to detect losses */ - #define TCP_RACK_STATIC_REO_WND 0x2 /* Use static RACK reo wnd */ -diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig -index 989e005bf698..d1584b4b39f9 100644 ---- a/net/ipv4/Kconfig -+++ b/net/ipv4/Kconfig -@@ -743,3 +743,26 @@ config TCP_MD5SIG - on the Internet. - - If unsure, say N. -+ -+config TCP_SIMULT_CONNECT_DEFAULT_ON -+ bool "Enable TCP simultaneous connect" -+ help -+ Enable TCP simultaneous connect that adds a weakness in Linux's strict -+ implementation of TCP that allows two clients to connect to each other -+ without either entering a listening state. The weakness allows an -+ attacker to easily prevent a client from connecting to a known server -+ provided the source port for the connection is guessed correctly. -+ -+ As the weakness could be used to prevent an antivirus or IPS from -+ fetching updates, or prevent an SSL gateway from fetching a CRL, it -+ should be eliminated by disabling this option. Though Linux is one of -+ few operating systems supporting simultaneous connect, it has no -+ legitimate use in practice and is rarely supported by firewalls. -+ -+ Disabling this may break TCP STUNT which is used by some applications -+ for NAT traversal. -+ -+ This setting can be overridden at runtime via the -+ net.ipv4.tcp_simult_connect sysctl. -+ -+ If unsure, say N. -diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c -index 3e5f4f2e705e..791329c77dea 100644 ---- a/net/ipv4/sysctl_net_ipv4.c -+++ b/net/ipv4/sysctl_net_ipv4.c -@@ -588,6 +588,15 @@ static struct ctl_table ipv4_table[] = { - .mode = 0644, - .proc_handler = proc_do_static_key, - }, -+ { -+ .procname = "tcp_simult_connect", -+ .data = &sysctl_tcp_simult_connect, -+ .maxlen = sizeof(int), -+ .mode = 0644, -+ .proc_handler = proc_dointvec_minmax, -+ .extra1 = SYSCTL_ZERO, -+ .extra2 = SYSCTL_ONE, -+ }, - { } - }; - -diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c -index 6bf066f924c1..e57673f42c6f 100644 ---- a/net/ipv4/tcp_input.c -+++ b/net/ipv4/tcp_input.c -@@ -82,6 +82,7 @@ - #include <net/mptcp.h> - - int sysctl_tcp_max_orphans __read_mostly = NR_FILE; -+int sysctl_tcp_simult_connect __read_mostly = IS_ENABLED(CONFIG_TCP_SIMULT_CONNECT_DEFAULT_ON); - - #define FLAG_DATA 0x01 /* Incoming frame contained data. */ - #define FLAG_WIN_UPDATE 0x02 /* Incoming ACK was a window update. */ -@@ -6195,7 +6196,7 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, - tcp_paws_reject(&tp->rx_opt, 0)) - goto discard_and_undo; - -- if (th->syn) { -+ if (th->syn && sysctl_tcp_simult_connect) { - /* We see SYN without ACK. It is attempt of - * simultaneous connect with crossed SYNs. - * Particularly, it can be connect to self. --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0111-dccp-ccid-move-timers-to-struct-dccp_sock.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0111-dccp-ccid-move-timers-to-struct-dccp_sock.patch deleted file mode 100644 index 27b8312f70f9..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0111-dccp-ccid-move-timers-to-struct-dccp_sock.patch +++ /dev/null @@ -1,238 +0,0 @@ -From 70b68f8b02f0b7cba8336108c3726486bedf1a82 Mon Sep 17 00:00:00 2001 -From: Thadeu Lima de Souza Cascardo <cascardo@canonical.com> -Date: Tue, 13 Oct 2020 19:18:48 +0200 -Subject: [PATCH 111/113] dccp: ccid: move timers to struct dccp_sock - -When dccps_hc_tx_ccid is freed, ccid timers may still trigger. The reason -del_timer_sync can't be used is because this relies on keeping a reference -to struct sock. But as we keep a pointer to dccps_hc_tx_ccid and free that -during disconnect, the timer should really belong to struct dccp_sock. - -This addresses CVE-2020-16119. - -Fixes: 839a6094140a (net: dccp: Convert timers to use timer_setup()) -Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@canonical.com> -Signed-off-by: Kleber Sacilotto de Souza <kleber.souza@canonical.com> ---- - include/linux/dccp.h | 2 ++ - net/dccp/ccids/ccid2.c | 32 +++++++++++++++++++------------- - net/dccp/ccids/ccid3.c | 30 ++++++++++++++++++++---------- - 3 files changed, 41 insertions(+), 23 deletions(-) - -diff --git a/include/linux/dccp.h b/include/linux/dccp.h -index 07e547c02fd8..504afa1a4be6 100644 ---- a/include/linux/dccp.h -+++ b/include/linux/dccp.h -@@ -259,6 +259,7 @@ struct dccp_ackvec; - * @dccps_sync_scheduled - flag which signals "send out-of-band message soon" - * @dccps_xmitlet - tasklet scheduled by the TX CCID to dequeue data packets - * @dccps_xmit_timer - used by the TX CCID to delay sending (rate-based pacing) -+ * @dccps_ccid_timer - used by the CCIDs - * @dccps_syn_rtt - RTT sample from Request/Response exchange (in usecs) - */ - struct dccp_sock { -@@ -303,6 +304,7 @@ struct dccp_sock { - __u8 dccps_sync_scheduled:1; - struct tasklet_struct dccps_xmitlet; - struct timer_list dccps_xmit_timer; -+ struct timer_list dccps_ccid_timer; - }; - - static inline struct dccp_sock *dccp_sk(const struct sock *sk) -diff --git a/net/dccp/ccids/ccid2.c b/net/dccp/ccids/ccid2.c -index 3da1f77bd039..dbca1f1e2449 100644 ---- a/net/dccp/ccids/ccid2.c -+++ b/net/dccp/ccids/ccid2.c -@@ -126,21 +126,26 @@ static void dccp_tasklet_schedule(struct sock *sk) - - static void ccid2_hc_tx_rto_expire(struct timer_list *t) - { -- struct ccid2_hc_tx_sock *hc = from_timer(hc, t, tx_rtotimer); -- struct sock *sk = hc->sk; -- const bool sender_was_blocked = ccid2_cwnd_network_limited(hc); -+ struct dccp_sock *dp = from_timer(dp, t, dccps_ccid_timer); -+ struct sock *sk = (struct sock *)dp; -+ struct ccid2_hc_tx_sock *hc; -+ bool sender_was_blocked; - - bh_lock_sock(sk); -+ -+ if (inet_sk_state_load(sk) == DCCP_CLOSED) -+ goto out; -+ -+ hc = ccid_priv(dp->dccps_hc_tx_ccid); -+ sender_was_blocked = ccid2_cwnd_network_limited(hc); -+ - if (sock_owned_by_user(sk)) { -- sk_reset_timer(sk, &hc->tx_rtotimer, jiffies + HZ / 5); -+ sk_reset_timer(sk, &dp->dccps_ccid_timer, jiffies + HZ / 5); - goto out; - } - - ccid2_pr_debug("RTO_EXPIRE\n"); - -- if (sk->sk_state == DCCP_CLOSED) -- goto out; -- - /* back-off timer */ - hc->tx_rto <<= 1; - if (hc->tx_rto > DCCP_RTO_MAX) -@@ -166,7 +171,7 @@ static void ccid2_hc_tx_rto_expire(struct timer_list *t) - if (sender_was_blocked) - dccp_tasklet_schedule(sk); - /* restart backed-off timer */ -- sk_reset_timer(sk, &hc->tx_rtotimer, jiffies + hc->tx_rto); -+ sk_reset_timer(sk, &dp->dccps_ccid_timer, jiffies + hc->tx_rto); - out: - bh_unlock_sock(sk); - sock_put(sk); -@@ -330,7 +335,7 @@ static void ccid2_hc_tx_packet_sent(struct sock *sk, unsigned int len) - } - #endif - -- sk_reset_timer(sk, &hc->tx_rtotimer, jiffies + hc->tx_rto); -+ sk_reset_timer(sk, &dp->dccps_ccid_timer, jiffies + hc->tx_rto); - - #ifdef CONFIG_IP_DCCP_CCID2_DEBUG - do { -@@ -700,9 +705,9 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) - - /* restart RTO timer if not all outstanding data has been acked */ - if (hc->tx_pipe == 0) -- sk_stop_timer(sk, &hc->tx_rtotimer); -+ sk_stop_timer(sk, &dp->dccps_ccid_timer); - else -- sk_reset_timer(sk, &hc->tx_rtotimer, jiffies + hc->tx_rto); -+ sk_reset_timer(sk, &dp->dccps_ccid_timer, jiffies + hc->tx_rto); - done: - /* check if incoming Acks allow pending packets to be sent */ - if (sender_was_blocked && !ccid2_cwnd_network_limited(hc)) -@@ -737,17 +742,18 @@ static int ccid2_hc_tx_init(struct ccid *ccid, struct sock *sk) - hc->tx_last_cong = hc->tx_lsndtime = hc->tx_cwnd_stamp = ccid2_jiffies32; - hc->tx_cwnd_used = 0; - hc->sk = sk; -- timer_setup(&hc->tx_rtotimer, ccid2_hc_tx_rto_expire, 0); -+ timer_setup(&dp->dccps_ccid_timer, ccid2_hc_tx_rto_expire, 0); - INIT_LIST_HEAD(&hc->tx_av_chunks); - return 0; - } - - static void ccid2_hc_tx_exit(struct sock *sk) - { -+ struct dccp_sock *dp = dccp_sk(sk); - struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk); - int i; - -- sk_stop_timer(sk, &hc->tx_rtotimer); -+ sk_stop_timer(sk, &dp->dccps_ccid_timer); - - for (i = 0; i < hc->tx_seqbufc; i++) - kfree(hc->tx_seqbuf[i]); -diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c -index b9ee1a4a8955..685f4d046c0d 100644 ---- a/net/dccp/ccids/ccid3.c -+++ b/net/dccp/ccids/ccid3.c -@@ -184,17 +184,24 @@ static inline void ccid3_hc_tx_update_win_count(struct ccid3_hc_tx_sock *hc, - - static void ccid3_hc_tx_no_feedback_timer(struct timer_list *t) - { -- struct ccid3_hc_tx_sock *hc = from_timer(hc, t, tx_no_feedback_timer); -- struct sock *sk = hc->sk; -+ struct dccp_sock *dp = from_timer(dp, t, dccps_ccid_timer); -+ struct ccid3_hc_tx_sock *hc; -+ struct sock *sk = (struct sock *)dp; - unsigned long t_nfb = USEC_PER_SEC / 5; - - bh_lock_sock(sk); -+ -+ if (inet_sk_state_load(sk) == DCCP_CLOSED) -+ goto out; -+ - if (sock_owned_by_user(sk)) { - /* Try again later. */ - /* XXX: set some sensible MIB */ - goto restart_timer; - } - -+ hc = ccid_priv(dp->dccps_hc_tx_ccid); -+ - ccid3_pr_debug("%s(%p, state=%s) - entry\n", dccp_role(sk), sk, - ccid3_tx_state_name(hc->tx_state)); - -@@ -250,8 +257,8 @@ static void ccid3_hc_tx_no_feedback_timer(struct timer_list *t) - t_nfb = max(hc->tx_t_rto, 2 * hc->tx_t_ipi); - - restart_timer: -- sk_reset_timer(sk, &hc->tx_no_feedback_timer, -- jiffies + usecs_to_jiffies(t_nfb)); -+ sk_reset_timer(sk, &dp->dccps_ccid_timer, -+ jiffies + usecs_to_jiffies(t_nfb)); - out: - bh_unlock_sock(sk); - sock_put(sk); -@@ -280,7 +287,7 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb) - return -EBADMSG; - - if (hc->tx_state == TFRC_SSTATE_NO_SENT) { -- sk_reset_timer(sk, &hc->tx_no_feedback_timer, (jiffies + -+ sk_reset_timer(sk, &dp->dccps_ccid_timer, (jiffies + - usecs_to_jiffies(TFRC_INITIAL_TIMEOUT))); - hc->tx_last_win_count = 0; - hc->tx_t_last_win_count = now; -@@ -354,6 +361,7 @@ static void ccid3_hc_tx_packet_sent(struct sock *sk, unsigned int len) - static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) - { - struct ccid3_hc_tx_sock *hc = ccid3_hc_tx_sk(sk); -+ struct dccp_sock *dp = dccp_sk(sk); - struct tfrc_tx_hist_entry *acked; - ktime_t now; - unsigned long t_nfb; -@@ -420,7 +428,7 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) - (unsigned int)(hc->tx_x >> 6)); - - /* unschedule no feedback timer */ -- sk_stop_timer(sk, &hc->tx_no_feedback_timer); -+ sk_stop_timer(sk, &dp->dccps_ccid_timer); - - /* - * As we have calculated new ipi, delta, t_nom it is possible -@@ -445,8 +453,8 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) - "expire in %lu jiffies (%luus)\n", - dccp_role(sk), sk, usecs_to_jiffies(t_nfb), t_nfb); - -- sk_reset_timer(sk, &hc->tx_no_feedback_timer, -- jiffies + usecs_to_jiffies(t_nfb)); -+ sk_reset_timer(sk, &dp->dccps_ccid_timer, -+ jiffies + usecs_to_jiffies(t_nfb)); - } - - static int ccid3_hc_tx_parse_options(struct sock *sk, u8 packet_type, -@@ -488,21 +496,23 @@ static int ccid3_hc_tx_parse_options(struct sock *sk, u8 packet_type, - - static int ccid3_hc_tx_init(struct ccid *ccid, struct sock *sk) - { -+ struct dccp_sock *dp = dccp_sk(sk); - struct ccid3_hc_tx_sock *hc = ccid_priv(ccid); - - hc->tx_state = TFRC_SSTATE_NO_SENT; - hc->tx_hist = NULL; - hc->sk = sk; -- timer_setup(&hc->tx_no_feedback_timer, -+ timer_setup(&dp->dccps_ccid_timer, - ccid3_hc_tx_no_feedback_timer, 0); - return 0; - } - - static void ccid3_hc_tx_exit(struct sock *sk) - { -+ struct dccp_sock *dp = dccp_sk(sk); - struct ccid3_hc_tx_sock *hc = ccid3_hc_tx_sk(sk); - -- sk_stop_timer(sk, &hc->tx_no_feedback_timer); -+ sk_stop_timer(sk, &dp->dccps_ccid_timer); - tfrc_tx_hist_purge(&hc->tx_hist); - } - --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0112-Revert-dccp-don-t-free-ccid2_hc_tx_sock-struct-in-dc.patch b/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0112-Revert-dccp-don-t-free-ccid2_hc_tx_sock-struct-in-dc.patch deleted file mode 100644 index 67708033d230..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.13/hardened-patches/0112-Revert-dccp-don-t-free-ccid2_hc_tx_sock-struct-in-dc.patch +++ /dev/null @@ -1,40 +0,0 @@ -From a1369990ca622db871f12a9a6fc27f89f36ef1aa Mon Sep 17 00:00:00 2001 -From: Thadeu Lima de Souza Cascardo <cascardo@canonical.com> -Date: Tue, 13 Oct 2020 19:18:49 +0200 -Subject: [PATCH 112/113] Revert "dccp: don't free ccid2_hc_tx_sock struct in - dccp_disconnect()" - -This reverts commit 2677d20677314101293e6da0094ede7b5526d2b1. - -This fixes an issue that after disconnect, dccps_hc_tx_ccid will still be -kept, allowing the socket to be reused as a listener socket, and the cloned -socket will free its dccps_hc_tx_ccid, leading to a later use after free, -when the listener socket is closed. - -This addresses CVE-2020-16119. - -Fixes: 2677d2067731 (dccp: don't free ccid2_hc_tx_sock struct in dccp_disconnect()) -Reported-by: Hadar Manor -Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@canonical.com> -Signed-off-by: Kleber Sacilotto de Souza <kleber.souza@canonical.com> ---- - net/dccp/proto.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/net/dccp/proto.c b/net/dccp/proto.c -index 6d705d90c614..359e848dba6c 100644 ---- a/net/dccp/proto.c -+++ b/net/dccp/proto.c -@@ -279,7 +279,9 @@ int dccp_disconnect(struct sock *sk, int flags) - - dccp_clear_xmit_timers(sk); - ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk); -+ ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk); - dp->dccps_hc_rx_ccid = NULL; -+ dp->dccps_hc_tx_ccid = NULL; - - __skb_queue_purge(&sk->sk_receive_queue); - __skb_queue_purge(&sk->sk_write_queue); --- -2.30.0 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/dtrace-patches/0001-ctf-generate-CTF-information-for-the-kernel.patch b/sys-kernel/cairn-sources/files/5.10.14/dtrace-patches/0001-ctf-generate-CTF-information-for-the-kernel.patch deleted file mode 100644 index 2eda4541a94c..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/dtrace-patches/0001-ctf-generate-CTF-information-for-the-kernel.patch +++ /dev/null @@ -1,7297 +0,0 @@ -From ee291dd05f9c4904f1c5a110d22cf0c3a5580df6 Mon Sep 17 00:00:00 2001 -From: Nick Alcock <nick.alcock@oracle.com> -Date: Wed, 14 Nov 2018 19:42:21 +0000 -Subject: [PATCH 01/19] ctf: generate CTF information for the kernel - -This introduces a new tool, dwarf2ctf, which runs whenever 'make ctf' is -run, extracting information on the kernel's types and global variables -from the DWARF-format debug information in the kernel build tree, -deduplicating it, and emitting it in Sun's Compact Type Format into a -mmappable type archive named vmlinux.ctfa, which is installed at 'make -install' time into /lib/modules/$(uname -r)/kernel/. Out-of-tree -modules cannot participate in this mechanism since the file is already -written: CTF information for such modules is instead linked into such -modules at build time as new sections named .SUNW_ctf (as a result, most -of the build-time machinery for this is in scripts/Makefile.modpost). -Care should be taken not to strip such sections into debug RPMs (they -are small enough that this should not be a problem). - -Within the ctfa file, the type information is divided into a shared -repository, containing all types used by more than one module, CTF for -the core kernel, and separate CTF for each module built, whether or not -this module has been compiled in or not: if a file *could* be built as a -module, it will be considered to be a module from the perspective of CTF -file emission (and kallmodsyms: see the next commit). This ensures that -external consumers such as DTrace always find types for a given module -in the same place, regardless of the local kernel configuration, as long -as that module is present at all, assisting in portability of D scripts -between installations. The ctf_ar tool in libdtrace-ctf can be used to -inspect ctfa files, and the ctf_dump tool can be used to look at the ctf -files they contain. - -This process needs a pair of new files, objects.builtin (which lists all -object files that are unconditionally built into the kernel and cannot -be built as modules) and modules_thick.builtin, which maps from the thin -archives that make up built-in modules to their constituent object -files. Taken together, these files let dwarf2ctf determine whether a -given object file linked into vmlinux.o is part of a module, and if so, -which one. - -There is a single manually-maintained blacklist of structure members -dwarf2ctf cannot handle in scripts/dwarf2ctf/member.blacklist: this is -used to identify structure members which have different definitions in -different object files even though they are defined in the same location -in the same source file, usually due to preprocessor magic. (Currently, -the only item in this list is present for example purposes only, since -the file in question was recently removed from the kernel: dwarf2ctf can -these days identify most members needing blacklisting automatically, and -will fail with an error if it needs more help. It is quite possible that -dwarf2ctf will fail on make allyesconfig kernel configurations and other -extreme cases: I hope to track all such bugs down in time.) - -The documentation for dwarf2ctf is currently somewhat outdated: an -update is planned. It remains largely accurate except for some details -of the deduplication pass. - -This introduces new kernel build-time dependencies on elfutils, zlib, -glib, and the new libdtrace-ctf package (shared with DTrace userspace). -No new runtime dependencies are introduced. - -v5.6: retain the tristate machinery and scripts/Makefile.modbuiltin, - since there appears to be no other way to get modules_thick.builtin - (or anything like it) generated. - -Signed-off-by: Nick Alcock <nick.alcock@oracle.com> -Signed-off-by: Kris Van Hees <kris.van.hees@oracle.com> -Signed-off-by: Tomas Jedlicka <tomas.jedlicka@oracle.com> ---- - .gitignore | 3 + - Documentation/dontdiff | 1 + - Documentation/dwarf2ctf | 1054 ++++++ - Documentation/kbuild/kconfig.rst | 5 + - Documentation/process/changes.rst | 23 +- - Makefile | 72 +- - lib/Kconfig | 12 + - scripts/Kbuild.include | 6 + - scripts/Makefile | 1 + - scripts/Makefile.modbuiltin | 60 + - scripts/Makefile.modfinal | 141 +- - scripts/dwarf2ctf/.gitignore | 1 + - scripts/dwarf2ctf/Makefile | 10 + - scripts/dwarf2ctf/dwarf2ctf.c | 4962 ++++++++++++++++++++++++++++ - scripts/dwarf2ctf/eu_simple.c | 2 + - scripts/dwarf2ctf/member.blacklist | 1 + - scripts/eu_simple.c | 356 ++ - scripts/eu_simple.h | 91 + - scripts/kconfig/confdata.c | 41 +- - scripts/move-if-change | 8 + - scripts/package/mkspec | 12 + - 21 files changed, 6851 insertions(+), 11 deletions(-) - create mode 100644 Documentation/dwarf2ctf - create mode 100644 scripts/Makefile.modbuiltin - create mode 100644 scripts/dwarf2ctf/.gitignore - create mode 100644 scripts/dwarf2ctf/Makefile - create mode 100644 scripts/dwarf2ctf/dwarf2ctf.c - create mode 100644 scripts/dwarf2ctf/eu_simple.c - create mode 100644 scripts/dwarf2ctf/member.blacklist - create mode 100644 scripts/eu_simple.c - create mode 100644 scripts/eu_simple.h - create mode 100755 scripts/move-if-change - -diff --git a/.gitignore b/.gitignore -index d01cda8e11779a2fa3e3333fd176e2e77e02fd21..1c10cd7ce03399a97367d56dbefd66dea1823859 100644 ---- a/.gitignore -+++ b/.gitignore -@@ -48,6 +48,8 @@ - Module.symvers - modules.builtin - modules.order -+modules_thick.builtin -+objects.builtin - - # - # Top-level generic files -@@ -58,6 +60,7 @@ modules.order - /vmlinux - /vmlinux.32 - /vmlinux.symvers -+/vmlinux.ctfa - /vmlinux-gdb.py - /vmlinuz - /System.map -diff --git a/Documentation/dontdiff b/Documentation/dontdiff -index e361fc95ca293d80434ee0cdfae309046c17d612..a763d0fb892edf3e0cfddc1670f52963eaad5a36 100644 ---- a/Documentation/dontdiff -+++ b/Documentation/dontdiff -@@ -181,6 +181,7 @@ modpost - modules.builtin - modules.builtin.modinfo - modules.nsdeps -+modules_thick.builtin - modules.order - modversions.h* - nconf -diff --git a/Documentation/dwarf2ctf b/Documentation/dwarf2ctf -new file mode 100644 -index 0000000000000000000000000000000000000000..5cc445fbd227cbea527b593b2f16775430ee5f52 ---- /dev/null -+++ b/Documentation/dwarf2ctf -@@ -0,0 +1,1054 @@ -+dwarf2ctf, a type encoder for the Linux kernel -+========= -+ -+Many kernel-level debugging and tracing systems need access to the kernel's type -+information. Since C doesn't support any form of introspection, the data must -+be extracted in some other way: here, we extract it from the DWARF debugging -+information generated by the compiler. Unfortunately, this information is very -+voluminous (just the type information alone adds up to a couple of hundred -+megabytes in a 'make allyesconfig' kernel): even if users are happy to spend the -+disk space, the time and memory required to read much of this information in is -+likely to be prohibitive. -+ -+This problem is not new -- back in 2004, Sun had the same problem when -+attempting to give DTrace a view of the type information in the Solaris kernel. -+Their solution was the Compact ANSI-C Type Format (CTF), a highly compacted -+representation of C types suitable for debuggers and tracers. They combined -+this with a highly efficient tool for converting DWARF2 types to CTF, and hacks -+in the Solaris kernel causing the kernel itself to emit CTF data for its own -+types. -+ -+Unfortunately while this tool may be highly efficient it is not adequate for the -+Linux kernel. It treats every ELF object as an independent entity with an -+independent set of types -- perfectly all right for the Solaris kernel with a -+few hundred modules maximum, but very much not for Linux, where distro kernels -+often compile in thousands of modules. Ideally, we would like to treat all -+kernel modules, built-in or not, the same way, sharing and deduplicating all -+globally-visible types across the entire set of visible modules and recording -+each precisely once. -+ -+We also want to collect descriptions of global variables and emit descriptions -+of their name->type mapping as well, since the kernel has no easily accessible -+ELF section we can extract this information from at runtime (kernel modules must -+be accessible at runtime for modern Linux systems to work, but the kernel itself -+could have come from over the network or off a USB key or from a non-mounted -+partition or an EFI boot partition or who knows where, and could have any name -+even if it is accessible: so tracing tools should not rely on being able to look -+inside the kernel image). -+ -+We do all this with dwarf2ctf, a CTF generation tool that reads in DWARF from a -+set of object files (usually, every object file in the kernel and all modules) -+and fills a directory with compressed files containing CTF representations of -+the types in those object files: the kernel build system regenerates these as -+necessary and links them directly into kernel modules. -+ -+Caveats: It is somewhat specific to the form of DWARF output emitted by GCC, and -+doesn't yet support DWARF-4 type signatures or compressed DWARF at all. -+ -+We'll look at each part of this system in turn, from the top down, starting with -+using the kernel type information dwarf2ctf produces in other programs. -+ -+ -+Using dwarf2ctf output -+---------------------- -+ -+Using this data is fairly simple. Once you've read the CTF sections from the -+kernel modules and inflated them (or ignored them if they are empty or, as just -+mentioned, one byte long), you simply need to look at the ctf_parent_name() for -+each module, and if it is set to "ctf", call ctf_import() to set the parent of -+this module to the CTF data you have read from the .ctf.shared_ctf section in -+the ctf.ko kernel module. The core kernel's types are stored in the -+.ctf.vmlinux section in the same kernel module, and all built-in kernel modules -+have their types in .ctf.$module_name. Non-built-in kernel modules just have a -+.ctf section containing their types, which again might need their parent set to -+"shared_ctf". (Out-of-tree kernel modules will have no such parent.) -+ -+Once you've set up the parenthood relationships you can call ctf_close() on the -+shared type repository and forget about it entirely: it will be refcounted and -+destroyed when all its children are closed. -+ -+ -+You should end up with a family of CTF files, one per kernel module built-in or -+not and one for the core kernel, freely usable for whatever purpose you need. -+ -+ -+Invocation and build-system connections -+---------- -+ -+dwarf2ctf's command-line syntax emphasises simplicity over compactness. Linux -+has nearly-infinitely-long command lines these days, so we can take advantage of -+this. -+ -+Two syntaxes are supported. The first shares types across multiple modules and -+the core kernel; the second is used for out-of-tree module building, and avoids -+either sharing anything at all across modules or depending on the set of shared -+types defined for the core kernel. -+ -+ -+dwarf2ctf outputdir objects.builtin modules.builtin dedup.blacklist \ -+ vmlinux.o module.o ... -+dwarf2ctf outputdir -e module.o ... -+ -+where: -+ -+ - 'outputdir' is the possibly-relative path to a directory in which the -+ generated CTF files get placed. -+ - 'objects.builtin' is the name of the file containing the object files that -+ correspond to always-built-in kernel code (that cannot be built as modules). -+ - 'modules.builtin' is the name of the file containing the names of -+ kernel modules presently built in to the kernel. -+ - 'dedup.blacklist' is a blacklist of modules that should never participate -+ in deduplication: see 'Duplicate type detection' below. -+ - the .o filenames are the names of object files comprising the kernel and/or -+ modules: you can feed in whole modules at once (before linking with .mod.o). -+ This list is often very, very long (I have seen command-lines in excess of -+ 60Kb). -+ -+dwarf2ctf's output consists of a series of gzip-compressed .ctf.new files in the -+outputdir, which the makefile compares with and if necessary moves over the top -+of .ctf files with the same basename, so as to avoid relinking things if -+dwarf2ctf has written out content identical to what it wrote last time it ran. -+These fall into several classes, partitioned according to the contents of -+objects.builtin and modules.builtin: -+ -+ - shared_ctf.builtin.ctf: The shared type repository. Types shared by more -+ than one of the files below go here. -+ libdtrace-ctf). See 'Using dwarf2ctf output' below regarding use of this -+ data. -+ - vmlinux.builtin.ctf: Types in the core kernel, that cannot be built in to -+ modules, go here. -+ - *.builtin.ctf: One of these is generated for the types in each module that -+ is presently built in to the kernel. -+ - *.mod.ctf: One of these is generated for each .ko. -+ -+All the files in the first three classes are linked into the ctf.ko module under -+various names, an empty module containing nothing but CTF data. -+ -+ -+A lengthy section of Makefile.modpost, and a short section of the toplevel -+Makefile, is dedicated to creating these files, and to linking them into the -+kernel modules. The dependency graph related to dwarf2ctf output is quite -+complex: modules and objects (ld -r'ed *.o files) are processed by dwarf2ctf to -+produce a number of files in the .ctf directory, and the final modules depend on -+the relevant ctf files. The .mod.ctf's go into the .ko's with the same stem -+name, but ctf.ko receives content from all the CTF files corresponding to -+built-in modules, and until dwarf2ctf runs and creates those files we cannot -+tell what those CTF files will be, though we do have a wildcard that matches -+them all. -+[ -+GNU Make's 'secondary expansion' feature comes to the rescue here: we can -+compute a list of expected CTF filenames at runtime, given the names of the -+modules we are linking in. For the builtin modules, we cheat and touch a stamp -+file after moving any .ctf.new files back over a .ctf file, then depend on that -+to see if ctf.ko needs to be relinked. -+ -+The actual incorporation of the CTF data into the kernel modules happens before -+module signing (if signing is active), by calling objcopy --add-section on the -+module in question. This too has some knotty corners. -+ -+First of all, the module linkage process normally links a module using all the -+prerequisites of the module's target -- but we have designated all the CTF files -+as prerequisites of the module's target, and we don't want to link them directly -+in using ld(1), since they aren't object files. So we have to filter them out in -+the link line. -+ -+Secondly, those modules which have no CTF files should acquire empty CTF -+sections to indicate their lack of unique types -- but objcopy in binutils 2.20 -+and below silently exits if asked to --add-section an empty file. So we use dd -+to generate a file with a one-byte null in it instead, and teach the users of -+CTF sections to treat a one-byte-long 'CTF' section as if it were empty. -+ -+ -+Overview of dwarf2ctf operation -+-------- -+ -+There are four phases to dwarf2ctf operation: initialization, duplicate type -+detection, CTF construction, and writeout. Some of these phases can repeat. -+All but the last phase consists purely of sucking data from object files into -+GHashTables in memory. (The last two phases could potentially be combined, -+shrinking the size of one hash and saving memory, but the hash that is shrunk is -+by no means the largest one, so the extra complexity is probably not worth it.) -+ -+dwarf2ctf uses several other libraries to do this: -+ -+ - elfutils, used for DWARF parsing. We could potentially write our own -+ DWARF parser, but elfutils works and is tested. -+ -+ - glib, used for the GHashTable. The rest of the kernel uses roll-your-own -+ hash tables, but dwarf2ctf makes heavy demands of its hashtables: they must -+ be expanding hashes capable of efficiently storing hundreds of thousands of -+ items, with amortized log(N) lookup time, and they must support deletion -+ (though it need not be particularly efficient deletion). This rules out -+ simple fixed-size bucket hashes like the ones used in other parts of the -+ kernel build system: GHashTable is already implemented, and works. -+ -+ - zlib, used to compress the CTF information. -+ -+ - libdtrace-ctf, which both reads and writes the CTF data. This is a port of -+ the Solaris CTF library, GPLed and with additional support for the storage -+ of name->type mappings (meant to represent variables) akin to its existing -+ ELF symbol->type mappings. -+ -+dwarf2ctf has a good few important data structures, described at the top of -+scripts/dwarf2ctf/dwarf2ctf.c. -+ -+dwarf2ctf has its own trace facility, implemented via the dw_ctf_trace() macro -+and enabled by compiling with -DDEBUG and setting DWARF2CTF_TRACE in the -+environment. (The first step is required because some very numerous data -+structures are greatly expanded when debugging is turned on, which would waste -+memory if it were done all the time). This produces a huge volume of trace -+output, several gigabytes when run over an allyesconfig kernel. -+ -+ -+Unless you're interested in how dwarf2ctf works internally, you can stop reading -+here. If you are interested, now is a good time to read the comments above -+main() in scripts/dwarf2ctf/dwarf2ctf.c, which briefly describe dwarf2ctf's data -+structures and functions. -+ -+ -+Flow of Control -+--------------- -+ -+The /* C comments */ point to other sections of this document, -+ -+Functions named in the /* Utilities */ section of dwarf2ctf.c are not mentioned -+here for simplicity's sake. -+ -+[C]: Callback -+[R]: recursive -+[1]: Numbers: Mutually-recursive loop -+|: Several functions which all call the same functions -+->: Call from array of callbacks (filter_ctf_*() omitted as uninteresting) -+ -+main() -+ /* See 'Initialization' */ -+ init_assembly_tab() -+ init_builtin() -+ init_dedup_blacklist() -+ init_member_blacklist() -+ run() -+ init_tu_to_modules() -+ init_ctf_table() -+ -+ /* Duplicate detection */ -+ -+ scan_duplicates() -+ process_file() /* Toplevel DWARF walkers */ -+[C] detect_duplicates_init() -+[R] process_tu_func() -+[C] assembly_filter_tab[] -+[C] detect_duplicates() -+[ 1] mark_shared() -+[R] type_id() /* Type IDs */ -+[C1] mark_shared() -+[R] mark_seen_contained() -+[C] detect_duplicates_done() -+ -+ process_file() -+[C] detect_duplicates_init() -+[R] process_tu_func() -+[C] assembly_filter_tab[] -+[C] detect_duplicates_alias_fixup() -+[R] type_id() -+[C] is_named_struct_union_enum() -+[R] type_id() -+[C] detect_duplicates_alias_fixup_internal() -+ mark_shared() (see above) -+[C] detect_duplicates_done() -+ -+ /* CTF construction */ -+ -+ process_file() -+[R] process_tu_func() -+[C] assembly_filter_tab[] -+[C] construct_ctf() -+[ 2] construct_ctf_id() -+[R3] die_to_ctf() -+ assembly_tab[] -+[C] -> assemble_ctf_base() -+ -> assemble_ctf_pointer() -+ | assemble_ctf_array() -+ | assemble_ctf_array_dimension() -+ | assemble_ctf_typedef() -+ | assemble_ctf_cvr_qual() -+ | assemble_ctf_variable() -+ lookup_ctf_type() -+[ 2] construct_ctf_id() -+ -> assemble_ctf_enumeration() -+ -> assemble_ctf_enumerator() -+ -> assemble_ctf_struct_union() -+ -> assemble_ctf_su_member() -+[ 3] die_to_ctf() -+[ 2] construct_ctf_id() -+ -+ write_types() -+ -+Initialization -+-------------- -+ -+ init_assembly_tab() -+ init_builtin() -+ init_dedup_blacklist() -+ run() -+ init_tu_to_modules() -+ init_ctf_table() -+ -+This happens at the top of main() and run(), and in various functions named -+init_*(). Of these, init_assembly_tab() and init_builtin() serve only to turn -+various static arrays and files mentioned on the command line into more useful -+internal representations (e.g. the assembly filter array of structures is turned -+into a pair of arrays indexed by DWARF tag), and the blacklisting functions are -+described in the section on duplicate type detection below. -+ -+init_ctf_table(), called both at initialization time and later during CTF -+assembly when new CTF files are found to be needed, creates a new CTF file in -+memory and either marks it as a child of the shared type repository, or (if it -+*is* the shared type repository, or deduplication is off and there is only one -+CTF file being processed and no shared type repository at all) creates a few -+types in it which CTF has representations of but DWARF does not: a void type, -+and a generic catchall pointer-to-function-returning-int. -+ -+That leaves init_tu_to_modules(). This walks over all the top-level -+compile_unit DIEs in the DWARF debugging information in every object file -+mentioned in the list of modules and built-in modules, constructing a mapping -+from translation unit name back to the name of the kernel module it comes from, -+even if that module is built in to the kernel. This is normally the same as the -+filename (sans extension), but for built-in kernel modules, the name comes from -+the modules.builtin file's entry for the translation unit instead, so that the -+output can land in a .builtin.ctf file rather than being jammed into -+vmlinux.builtin.ctf with the core kernel's types. -+ -+This means that dwarf2ctf can operate in terms of the kernel module a type is -+contained within rather than having to think about the mapping between object -+file name, translation unit name and module name all the time. -+ -+ -+Toplevel DWARF walkers -+---------------------- -+ -+ process_file() -+[C] (per-TU initialization callback) -+[R] process_tu_func() -+[C] assembly_filter_tab[] -+[C] (per-DIE callback) -+[C] (per-TU cleanup callback) -+ -+All routines in dwarf2ctf other than initialization and writeout are DWARF -+walkers: i.e., they walk over all DWARF DIEs in all object files specified on -+the command line and do something with every DIE. This job is done by -+process_file() and its helper process_tu_func(), which not only digs out the -+corresponding (built-in or non-built-in) module name corresponding to each -+object file, but also detects and skips translation units it has handled before -+(in case they are incrementally linked into multiple object files) and allows -+callbacks to be invoked at the start and end of each translation unit. -+ -+Even though dwarf2ctf only cares about top-level types, in some situations DWARF -+can emit top-level types with references to a non-top-level type: if all -+occurrences of the top-level type are an opaque structure, and the only -+non-opaque definition is inside a function, references in the same translation -+unit as the non-opaque definition will point to the definition inside the -+function (and references outside the translation unit will not point at any -+definition). Thus, if we want to catch all nuances of globally-visible types, -+we have to scan types inside functions and lexical blocks inside functions too. -+ -+To avoid generating a vast number of unnecessary type definitions, the 'assembly -+table' which describes how to construct a CTF type given a DWARF DIE also -+contains a description of a set of filters which are passed the current DIE and -+its parent: if they return false, the DIE is skipped and never passed to the -+callback function. We also avoid calling the callback for any DWARF DIE whose -+tag doesn't appear in the assembly table at all: there's no point doing -+duplicate detection or anything else for a DWARF DIE we won't be generating CTF -+from. There are currently two filters defined: filter_ctf_file_scope(), which -+is called for every DWARF DIE whose tag is one we never expect to see a -+reference to if it is inside a function (except if they relate to a structure or -+union, as above), and filter_ctf_uninteresting(), which is called for variables -+to see if they are worthy of recording (top-level named variables with external -+linkage not part of the internal workings of macros only). -+ -+ -+Type IDs -+-------- -+ -+[R] type_id() -+[C] (optional per-type callback) -+ -+The only thing dwarf2ctf does which the Sun tool does not is the detection of -+duplicate and shared types, both within individual kernel modules and across -+modules. Our ultimate goal is that a type that appears in the source code once -+appears in the CTF output once as well. This goal has mostly been attained, -+except for out-of-tree modules, where cross-module type sharing must be disabled -+to avoid requiring rebuilds of the module whenever the core kernel is rebuilt. -+ -+The core of this is the concept of a *type ID* and the function type_id() which -+computes it. A type ID is an identifier for a type which precisely represents -+that type and only that type. Doing this for types in different headers or at -+different scopes with the same name without needing to encode knowledge of C -+scoping rules into dwarf2ctf is an interesting proposition: we can use the line -+number and filename info provided by DWARF in most user-specified types to help. -+ -+A type ID is a recursively-constructed string of the following form (fixed -+elements represented by {}, optional elements by []): -+ -+//[filename]//[line number]//{type string} -+ -+Types are *based* upon other types iff they have a DW_AT_type attribute pointing -+to some other type. All types based upon other types have a type ID that is the -+type ID of the type upon which they are based, with additional information -+specific to this type appended to it. The filename and line number is only -+added for those types which are not based upon other types and which have a -+filename and line number in the DWARF (lots don't, e.g. base types): the -+filename is canonicalized with realpath(), though since this is quite slow and -+type_id() is called a lot, the mapping from DWARF filename to realpath() result -+is cached. Types that have no filename or line number start with '////'. -+ -+We use // to separate the filename and line number elements because this is the -+shortest string other than NUL that cannot appear in a canonicalized POSIX -+pathname (ignoring Pyramid, Cygwin and other strange systems that actually -+return // in the result of realpath(): Linux doesn't use it and that's all that -+matters. Should it start to use it, we can switch delimiter to ///.) -+ -+Function pointers are not represented (or, rather, are all mapped to the same -+type ID, the generic catchall function-pointer type mentioned above); array -+dimensions are represented by [index-type dimension], or [] for flexible array -+members. Structure members are not represented, since they are not types, but -+the types of their members *are* represented, as are nested structures (the line -+number and filename serving, as ever, to disambiguate them from other structures -+with the same name declared nested inside different structures). -+ -+The following are some examples of valid type IDs (assuming the kernel source -+tree is, implausibly, located at /k/, just off the root directory: comments on -+individual types done /* like C */; the last example is broken across lines for -+formatting's sake): -+ -+//fp//* # a pointer to a function, any function -+////long int -+////char [] -+////unsigned int typedef __kernel_uid_t typedef __kernel_uid32_t -+//fp//* typedef __signalfn_t * typedef __sighandler_t -+////struct nsproxy /* an opaque type */ -+////struct nsproxy * # /* pointer to it */ -+////long unsigned int typedef u64 volatile -+////long unsigned int volatile const * const -+////long unsigned int typedef sector_t [////long unsigned int 511] -+/k/include/linux/types.h//222//struct list_head -+/k/include/linux/types.h//222//struct list_head * -+/k/include/linux/types.h//222//struct list_head [////long unsigned int 5] -+/k/include/linux/types.h//217//struct /* no struct tag */ -+/k/include/linux/types.h//217//struct typedef atomic64_t -+/k/include/linux/mm_types.h//34//struct page * typedef pgtable_t -+/k/fs/eventpoll.c//122//struct nested_calls -+/k/include/linux/sysctl.h//1016//struct ctl_table typedef ctl_table -+ [////long unsigned int 4] var inotify_table /* A global variable */ -+ -+This scheme means that cv-quals and other modifiers applied to other types are -+always merged: if there are a dozen typedefs for a single type 'foo' with the -+same name declared in the same place, they all end up with the same type ID and -+are only emitted into the CTF once. -+ -+The type_id() function can also accept a callback, which is called as the -+recursion unwinds, from base type up to derived type: so it might be called for -+"////unsigned int", then for "////unsigned int typedef __kernel_uid_t", and so -+on up to the DIE that was originally passed in. Because type_id() returns a -+dynamically-allocated string, calls to type_id() made purely for the sake of -+invoking a callback are normally of the peculiar form "free(type_id(...))". -+ -+type_id() is a very hot spot, so syscall results are cached in it (such as -+realpath(), as mentioned above), and when string appending is done, it is done -+all at once where possible, via str_appendn(), which calls realloc() only once -+no matter the number of strings being appended. -+ -+Lots of core data structures in dwarf2ctf consist of hashes mapping type IDs to -+something else (predominantly CTF file/ID pairs and module names). It would -+be possible to map from hashes of type IDs, saving some memory, but this would -+impair debugging so is not yet implemented. (If it is implemented, it should -+probably be implemented only when DEBUG is not defined.) -+ -+ -+Duplicate detection -+------------------- -+ -+ scan_duplicates() -+ process_file() /* Toplevel DWARF walkers */ -+[C] detect_duplicates_init() -+[R] process_tu_func() -+[C] assembly_filter_tab[] -+[C] detect_duplicates() -+[ 1] mark_shared() -+[R] type_id() /* Type IDs */ -+[C1] mark_shared() -+[ 4] type_id() -+[ 4] detect_duplicates_typeid() -+[ 4] detect_duplicates() -+[R] mark_seen_contained() -+ member_blacklisted() -+[C] detect_duplicates_done() -+ -+ process_file() -+[C] detect_duplicates_init() -+[R] process_tu_func() -+[C] assembly_filter_tab[] -+[C] detect_duplicates_alias_fixup() -+[R] type_id() -+[C] is_named_struct_union_enum() -+[R] type_id() -+[C] detect_duplicates_alias_fixup_internal() -+ mark_shared() (see above) -+[C] detect_duplicates_done() -+ -+The job of the duplicate detection pass is to fill out the id_to_module hash, -+which maps type IDs to the module they appear in, with the two special cases -+that types that appear only in the core kernel are said to appear in the module -+'vmlinux', and types that appear in more than one module (or in a module and in -+the core kernel) are said to appear in the module 'shared_ctf', the shared type -+repository. This is quite a tricky multi-pass process, because we must ensure -+that the shared type repository is self-contained: all types in the repository -+must not reference any types outside the repository. -+ -+Detecting duplicates itself is easy: we consider two types duplicates if they -+have the same type ID: if they both reside in the same module, the resulting -+type resides in that module too. However, detecting shared types is harder. -+We consider that a type belongs in the shared module if any of these conditions -+is true: -+ -+ - the type appears multiple times in different modules -+ - a type for which this type is a base type is shared -+ - the type is referenced by a structure or union member, and the structure -+ or union is shared -+ - the type is a non-opaque type with an opaque variant ('struct foo'), or -+ vice versa, and either of these variants is shared: these two types will -+ get different type IDs, so explicit checking is necessary -+ -+Note that we do *not* consider a type to belong in the shared module merely if -+*it* has a base type which is shared: indeed, this is the common case for -+unshared types (even unshared structures tend to have fields of shared types -+like int). -+ -+It should be fairly easy to see that sharedness is a contagious property: -+e.g. if you mark a structure as shared, and one of its members is an -+otherwise-unshared opaque pointer to a structure, you have to mark that as -+shared: this causes the non-opaque definition of the structure, and all *its* -+members, to be shared, and so on. So since dwarf2ctf does not track the members -+of structures itself (not until the CTF generation phase, anyway), this means -+walking over the DWARF DIEs multiple times, checking for sharedness over and -+over until we are done. -+ -+We partition the problem into two parts, both of which are carried out by -+process_file() callback functions: detect_duplicates() and -+detect_duplicates_alias_fixup(). -+ -+ -+detect_duplicates() is called first, once for every DIE in the kernel (via -+process_file()). This identifies types that are duplicated but not shared, and -+identifies shared types without consideration of opaque struct/union aliasing. -+It also flags types that have been seen only once as 'seen': this is checked -+much later on by the CTF construction phase, since construction of CTF for -+any type which has not been inspected by the deduplicator is a sign of a bug in -+the deduplicator. -+ -+This has several subtleties. -+ -+If we are running for an out-of-tree module, we must still identify types as -+duplicated within the module, but must never mark them as shared: out-of-tree -+modules cannot contribute to the shared type repository nor even use types in -+it, since they are rebuilt independently from the kernel proper and thus cannot -+depend on a type currently in the repository remaining there (e.g. perhaps it -+has only two users, both in modules, and the kernel is rebuilt to not build one -+of those modules anymore: this should not require rebuilding of any out-of-tree -+modules). -+ -+If we mark a structure or union type as seen, we must mark aggregate types that -+appear directly within that type's DIE as seen as well. This is done by the -+recursive function mark_seen_contained(). You might wonder what the point of it -+is: such types surely cannot appear anywhere else, and any duplication will -+precisely match the duplication of the containing type. The answer is that they -+can still be referenced as the type of structure members of their containing -+structure, e.g. in -+ -+struct foo { -+ struct bar { -+ } *baz; -+ struct bar wombat[16]; -+}; -+ -+Here, a reference to 'struct bar' appears in 'struct foo', and CTF is -+constructed for it, even though it is not a top-level DIE. In GCC 4.8+, a -+reference to the 16-element array-of-struct-bar can also appear in 'struct foo': -+in fact almost anything can appear in there if used nowhere else in the -+translation unit, even base types. So we look for the appearance of anything -+which we can assemble into CTF (anything in the assembly_tab) other than -+members, since members cannot be used as the type of anything else, and mark -+them all as seen in this module. (Nearly everything in a structure or union is -+a member, so this ends up skipping almost but not quite everything.) -+ -+ -+If we find that a type has appeared more than once in different kernel modules -+(or in a module and in the core kernel), we must mark it as shared. This is -+done via mark_shared(), which is both a function that can be directly called -+(e.g. from detect_duplicates()) and a type_id() callback. If it is called -+directly, it immediately reinvokes itself as a type_id() callback, which calls -+it for the base type of the type in question and then for all qualifiers up the -+type ID stack, marking them all as shared if they weren't already. -+ -+If a structure or union is marked as shared, the types of its members are also -+marked as shared via a recursive call (even if they have already been so marked: -+just because this structure is of a type we've already seen, in a location we've -+already seen, doesn't mean that someone might not have legitimately used -+#defines to add extra members to the end of it, and we need to mark them as -+shared too). We track structures that have been seen in this translation unit -+and avoid recursing into them, to avoid an infinite loop in cases like this: -+ -+struct one; -+struct two { -+ struct one *foo; -+}; -+ -+struct one { -+ struct two *foo; -+} -+ -+The types being pointers does not help here -- the marking of 'struct one *' as -+shared will automatically mark 'struct one' as shared too, because otherwise we -+might have a structure in the shared type repository whose members' types -+could not be found there. -+ -+ -+The second pass is the 'alias fixup' pass, implemented by -+detect_duplicates_alias_fixup(). This pass serves to detect unshared opaque -+types whose non-opaque equivalents are shared, and vice versa. It is executed -+repeatedly until no types have been marked as shared for an entire iteration, -+but is considerably faster per iteration than the first pass, which often -+consumes more than half of dwarf2ctf's total runtime. We work in one direction -+only, looking for non-opaque structures, unions or enums which have structure -+tags. (Structures without tags cannot have opaque variants, and structures -+which are opaque will have non-opaque cousins somewhere, or can be emitted to -+the CTF as an opaque structure harmlessly since they truly have no members and -+are probably manipulated only via casts.) -+ -+We identify structures, unions or enums with tags via the type_id() callback -+is_named_struct_union_enum(), but cannot determine if something is an opaque -+structure at this stage. Instead, we do that after the callback, checking to -+see if the first four characters of the type ID are "////": this relies on the -+fact that GCC never gives opaque structures line numbers in DWARF. We do the -+actual checking and marking of each non-opaque structure using -+detect_duplicates_alias_fixup_internal(), which is yet another type_id() -+callback. -+ -+This function directly synthesises the name which this structure's opaque cousin -+would have, if it existed, by stripping off the line number and filename and -+replacing them with '////', and sees if either of these types have been marked -+as shared while the other has not. If the opaque type is shared, the non-opaque -+variant can be marked shared using the same recursive mark_shared() function as -+before (thus marking the types of all its members and types it depends upon as -+shared too). If it is the opaque type that needs marking shared, this will not -+work, since mark_shared() takes a DWARF DIE, and we don't have one for the -+opaque type, just a faked-up type ID. However, since an opaque type doesn't -+have any members that need recursively tracing, we don't need access to its -+DWARF DIE to figure them out, and can just mark it as shared directly, via an -+insert into the id_to_module hash. -+ -+Since this function is a type_id() callback, it is called not just for -+structures but for types based on them (e.g. in type_id form, "struct foo const -+* [43] volatile *"); at every level of this declarator stack, a shared opaque -+base type will contaminate its non-opaque cousins with sharedness, and vice -+versa. This handles situations in which, say, the opaque version of "struct foo -+const * [43]" was used by more than one module and was marked as shared: the -+marking process will have marked the opaque versions of "struct foo const * -+[43]", "struct foo const *", "struct foo const" and "struct foo" as shared, but -+will not have touched any non-opaque versions of these types which may exist -+until this routine runs. It also handles typedefs to structures with no need -+for any extra code. -+ -+This whole alias fixup process needs to be repeated, because whenever a -+non-opaque type is marked as shared and its member's types traced and marked -+shared, *those* may themselves be structure types with corresponding opaque or -+non-opaque variants, and when they are opaque types the non-opaque variant that -+alias fixup works from may already have passed under the DWARF walker's gaze: so -+another pass over the kernel's DWARF is necessary to be sure we catch it. -+mark_shared() thus sets a flag that scan_duplicates() recognizes and uses to -+trigger another run through the alias fixup pass. -+ -+ -+There are a very few modules that this algorithm doesn't work for. One example -+is snd-ens1371, which reads, in toto -+ -+#define CHIP1371 -+#include "ens1370.c" -+ -+and ens1370.c (itself a distinct kernel module) then defines a 'struct ensoniq' -+whose members vary depending on whether CHIP1371 is defined. Obviously, it is -+impossible to share any such types between kernel modules even though their -+names are the same and they are defined in the same place in the same source -+file in both cases. But this sort of trickery is very rare, so we simply -+implement a 'deduplication blacklist' of modules which will not introduce new -+types into the shared CTF repository, and who do not participate in alias fixup -+detection either. Detecting these cases in order to blacklist them is harder: -+no automated system has yet been implemented, although instances where #defines -+of this nature introduce new types that are then used by later members will -+cause assertion failures inside dwarf2ctf which might be a clue. So it is -+possible that some examples have been missed. (The blacklist only applies to -+cases where structure members change within a single kernel build, so cases -+where structures have members whose presence depends on CONFIG_* values are -+quite all right, as are cases where #defines are introduced by one translation -+that #includes another that then goes on to define whole new structures: it is -+only cases where modules #define something that changes the definition of -+individual possibly-shared types that will need blacklisting.) -+ -+ -+There are a few even worse cases where a single structure is defined with -+different members in different translation units within a single module. In -+this case we can do nothing at all, since our output representation describes -+only a single type per module: we implement a 'member blacklist' which bans -+emission of affected members entirely, leaving a description of a structure with -+an undescribed hole in it. -+ -+ -+CTF construction -+---------------- -+ -+ process_file() -+[R] process_tu_func() -+[C] assembly_filter_tab[] -+[C] construct_ctf() -+[ 2] construct_ctf_id() -+[R3] die_to_ctf() -+ assembly_tab[] -+[C] -> assemble_ctf_base() -+ -> assemble_ctf_pointer() -+ | assemble_ctf_array() -+ | assemble_ctf_array_dimension() -+ | assemble_ctf_typedef() -+ | assemble_ctf_cvr_qual() -+ | assemble_ctf_variable() -+ lookup_ctf_type() -+[ 2] construct_ctf_id() -+ -> assemble_ctf_enumeration() -+ -> assemble_ctf_enumerator() -+ -> assemble_ctf_struct_union() -+ -> assemble_ctf_su_member() -+ member_blacklisted() -+[ 3] die_to_ctf() -+[ 2] construct_ctf_id() -+[C] cleanup_sou_member_count() -+ -+The next stage after the detection of duplicate and cross-module shared types is -+to generate CTF. We generate all CTF at once before emitting it: this is -+potentially somewhat wasteful of memory, but in practice has not proved to be a -+problem: substantially less memory is used than is used by other parts of the -+kernel build, unless -DDEBUG is enabled. Its job is to look through the -+kernel's type DWARF (via process_file(), as usual) and create CTF for every -+file-or-global-scope type and every externally-visible variable in the CTF file -+in which the duplicate detection pass has said that type should appear. -+(Variables are treated exactly like types: it just so happens that they are -+never shared because no type or variable can depend upon them, so they always go -+directly into the appropriate module and never into the shared type repository.) -+ -+At this stage, the 'CTF files' are not actually files but rather ctf_file_t -+structures maintained by libdtrace-ctf and tracked in the per_module hash, along -+with other information which varies by module name. We track every single -+individual type in the CTF file in the id_to_type hash, which maps type IDs to -+pairs of (CTF file ID, ctf type ID): this lets us use the type IDs described -+above when considering cross-references within CTF files (e.g. from one CTF type -+to a type it depends upon). -+ -+The most important functions in this phase are: -+ -+ - construct_ctf_id(), the top-level process_file() callback which is given a -+ DWARF DIE, looks in module_to_ctf_file for the CTF file where this type -+ should land (creating it if necessary), makes sure a type with this type ID -+ has not already been created there, calls die_to_ctf() to create the CTF, -+ notes where it was created in id_to_type, and handles errors. -+ -+ - die_to_ctf(), a recursive function which calls the assembly function for the -+ DIE it is given and all its immediate children, with special-case handling -+ for tagged structures and unions. If you want to create a type but not note -+ where it was created for future lookups by lookup_ctf_type(), this is what to -+ call. (This is only done currently for unnamed structures/unions.) -+ -+ - lookup_ctf_type(), which is called by CTF assembly functions for those -+ types that depend upon other types: it calls construct_ctf_id() again -+ to construct the type, and double-checks that all such types appear -+ either in the module we are constructing types for, or in the shared CTF -+ module. CTF represents all function pointers the same way, and has a -+ special type ID for 'void', so we special-case both of these cases. -+ -+These functions are mostly straightforward (though highly recursive, with all -+three plus CTF construction functions participating in loop 2 above, -+die_to_ctf() calling itself directly, and even one situation, the -+already-mentioned unnamed structures/unions, in which die_to_ctf() is directly -+called back by a CTF construction function, in loop 3 above.) -+ -+ -+There are a few subtleties, though. Firstly, error handling. We consider that -+errors that will lead to unusable CTF are fatal: mostly, these are errors where -+a bug in the deduplicator has failed to trace types correctly and has left at -+least one type in the shared module depending on a type in a non-shared module, -+or has failed to mark a type as shared at all. In all these cases, you'll -+eventually get an error from lookup_ctf_type() of the general form -+ -+blah.c:413:foo_t: Internal error: lookup of flob found in different file. -+ -+The first two parts of this error are the translation unit and line number the -+type being assembled (usually a structure or union) was found in: foo_t is the -+name of the type being assembled. The type of the structure being looked up -+appears nowhere, because we don't know it, but the name of the member is given -+("flob" above, or "(unnamed)" if we don't know it). If you want more -+information, you can pass -DDEBUG to the compilation of dwarf2ctf.c in -+scripts/dwarf2ctf/Makefile, and rerun dwarf2ctf, and you'll get the module and -+filename in which both the originating and the target types appear. In order to -+actually track down the bug you'll probably have to run dwarf2ctf with -+DWARF2CTF_TRACE set in the environment, and look at the place where the target -+type was deduplicated, and try to figure out why the deduplicator didn't trace -+the reference to the type in foo_t correctly. -+ -+There is another kind of error, though: a failure to assemble a single type, -+perhaps because DWARF was emitted that we don't know how to understand (this is -+particularly likely in structure assembly, where we are highly dependent on the -+form of the DWARF that GCC happens to emit for DW_AT_member_location). We pass -+an 'enum skip_type' around, which has three possible values, one of which is -+SKIP_ABORT. Before each type is assembled, we call ctf_snapshot() to take a -+snapshot of the variable-plus-type set in the CTF file we're working over. If a -+SKIP_ABORT propagates up to construct_ctf_id(), we call ctf_rollback(), which -+throws away every type constructed since the last ctf_snapshot() -- i.e., the -+specific erroneous type we've just been working on. (We might have emitted some -+parts of it and then failed, so we should try to clean up). -+ -+A SKIP_ABORT is not fatal unless DEBUG is defined: its only effect is to omit -+one single type from the resulting CTF, which is probably still usable. -+ -+libdtrace-ctf causes additional problems here. It can only see the types we -+added once the notably expensive function ctf_update() is called. This takes -+the in-memory structures and serializes them (all of them, every time). This -+only affects libctf when structure and union members are added: libctf needs to -+know the sizes and alignments of the types of those members, which might quite -+possibly just have been added, e.g. if this structure contains a pointer to its -+own structure tag. So, when we insert a member in assemble_ctf_su_member(), we -+note a bad type-ID error and do a ctf_update() on the file we're working over -+and try again: even then that can fail if the type was added to the shared -+repository, so we do a ctf_update() on *that* and try again, and only if that -+fails do we declare a SKIP_ABORT error. (We check the shared repository last -+because it is very large, so takes longer to serialize than other CTF files do). -+ -+The need to keep the number of calls to ctf_update() down means we must avoid -+all access to the CTF types we are assembling if we can possibly get at the same -+data another way. Hence the member_counts hash, a member of the per_module -+state, which tracks the number of members in structures with a given C-style -+name and their CTF IDs. This structure allows us to handle the (valid) C idiom -+of redeclaring the same structure with a different number of members, merging -+the definitions across translation units and discarding them (iff the structure -+was unshared) when we transition into a new module, without ever having to -+consult the CTF to see how many members we put into it. (We have to use the -+C-style name here, because by definition the type IDs of such redeclared -+structures will be different, since a type ID contains a line number and -+translation unit name.) -+ -+ -+There's more error-handling complexity inside die_to_ctf(), where errors from -+libdtrace-ctf are actually reported (there may be multiple of them for a single -+type, e.g. if we are assembling a structure and several members somehow refer to -+a type we do not know about). -+ -+die_to_ctf() itself has the sort of parameter list that can make people swear -+off C for life. It is largely explained in the description of ctf_assembly_fun. -+Most parts of it are hardly used in the function itself, just passed down to CTF -+assembly functions. -+ -+Finally, we must note the override flag. Both die_to_ctf() and -+construct_ctf_id() return a CTF ID. This is thrown away by the DWARF walking -+code (the function construct_ctf() exists just for that purpose), but when -+called by lookup_ctf_type(), this CTF ID is taken to be the single ID of the CTF -+type that's just been assembled. Normally this is the same as the CTF ID -+returned by the CTF assembly function for the top-level DWARF DIE, but there are -+a few structures for which we want to return the result of some other CTF -+assembly function. -+ -+The only currently-existing example is array dimensions, which DWARF represents -+as a typed array DIE whose child is a dimension, but which CTF represents as an -+array-with-dimensions that you can't change afterwards. We can't assemble an -+'array' at the top level because we don't know how big it is, but we have to -+track the type recorded there somehow. We handle this by having -+assemble_ctf_array(), the assembly function for the top-level DW_TAG_array_type -+DIE, simply look up the type of the array's members and return its ID as if it -+had just constructed it, after which assemble_ctf_array_dimension(), the -+assembly function for DW_TAG_subrange_type, actually constructs the array, -+wrapping it around the CTF 'ID' 'assembled' by the parent and setting the -+override flag to make sure that this is what is really recorded. -+ -+ -+CTF construction functions -+-------------------------- -+ -+Each CTF construction function takes a single DWARF DIE and turns it into CTF, -+somehow. They are laid out in the assembly table described in 'toplevel DWARF -+walkers' above. They all start the same way, with a series of CTF_DW_ENFORCE or -+CTF_DW_ENFORCE_NOT assertions. These guard against corrupted DWARF missing some -+of the attributes we need, or DWARF containing attributes which indicate that we -+can't handle the content (e.g. DW_AT_signature or DW_AT_specification on -+structures, which would both indicate this is DWARF 4, which we can't handle -+yet.) -+ -+We'll go through these functions one by one, pointing out anything that -+maintainers should be aware of. -+ -+ -+assemble_ctf_base() assembles all integral base types (DW_TAG_base_type) and -+transforms them into the corresponding CTF type. The functions we need to call -+for this in the CTF API all have the same type signature but have different -+names; CTF also distinguishes between the various differently-sized -+floating-point types, so we must figure out from the type size which type a -+given DWARF base type is referring to. We map from DWARF encoding to a triple -+of (CTF addition function, CTF integral type, type size) where the latter is -+optional and depends on the size of the DWARF type we are encoding and the size -+of various floating_point types on the current system. (This does mean that -+cross-compilation using dwarf2ctf is likely to fail fairly often: we need -+machinery to determine the sizeof() types on the target system before that can -+function.) -+ -+This sizeof()-based search procedure is why we do not currently support -+DW_AT_bit_size for base types: we could easily support it for sizes modulo 8, -+but GCC happens to emit DW_AT_byte_size in this case. In C DW_AT_bit_size is -+likely to be emitted only for bitfields in structures anyway, not for base -+types. -+ -+ -+assemble_ctf_pointer() and assemble_ctf_typedef() are trivial: look up the -+associated type with lookup_ctf_type() and assemble the appropriate thing. -+assemble_ctf_cvr_qual() is almost as trivial, but has to figure out which of -+const, volatile or restrict it was called for and call the corresponding CTF API -+function. assemble_ctf_enumeration() and assemble_ctf_enumerator() are quite -+simple too. -+ -+ -+assemble_ctf_variable() has a couple of extra complexities: we unconditionally -+set the skip parameter to SKIP_SKIP, suppressing recursion into containing DIEs, -+since we already know we won't care about any of them. Also, while the -+deduplication pass unifies opaque and non-opaque structures into the same type, -+it never makes sure that variables declared in the same header by translation -+units which have opaque versus non-opaque structures in scope are deduplicated. -+e.g. you could well end up with these two type IDs, depending on whether -+<linux/pid_namespace.h> was included before <linux/pid.h> in a given translation -+unit: -+ -+////struct pid_namespace var init_pid_ns -+/path/to/kernel/include/linux/pid_namespace.h//19//struct pid_namespace var init_pid_ns -+ -+These variables both refer to the same type, but deduplicating them would -+require an additional deduplication pass. Since variables are always terminal -+and nothing can refer to them, nothing will ever look up any of those type IDs -+(since the only thing that looks up type IDs is code that is searching for type -+that other types depend on). So we don't care about this duplication and -+running an additional deduplication pass to eliminate it would slow down -+dwarf2ctf to no good end. It's better just to ignore duplicate errors from -+ctf_add_variable(). -+ -+ -+assemble_ctf_array() and assemble_ctf_array_dimension() we talked about -+above. One last subtlety remains, which is that figuring out the actual -+dimensionality of an array is complicated enough that it has been hived off into -+a private_subrange_dimension() function, called both from here and from -+type_id(). Arrays with neither a DW_AT_upper_bound nor a DW_AT_count, and -+arrays without an indexing type, are best considered flexible arrays; arrays -+whose upper bound or count is not unsigned or signed integral data are also -+flexible (perhaps they're using a full-blown location list, but we can't encode -+that in CTF so we treat it as flexible); and if an upper bound is used, we want -+to add one to its value before treating it as a count of elements. -+ -+ -+This leaves structure/union assembly, both of which are assembled by the same -+pair of functions, assemble_ctf_struct_union for the type itself and -+assemble_ctf_su_member() for the individual members. As with -+assemble_ctf_cvr_qual(), we have to look at the tag to figure out which CTF -+function to use to do the assembly, but we have an extra constraint: it is -+perfectly idiomatic C to declare a structure repeatedly with a different number -+of members every time. This is perfectly permissible as long as the leading -+portions of all declarations match. We do not verify this (we hope that the -+compiler will diagnose it, which it will unless the conflicting declarations -+cross modules), though perhaps we should: we simply look up the structure in the -+CTF and the DWARF and skip assembly of the structure members via SKIP_SKIP if -+the already-assembled structure has at least as many members as the current one. -+ -+assemble_ctf_su_member() is by far the most complex of the assembly functions. -+It has to handle members that already exist, members that need assembly, members -+that correspond to unnamed structure members, numerous different ways of -+representing structure offsets and members with no offset at all. -+ -+The offset computation is quite laborious and by no means complete: a complete -+implementation would require an interpreter for DWARF location lists, which is -+total overkill given that in DWARF2 GCC emits a totally stereotyped location -+list, and in DWARF3+ we don't need location list parsing at all. CTF wants an -+offset in bits. -+ -+We have five cases: -+ - for DW_AT_data_bit_offset, we just use the offset unchanged. -+ -+ - for DW_AT_data_member_location with an integral form (data2, data4, data8, -+ udata, or sdata) we just look it up and multiply it by eight, adding the -+ parent's DW_AT_bit_offset to handle structures nested inside other -+ structures. -+ -+ - for DW_AT_data_member_location with a block form, we make sure that the list -+ is of one particular simple form (DW_OP_plus_uconst and a constant value in -+ bytes), and abort assembly otherwise. The only case I know of where this -+ test will trip is C++ virtual bases: if people are using C++ code with -+ virtual bases inside the kernel they deserve sympathy, but probably not -+ support in the code. CTF can't represent C++ types in any case. -+ -+ - for expression location lists, or anything else that we don't understand, we -+ simply die (we could simply skip the type, but this seems serious enough that -+ dying is warranted). -+ -+ - with none of these present, we have no offset: the member is at the same -+ location as the start of the structure. -+ -+But where is the 'start of the structure'? That depends on whether this is an -+unnamed struct/union member (usually a union). If it is, we want to fold all -+its members directly into the parent structure, with their offsets increased by -+the offset of the unnamed member as a whole. This is done by directly calling -+die_to_ctf() with the first child of the anonymous member's type and with all -+other parameters set as if the parent DIE was the current structure, thus -+fooling die_to_ctf() into believing that these members are members of the -+current structure, not of the anonymous one. The offset-increasing magic is -+done via the parent_bias parameter to die_to_ctf() and all the CTF construction -+functions: it is ignored by all of them except for assemble_ctf_su_member() -+itself, which adds the parent bias onto the normally-computed offset, and is -+otherwise passed down unchanged to all children. This means that even this -+terribly contrived case works: -+ -+struct horror { -+ int spacer; -+ union { -+ struct { -+ int spacer; -+ struct { -+ int foo; -+ int bar; -+ } b; -+ } a; -+ }; -+}; -+ -+In this situation, horror.a.b.bar may have: -+ -+ - a nonzero parent_bias due to the offset of the anonymous union in 'struct -+ horror' -+ - a nonzero offset due to the offset of 'bar' in its containing structure -+ - if DW_AT_data_member_location with integral form is used, a nonzero -+ DW_AT_bit_offset of 'b' in 'a' -+ -+If this is not an anonymous union, we are dealing with only one member: we look -+up its type and add it reasonably conventionally via ctf_add_member_offset(). -+Even here there are subtleties: we use construct_ctf_id() directly rather than -+via lookup_ctf_type() so we can get a better error message on failure, and we -+ignore any duplicate-member errors because this is probably a sign that this -+structure has already been encountered and we are working through another -+instance of it with more members. -+ -+ -+Writeout -+-------- -+ -+ write_types() -+ -+This couldn't really be simpler, as the trivial call graph shows. We create an -+output directory with the requested name, then work over the entire -+module_to_ctf_file hash, writing out every CTF file into a new suitably-named -+file via zlib's compressed file I/O functions. -diff --git a/Documentation/kbuild/kconfig.rst b/Documentation/kbuild/kconfig.rst -index dce6801d66c9b5e575ad9c4b4e8a557181bf7e8f..a9a855f894b3fad08f7ef89fff31fd7c626819eb 100644 ---- a/Documentation/kbuild/kconfig.rst -+++ b/Documentation/kbuild/kconfig.rst -@@ -154,6 +154,11 @@ KCONFIG_AUTOCONFIG - This environment variable can be set to specify the path & name of the - "auto.conf" file. Its default value is "include/config/auto.conf". - -+KCONFIG_TRISTATE -+---------------- -+This environment variable can be set to specify the path & name of the -+"tristate.conf" file. Its default value is "include/config/tristate.conf". -+ - KCONFIG_AUTOHEADER - ------------------ - This environment variable can be set to specify the path & name of the -diff --git a/Documentation/process/changes.rst b/Documentation/process/changes.rst -index dac17711dc1123c5996c5468086168a8c55f126a..1bce2aab4109241ecfd4fd48ca57506256dea101 100644 ---- a/Documentation/process/changes.rst -+++ b/Documentation/process/changes.rst -@@ -56,9 +56,14 @@ iptables 1.4.2 iptables -V - openssl & libcrypto 1.0.0 openssl version - bc 1.06.95 bc --version - Sphinx\ [#f1]_ 1.3 sphinx-build --version -+elfutils\ [#f2]_ 0.156 eu-readelf --version -+pkg-config\ [#f2]_ 0.16 pkg-config --version -+glib\ [#f2]_ 2.x pkg-config --exists glib-2.0 && echo present -+libdtrace-ctf\ [#f2]_ 1.1 - ====================== =============== ======================================== - - .. [#f1] Sphinx is needed only to build the Kernel documentation -+.. [#f2] This is needed at build-time when CTF or DTrace are enabled - - Kernel compilation - ****************** -@@ -94,7 +99,8 @@ pkg-config - The build system, as of 4.18, requires pkg-config to check for installed - kconfig tools and to determine flags settings for use in - 'make {g,x}config'. Previously pkg-config was being used but not --verified or documented. -+verified or documented. dwarf2ctf also relies on it during 'make ctf' and -+while building out-of-tree modules with CONFIG_CTF enabled. - - Flex - ---- -@@ -371,6 +377,21 @@ OpenSSL - - - <https://www.openssl.org/> - -+elfutils -+-------- -+ -+- <https://fedorahosted.org/elfutils/> -+ -+glib 2.x -+-------- -+ -+- <http://www.gtk.org/> -+ -+libdtrace-ctf -+------------- -+ -+- <https://oss.oracle.com/git/?p=libdtrace-ctf.git> -+ - System utilities - **************** - -diff --git a/Makefile b/Makefile -index a6b2e64bcf6c786be1bb38ff9b593c7c3f838e0a..e94e5bfc9c4f5d9c64c08c83d877c2c9394bc2c7 100644 ---- a/Makefile -+++ b/Makefile -@@ -1166,7 +1166,7 @@ cmd_link-vmlinux = \ - $(CONFIG_SHELL) $< "$(LD)" "$(KBUILD_LDFLAGS)" "$(LDFLAGS_vmlinux)"; \ - $(if $(ARCH_POSTLINK), $(MAKE) -f $(ARCH_POSTLINK) $@, true) - --vmlinux: scripts/link-vmlinux.sh autoksyms_recursive $(vmlinux-deps) FORCE -+vmlinux: scripts/link-vmlinux.sh autoksyms_recursive $(vmlinux-deps) modules_thick.builtin FORCE - +$(call if_changed,link-vmlinux) - - targets := vmlinux -@@ -1406,6 +1406,45 @@ modules.order: $(subdir-modorder) FORCE - - targets += modules.order - -+ifneq (CONFIG_CTF@,'@') -+ -+# We need to force everything to be built, since we need the .o files below. -+KBUILD_BUILTIN := 1 -+ -+# This contains all the object files that are built directly into the -+# kernel (including built-in modules), for consumption by dwarf2ctf in -+# Makefile.modpost. -+# This is made doubly annoying by the presence of '.o' files which are actually -+# thin ar archives, and the need to support file(1) versions too old to -+# recognize them as archives at all. (So we assume that everything that is not -+# an ELF object is an archive.) -+ifeq ($(SRCARCH),x86) -+objects.builtin: $(vmlinux-dirs) $(if $(KBUILD_BUILTIN),bzImage) FORCE -+else -+objects.builtin: $(vmlinux-dirs) $(if $(KBUILD_BUILTIN),vmlinux) FORCE -+endif -+ @echo $(KBUILD_VMLINUX_OBJS) | \ -+ tr " " "\n" | grep "\.o$$" | xargs -r file | \ -+ grep ELF | cut -d: -f1 > objects.builtin -+ @for archive in $$(echo $(KBUILD_VMLINUX_OBJS) |\ -+ tr " " "\n" | xargs -r file | grep -v ELF | cut -d: -f1); do \ -+ $(AR) t "$$archive" >> objects.builtin; \ -+ done -+ -+ctf: vmlinux.ctfa -+PHONY += ctf -+ -+# Making CTF needs the builtin files unless out-of-tree. -+ifeq ($(KBUILD_EXTMOD),) -+vmlinux.ctfa: modules_thick.builtin objects.builtin -+endif -+vmlinux.ctfa: -+ $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modfinal vmlinux.ctfa -+else -+PHONY += objects.builtin -+objects.builtin: -+endif -+ - # Target to prepare building external modules - PHONY += modules_prepare - modules_prepare: prepare -@@ -1428,6 +1467,9 @@ _modinst_: - @sed 's:^:kernel/:' modules.order > $(MODLIB)/modules.order - @cp -f modules.builtin $(MODLIB)/ - @cp -f $(objtree)/modules.builtin.modinfo $(MODLIB)/ -+ @if [ -f $(objtree)/vmlinux.ctfa ] ; then \ -+ cp -f $(objtree)/vmlinux.ctfa $(MODLIB)/kernel ; \ -+ fi - $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modinst - - # This depmod is only for convenience to give the initial -@@ -1459,6 +1501,23 @@ modules modules_install: - - endif # CONFIG_MODULES - -+# modules_thick.builtin maps from kernel modules (or rather the object file -+# names they would have had had they not been built in) to their constituent -+# object files: dwarf2ctf uses this to determine which modules any given object -+# file is part of. (We cannot eliminate the slight redundancy here without -+# double-expansion.) -+ -+modthickbuiltin-dirs := $(addprefix _modthickbuiltin_, $(build-dirs)) -+ -+modules_thick.builtin: $(modthickbuiltin-dirs) -+ $(Q)$(AWK) '!x[$$0]++' $(addsuffix /$@, $(build-dirs)) > $@ -+ -+PHONY += $(modthickbuiltin-dirs) -+# tristate.conf is not included from this Makefile. Add it as a prerequisite -+# here to make it self-healing in case somebody accidentally removes it. -+$(modthickbuiltin-dirs): include/config/tristate.conf -+ $(Q)$(MAKE) $(modbuiltin)=$(patsubst _modthickbuiltin_%,%,$@) builtin-file=modules_thick.builtin -+ - ### - # Cleaning is done on three levels. - # make clean Delete most generated files -@@ -1467,9 +1526,10 @@ endif # CONFIG_MODULES - # make distclean Remove editor backup files, patch leftover files and the like - - # Directories & files removed with 'make clean' --CLEAN_FILES += include/ksym vmlinux.symvers \ -- modules.builtin modules.builtin.modinfo modules.nsdeps \ -- compile_commands.json -+CLEAN_FILES += include/ksym .ctf vmlinux.symvers \ -+ modules.builtin modules.builtin.modinfo objects.builtin \ -+ modules.nsdeps compile_commands.json \ -+ .ctf.filelist .ctf.filelist.raw - - # Directories & files removed with 'make mrproper' - MRPROPER_FILES += include/config include/generated \ -@@ -1564,6 +1624,8 @@ help: - @echo ' (requires a recent binutils and recent build (System.map))' - @echo ' dir/file.ko - Build module including final link' - @echo ' modules_prepare - Set up for building external modules' -+ @echo ' ctf - Generate CTF type information for DTrace, installed by ' -+ @echo ' make modules_install' - @echo ' tags/TAGS - Generate tags file for editors' - @echo ' cscope - Generate cscope index' - @echo ' gtags - Generate GNU GLOBAL index' -@@ -1825,7 +1887,7 @@ clean: $(clean-dirs) - -o -name '*.symtypes' -o -name 'modules.order' \ - -o -name '.tmp_*.o.*' \ - -o -name '*.c.[012]*.*' \ -- -o -name '*.ll' \ -+ -o -name '*.ll' -o -name '*.ctfa' \ - -o -name '*.gcno' \) -type f -print | xargs rm -f - - # Generate tags for editors -diff --git a/lib/Kconfig b/lib/Kconfig -index b46a9fd122c81acabd888e8b250e78be4f575ef6..e2906daac926dc0b9f5342b37d521670015d7841 100644 ---- a/lib/Kconfig -+++ b/lib/Kconfig -@@ -582,6 +582,18 @@ config DIMLIB - # - config LIBFDT - bool -+# -+# CTF support is select'ed if needed -+# -+config CTF -+ bool "Compact Type Format generation" -+ default n -+ select STRIP_ASM_SYMS -+ depends on DEBUG_INFO && !DEBUG_INFO_REDUCED && !DEBUG_INFO_SPLIT && !DEBUG_INFO_DWARF4 && DTRACE -+ help -+ Emit a compact, compressed description of the kernel's datatypes and -+ global variables into the vmlinux.ctfa archive (for in-tree modules) -+ or into .ctf sections in kernel modules (for out-of-tree modules). - - config OID_REGISTRY - tristate -diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include -index 08e011175b4c879852a2cc203ea0b2ccf4ce8cfc..d3c6f0f56e6538b4383dea122f4f3ab687f5938b 100644 ---- a/scripts/Kbuild.include -+++ b/scripts/Kbuild.include -@@ -157,6 +157,12 @@ ld-ifversion = $(shell [ $(ld-version) $(1) $(2) ] && echo $(3) || echo $(4)) - # $(Q)$(MAKE) $(build)=dir - build := -f $(srctree)/scripts/Makefile.build obj - -+### -+# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.modbuiltin obj= -+# Usage: -+# $(Q)$(MAKE) $(modbuiltin)=dir -+modbuiltin := -f $(srctree)/scripts/Makefile.modbuiltin obj -+ - ### - # Shorthand for $(Q)$(MAKE) -f scripts/Makefile.dtbinst obj= - # Usage: -diff --git a/scripts/Makefile b/scripts/Makefile -index b5418ec587fbd2cd6ca6896b8868b93f12e59ef3..041bcf48cc5c7613d072cf50eae142a21d31153e 100644 ---- a/scripts/Makefile -+++ b/scripts/Makefile -@@ -34,6 +34,7 @@ targets += module.lds - - subdir-$(CONFIG_GCC_PLUGINS) += gcc-plugins - subdir-$(CONFIG_MODVERSIONS) += genksyms -+subdir-$(CONFIG_CTF) += dwarf2ctf - subdir-$(CONFIG_SECURITY_SELINUX) += selinux - - # Let clean descend into subdirs -diff --git a/scripts/Makefile.modbuiltin b/scripts/Makefile.modbuiltin -new file mode 100644 -index 0000000000000000000000000000000000000000..f2c085e8640fbe9d245fb91713c31379f10bcb59 ---- /dev/null -+++ b/scripts/Makefile.modbuiltin -@@ -0,0 +1,60 @@ -+# SPDX-License-Identifier: GPL-2.0 -+# ========================================================================== -+# Generating modules_thick.builtin -+# ========================================================================== -+ -+src := $(obj) -+ -+PHONY := __modbuiltin -+__modbuiltin: -+ -+include include/config/auto.conf -+# tristate.conf sets tristate variables to uppercase 'Y' or 'M' -+# That way, we get the list of built-in modules in obj-Y -+include include/config/tristate.conf -+ -+include scripts/Kbuild.include -+ -+ifdef building_out_of_srctree -+# Create output directory if not already present -+_dummy := $(shell [ -d $(obj) ] || mkdir -p $(obj)) -+endif -+ -+# The filename Kbuild has precedence over Makefile -+kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src)) -+kbuild-file := $(if $(wildcard $(kbuild-dir)/Kbuild),$(kbuild-dir)/Kbuild,$(kbuild-dir)/Makefile) -+include $(kbuild-file) -+ -+include scripts/Makefile.lib -+__subdir-Y := $(patsubst %/,%,$(filter %/, $(obj-Y))) -+subdir-Y += $(__subdir-Y) -+subdir-ym := $(sort $(subdir-y) $(subdir-Y) $(subdir-m)) -+subdir-ym := $(addprefix $(obj)/,$(subdir-ym)) -+pathobj-Y := $(addprefix $(obj)/,$(obj-Y)) -+ -+modthickbuiltin-subdirs := $(patsubst %,%/modules_thick.builtin, $(subdir-ym)) -+modthickbuiltin-target := $(obj)/modules_thick.builtin -+ -+__modbuiltin: $(obj)/$(builtin-file) $(subdir-ym) -+ @: -+ -+$(modthickbuiltin-target): $(subdir-ym) FORCE -+ $(Q) $(foreach mod-o, $(filter %.o,$(obj-Y)),\ -+ printf "%s:" $(addprefix $(obj)/,$(mod-o)) >> $@; \ -+ printf " %s" $(sort $(strip $(addprefix $(obj)/,$($(mod-o:.o=-objs)) \ -+ $($(mod-o:.o=-y)) $($(mod-o:.o=-Y))))) >> $@; \ -+ printf "\n" >> $@; ) \ -+ cat /dev/null $(modthickbuiltin-subdirs) >> $@; -+ -+PHONY += FORCE -+ -+FORCE: -+ -+# Descending -+# --------------------------------------------------------------------------- -+ -+PHONY += $(subdir-ym) -+$(subdir-ym): -+ $(Q)$(MAKE) $(modbuiltin)=$@ builtin-file=$(builtin-file) -+ -+.PHONY: $(PHONY) -diff --git a/scripts/Makefile.modfinal b/scripts/Makefile.modfinal -index ae01baf96f4e8038583d994df2348a0b53b8a565..920545d75da9b3248ef47ff1cdc81c981d3637ba 100644 ---- a/scripts/Makefile.modfinal -+++ b/scripts/Makefile.modfinal -@@ -1,11 +1,21 @@ - # SPDX-License-Identifier: GPL-2.0-only - # =========================================================================== --# Module final link -+# Module final link and CTF generation - # =========================================================================== -+# 1) compile all <module>.mod.c files -+# 2) for external modules, generate CTF for the module (there is an extra, -+# externally-invoked target that does this for the entire kernel but does -+# not invoke the rst of the module-building process) -+# 3) final link of the module to a <module.ko> file -+ -+# We need secondary expansion for 'module-ctfs-modular-prereq', below. -+ -+.SECONDEXPANSION: - - PHONY := __modfinal - __modfinal: - -+include include/config/auto.conf - include $(srctree)/scripts/Kbuild.include - - # for c_flags -@@ -27,16 +37,141 @@ quiet_cmd_cc_o_c = CC [M] $@ - %.mod.o: %.mod.c FORCE - $(call if_changed_dep,cc_o_c) - -+# Generate CTF for the entire kernel, or for the module alone if this is a -+# build of an external module. -+ -+# These are overridden below for standalone modules only. -+module-ctfs-modular-prereq = -+module-ctfs-modular = -+module-ctf-flags = -+cmd_touch_ctf = -+ctf-dir = ///.nonexistent -+cmd-touch-ctf = @: -+ -+ifdef CONFIG_CTF -+ -+# This is quite tricky. If called for non-external-modules, dwarf2ctf needs to -+# be told about all the built-in objects as well as all the external modules -- -+# but Makefile.modpost only knows about the latter. So the toplevel makefile -+# emits the names of the built-in objects into a temporary file, which is -+# then catted and its contents used as prerequisites by this rule. -+# -+# We write the names of the object files to be scanned for CTF content into a -+# file, then use that, to avoid hitting command-line length limits. -+ -+ifeq ($(KBUILD_EXTMOD),) -+ctf-dir-mk := -+quiet_cmd_ctf = CTFA -+ cmd_ctf = scripts/dwarf2ctf/dwarf2ctf vmlinux.ctfa $(srctree) objects.builtin modules_thick.builtin $(srctree)/scripts/dwarf2ctf/member.blacklist $(ctf-filelist) -+ctf-builtins := objects.builtin -+ctf-builtins-prereq := $(ctf-builtins) -+ ctf-modules := $(shell find . -name '*.ko' -print) -+ctf-filelist := .ctf.filelist -+ctf-filelist-raw := .ctf.filelist.raw -+ctf-stamp := -+ -+else -+ctf-dir := $(KBUILD_EXTMOD)/.ctf -+ctf-dir-mk := $(ctf-dir) -+quiet_cmd_ctf = CTF -+ cmd_ctf = scripts/dwarf2ctf/dwarf2ctf $(ctf-dir) -e $(ctf-filelist) -+ctf-builtins := ////.no-builtins -+ctf-builtins-prereq := -+ctf-modules := $(modules:.ko=.o) -+ctf-filelist := $(ctf-dir)/$(notdir $(M)-extmod).ctf.filelist -+ctf-filelist-raw := $(ctf-dir)/$(notdir $(M)-extmod).ctf.filelist.raw -+ctf-stamp = $(ctf-dir)/$(notdir $(M)-extmod).stamp -+ -+# All the modules' CTF depends on the stamp file. -+ -+all-module-ctfs = $(addprefix $(ctf-dir)/,$(notdir $(modules:.ko=.mod.ctf))) -+$(all-module-ctfs): $(ctf-stamp) -+ -+endif -+ -+# Split a list up like shell xargs does. -+define xargs = -+$(1) $(wordlist 1,1024,$(2)) -+$(if $(word 1025,$(2)),$(call xargs,$(1),$(wordlist 1025,$(words $(2)),$(2)))) -+endef -+ -+$(ctf-filelist-raw): $(ctf-builtins-prereq) $(ctf-modules) -+ @rm -f $(ctf-filelist-raw); -+ @if [ -n "$(ctf-dir-mk)" ]; then \ -+ mkdir -p "$(ctf-dir-mk)"; \ -+ fi -+ $(call xargs,@printf "%s\n" >> $(ctf-filelist-raw),$^) -+ @touch $(ctf-filelist-raw) -+ -+$(ctf-filelist): $(ctf-filelist-raw) -+ @rm -f $(ctf-filelist); -+ @cat $(ctf-filelist-raw) | while read -r obj; do \ -+ case $$obj in \ -+ $(ctf-builtins)) cat $$obj >> $(ctf-filelist);; \ -+ *.a) ar t $$obj > $(ctf-filelist);; \ -+ *.builtin) cat $$obj >> $(ctf-filelist);; \ -+ *) echo "$$obj" >> $(ctf-filelist);; \ -+ esac; \ -+ done -+ @touch $(ctf-filelist) -+ -+ifeq ($(KBUILD_EXTMOD),) -+# The CTF depends on the output CTF file list, and that depends -+# on the .ko files for the modules. -+vmlinux.ctfa: $(ctf-filelist) -+ $(call if_changed,ctf) -+else -+ -+# The CTF depends on the output CTF file list, and that depends -+# on the .o files for the modules -+$(ctf-stamp): $(ctf-filelist) -+ $(call if_changed,ctf) -+ @shopt -s nullglob; \ -+ for name in $(ctf-dir)/*.ctf.new; do \ -+ $(srctree)/scripts/move-if-change $$name $${name%.new}; \ -+ done; \ -+ touch $(ctf-stamp) -+ -+# Expands to the names of the CTF files to be incorporated into this module. -+# The former is used in prerequisite lists, thanks to secondary expansion. -+ -+module-ctfs-modular-prereq = $$(addprefix $(ctf-dir)/,$$(notdir $$*.mod.ctf)) -+module-ctfs-modular = $(addprefix $(ctf-dir)/,$(notdir $*.mod.ctf)) -+ -+# Expands to the name of a CTF file, given a target of a module name given to -+# one of the link rules below. -+ -+ctf-module-name = $(addprefix $(ctf-dir)/,$(notdir $(basename $@)).mod.ctf) -+ -+# An objcopy --add-section argument to add the CTF section to a standalone -+# module. -+ -+module-ctf-flags = --add-section .ctf=$(ctf-module-name) -+ -+# We have to put content in our dummy no-CTF files because --add-section -+# in binutils 2.20 silently fails if asked to add an empty file as a section. -+ -+cmd_touch_ctf = @for name in $(filter $(ctf-dir)/%,$(module-ctfs-modular)); do \ -+ test -f $$name || dd if=/dev/zero of=$$name bs=1 count=1 2>/dev/null; \ -+ done -+ -+endif # KBUILD_EXTMOD -+ -+endif # !CONFIG_CTF -+ - ARCH_POSTLINK := $(wildcard $(srctree)/arch/$(SRCARCH)/Makefile.postlink) - - quiet_cmd_ld_ko_o = LD [M] $@ - cmd_ld_ko_o = \ - $(LD) -r $(KBUILD_LDFLAGS) \ - $(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \ -- -T scripts/module.lds -o $@ $(filter %.o, $^); \ -+ -T scripts/module.lds $(LDFLAGS_$(modname)) -o $@.tmp \ -+ $(patsubst $(ctf-dir)/%,,$(filter %.o, $^)) && \ -+ $(OBJCOPY) $(module-ctf-flags) $@.tmp $@ && rm -f $@.tmp ; \ - $(if $(ARCH_POSTLINK), $(MAKE) -f $(ARCH_POSTLINK) $@, true) - --$(modules): %.ko: %.o %.mod.o scripts/module.lds FORCE -+$(modules): %.ko: %.o %.mod.o scripts/module.lds $(module-ctfs-modular-prereq) FORCE -+ $(call cmd_touch_ctf) - +$(call if_changed,ld_ko_o) - - targets += $(modules) $(modules:.ko=.mod.o) -diff --git a/scripts/dwarf2ctf/.gitignore b/scripts/dwarf2ctf/.gitignore -new file mode 100644 -index 0000000000000000000000000000000000000000..e37b47cf30280844fdb1c4bcfa512fa854f3636c ---- /dev/null -+++ b/scripts/dwarf2ctf/.gitignore -@@ -0,0 +1 @@ -+dwarf2ctf -diff --git a/scripts/dwarf2ctf/Makefile b/scripts/dwarf2ctf/Makefile -new file mode 100644 -index 0000000000000000000000000000000000000000..2b40419add316fd20f7171b4b9415ca8550cd50a ---- /dev/null -+++ b/scripts/dwarf2ctf/Makefile -@@ -0,0 +1,10 @@ -+ifdef CONFIG_CTF -+hostprogs-always-$(CONFIG_CTF) := dwarf2ctf -+ -+dwarf2ctf-objs := dwarf2ctf.o eu_simple.o -+ -+HOSTCFLAGS_eu_simple.o := -I$(srctree)/scripts -+HOSTCFLAGS_dwarf2ctf.o := $(shell pkg-config --cflags glib-2.0) -I$(srctree)/scripts -+ -+HOSTLDLIBS_dwarf2ctf := -ldtrace-ctf -lelf -ldw $(shell pkg-config --libs glib-2.0) -lz -+endif -diff --git a/scripts/dwarf2ctf/dwarf2ctf.c b/scripts/dwarf2ctf/dwarf2ctf.c -new file mode 100644 -index 0000000000000000000000000000000000000000..ecd430174442c7882236de086d5d9160ac1974e9 ---- /dev/null -+++ b/scripts/dwarf2ctf/dwarf2ctf.c -@@ -0,0 +1,4962 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * dwarf2ctf.c: Read in DWARF[23] debugging information from some set of ELF -+ * files, and generate CTF in correspondingly-named files, or in a single -+ * representation meant for mmapping. -+ * -+ * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#define _GNU_SOURCE 1 -+#include <stdio.h> -+#include <stdlib.h> -+#include <string.h> -+#include <errno.h> -+#include <stddef.h> -+#include <sys/stat.h> -+#include <sys/types.h> -+#include <fcntl.h> -+#include <limits.h> -+#include <endian.h> -+#include <unistd.h> -+ -+#include <libelf.h> -+#include <dwarf.h> -+#include <elfutils/libdwfl.h> -+#include <elfutils/libdw.h> -+#include <elfutils/version.h> -+#include <sys/ctf_api.h> -+#include <glib.h> -+ -+#include <eu_simple.h> -+ -+#ifndef PATH_MAX -+#define PATH_MAX 1024 -+#endif -+ -+#define __unused__ __attribute__((__unused__)) -+ -+/* -+ * If non-NULL, tracing is on. -+ */ -+static const char *trace; -+ -+/* -+ * Trace something. -+ */ -+#ifdef DEBUG -+#define dw_ctf_trace(format, ...) do { \ -+ if (trace) \ -+ fprintf(stderr, (format), ## __VA_ARGS__); \ -+} while (0) -+#else -+#define dw_ctf_trace(format, ...) -+#endif -+ -+/* -+ * Run dwarf2ctf over a single object file or set thereof. -+ * -+ * output_dir is the directory into which the CTF goes, if 'standalone', or the -+ * CTF archive file name otherwise. -+ */ -+static void run(char *output, int standalone); -+ -+/* -+ * Whether we are deduplicating. We do not deduplicate if run over external -+ * modules. -+ */ -+static int deduplicating; -+ -+/* -+ * A fully descriptive CTF type ID: both file and type ID in one place. -+ */ -+struct ctf_full_id { -+ ctf_file_t *ctf_file; -+ ctf_id_t ctf_id; -+#ifdef DEBUG -+ char module_name[PATH_MAX]; -+ char file_name[PATH_MAX]; -+#endif -+}; -+ -+/* -+ * A hash mapping 'atoms' (almost entirely type IDs) to nothing. -+ */ -+static GHashTable *atoms; -+ -+/* -+ * A mapping from the type ID of a DIE (see type_id()) to ctf_full_id_t's -+ * describing the type with that ID. The type ID is an atom. -+ * -+ * This is used to look up types regardless of which CTF file they may reside -+ * in. Not the same as a DWARF4 type signature because we must encode scope -+ * information which DWARF4 can encode in its DIE refs. -+ * -+ * (TODO: store a hash of the ID rather than the ID itself, to save memory. -+ * Makes debugging slightly harder though.) -+ */ -+static GHashTable *id_to_type; -+ -+/* -+ * A mapping from the type ID of a DIE (an atom) to the name of the module (and -+ * thus CTF table) incorporating that type. (Modules in this context, and -+ * throughout dwarf2ctf, are DTrace modules: a name without suffix or path.) -+ * -+ * This is used to merge types identical across modules (e.g. those in global -+ * header files). -+ */ -+static GHashTable *id_to_module; -+ -+/* -+ * Module-specific state. The module named 'vmlinux' is that corresponding to -+ * the types in always-built-in translation units; the module named 'shared_ctf' -+ * (not appearing in this mapping) is that corresponding to types shared between -+ * more than one module (even between two currently-built-in modules: we do not -+ * distinguish at this level between built-in modules and non-built-in modules.) -+ */ -+static GHashTable *per_module; -+ -+/* -+ * The data structure that per_module maps module names to. -+ */ -+struct per_module { -+ /* -+ * The CTF file containing the types in this module. -+ */ -+ ctf_file_t *ctf_file; -+ -+ /* -+ * A hash from a "CTF-form" structure name (in the form 's/u NAME') to -+ * a struct ctf_memb_count (see below). -+ */ -+ GHashTable *member_counts; -+}; -+ -+/* -+ * A count associating a type ID relating to a structure or union with a count -+ * of members in that structure. -+ */ -+struct ctf_memb_count { -+ ctf_id_t ctf_id; -+ size_t count; -+}; -+ -+/* -+ * A mapping from the absolute pathname of a TU to a hashtable mapping -+ * DIE offsets of child DIEs to DIE offsets of parents. Populated on first -+ * iteration. Contains only those DIEs that we know are necessary for other -+ * functions' use of this structure, to keep memory usage down. -+ */ -+static GHashTable *fn_to_die_to_parent; -+ -+/* -+ * Get a ctf_file out of the per_module hash for a given module. -+ */ -+static ctf_file_t *lookup_ctf_file(const char *module_name); -+ -+/* -+ * The names of the object files to run over. Except in -e mode, this comes -+ * straight from the module filelist passed in. -+ */ -+static char **object_names; -+static size_t object_names_cnt; -+ -+/* -+ * Populate the object_names list from the module filelist. -+ */ -+static void init_object_names(const char *object_names_file); -+ -+/* -+ * Populate and object_to_module from the objects.builtin and modules.builtin -+ * file. -+ */ -+static void init_builtin(const char *builtin_objects_file, -+ const char *builtin_module_file); -+ -+/* -+ * The member blacklist bans fields with specific names in specifically named -+ * structures, declared in specific source files, from being emitted. The -+ * mapping is from absolute source file name:structure.member to NULL (this is -+ * safe because type names cannot contain a colon, and structure names cannot -+ * contain a period). -+ */ -+static GHashTable *member_blacklist; -+ -+/* -+ * Populate the member blacklist from the member_blacklist file. -+ */ -+static void init_member_blacklist(const char *member_blacklist_file, -+ const char *srcdir); -+ -+/* -+ * Return 1 if a given DWARF DIE, which must be a DW_TAG_member, appears in the -+ * member blacklist. -+ */ -+static int member_blacklisted(Dwarf_Die *die, Dwarf_Die *parent_die); -+ -+/* -+ * The variable blacklist, like the others, is an automatically-maintained -+ * blacklist giving variables in specific modules which should not be emitted. -+ * (These are variables whose names are ambiguous within a module, and may -+ * appear multiple times in /proc/kallmodsyms, identical but for address and -+ * thus indistinguishable.) -+ * -+ * The mapping is from module`variable to NULL (safe because variable names -+ * cannot begin with a backtick, and even if they could DTrace's notation could -+ * not reference such variables). -+ */ -+static GHashTable *variable_blacklist; -+ -+/* -+ * A mapping from object file name to the name of the module that translation -+ * unit is part of. -+ * -+ * Actual, real, on-disk .ko modules do not appear here, because the translation -+ * is trivial for them. -+ */ -+static GHashTable *object_to_module; -+ -+/* -+ * Initialize a CTF type table, and possibly fill it with those special types -+ * that appear in CTF but not in DWARF (such as 'void'). (This filling happens -+ * only for the type table named "shared_ctf", unless deduplication is turned -+ * off.) -+ * -+ * If this is a local type table, and deduplication is active, make the global -+ * type table its parent. -+ */ -+static void init_ctf_table(const char *module_name); -+ -+/* -+ * A few useful singleton CTF type IDs in the global type table: a void pointer -+ * and a function pointer. Constructed by init_ctf_table(). -+ */ -+static ctf_id_t ctf_void_type; -+static ctf_id_t ctf_funcptr_type; -+ -+/* -+ * Initialize the child->parent DIE mapping for a single file. -+ */ -+static void init_parent_die(const char *file_name, Dwfl *dwfl); -+ -+/* -+ * Initialize one layer of a child->parent mapping. -+ */ -+static int init_parent_die_internal(const char *file_name, -+ GHashTable *offs, Dwarf_Die *parent, -+ int depth, int found_subprogram); -+ -+/* -+ * Override the presence and value of FORM_u/sdata attributes on DWARF DIEs, -+ * either adding to it, or replacing it. -+ * -+ * (Used so that a caller of construct_ctf_id() that wants a type to be created -+ * can override aspects of that type.) -+ * -+ * The 'chain', if set, causes the various private_*() functions that handle -+ * overrides to look back along the chain to find a suitable attribute. The -+ * chain must be set on the last element in the array. The search for -+ * attributes terminates at the first match. -+ * -+ * Note: this is not a particularly generic implementation: a better approach -+ * would be to keep walking the chain on DIE_OVERRIDE_ADD, and keep adding until -+ * we are done: but we have only one user of ADD, and it implements the addition -+ * itself because it is adding to a value from a different DIE: so this added -+ * generality is not needed yet. -+ */ -+struct die_override { -+ int tag; -+ int attribute; -+ enum { DIE_OVERRIDE_REPLACE, DIE_OVERRIDE_ADD } op; -+ Dwarf_Sword value; -+ struct die_override *chain; -+}; -+ -+/* -+ * Compute the type ID of a DWARF DIE (with possibly-overridden attributes) and -+ * return it in a new dynamically-allocated string. -+ * -+ * Optionally, call a callback with the computed ID once we know it (this is a -+ * recursive process, so the callback can be called multiple times as the ID -+ * is built up). -+ * -+ * An ID of NULL indicates that this DIE has no ID and need not be considered. -+ */ -+static char *type_id(Dwarf_Die *die, struct die_override *overrides, -+ void (*fun)(Dwarf_Die *die, -+ const char *id, -+ struct die_override *overrides, -+ void *data), -+ void *data) __attribute__((__warn_unused_result__)); -+ -+/* -+ * Internal: allows flags to be passed to affect one (and only one) type ID -+ * recursion, without affecting other type_id()s launched from the 'fun'. -+ */ -+static char *type_id_internal(Dwarf_Die *die, -+ struct die_override *overrides, -+ void (*fun)(Dwarf_Die *die, -+ const char *id, -+ struct die_override *overrides, -+ void *data), -+ void *data, -+ int flags); -+ -+/* -+ * Internal: generate the type ID for a type DIE. -+ * -+ * If there are no overrides, look for a bit_size and bit_offset and pass them -+ * down as well. -+ */ -+static char *type_id_type_die(Dwarf_Die *die, -+ Dwarf_Die *type_die, -+ struct die_override *overrides, -+ void (*fun)(Dwarf_Die *die, -+ const char *id, -+ struct die_override *overrides, -+ void *data), -+ void *data); -+ -+/* -+ * Convert 'long unsigned int' to 'sizetype'. Internal use within type_id(). -+ */ -+#define TI_COLLAPSE_SIZETYPE 0x1 -+ -+/* -+ * Process a file, calling the dwarf_process function for every type found -+ * therein (even types in functions). Optionally call tu_init() at the start of -+ * each translation unit, and tu_done() at the end. -+ */ -+static void process_file(const char *file_name, -+ void (*dwarf_process)(const char *module_name, -+ const char *file_name, -+ Dwarf_Die *die, -+ Dwarf_Die *parent_die, -+ void *data), -+ void (*tu_init)(const char *module_name, -+ const char *file_name, -+ Dwarf_Die *tu_die, -+ void *data), -+ void (*tu_done)(const char *module_name, -+ const char *file_name, -+ Dwarf_Die *tu_die, -+ void *data), -+ void *data); -+ -+/* -+ * process_file() helper, walking over the top level and picking up types -+ * therein. -+ */ -+static void process_tu_func(const char *module_name, -+ const char *file_name, -+ Dwarf *dwarf, -+ Dwarf_Die *parent_die, -+ Dwarf_Die *die, -+ void (*dwarf_process)(const char *module_name, -+ const char *file_name, -+ Dwarf_Die *die, -+ Dwarf_Die *parent_die, -+ void *data), -+ void *data); -+ -+/* -+ * Records the type ID of interesting types, the files they are contained in, -+ * and their DWARF offset, so they can be found rapidly. -+ * -+ * Used to avoid rescanning files that can contain no duplicates. -+ */ -+struct dedup_id_file { -+ char *file_name; -+ char *id; -+ Dwarf_Off dieoff; -+}; -+ -+/* -+ * The structure used as the data argument for dedup() and -+ * dedup_alias_fixup(). -+ * -+ * structs_seen tracks the IDs of structures marked as duplicates within a given -+ * translation unit, in order that recursion terminates if two such structures -+ * have pointers to each other. -+ * -+ * vars_seen tracks variables seen in this module, mapping from unadorned name -+ * to a non-NULL pointer (for static, non-'external') or NULL (for non-static or -+ * 'extern'). If a static variable coexists with any other variable with the -+ * same name, static or not, the variable is blacklisted. (Non-static -+ * coexistence is fine, because they are just different references to the same -+ * variable). Note that management of this variable is a little annoying -+ * because it varies by module, not by TU, so we can't use tu_init/tu_done to -+ * manage its lifetime. -+ * -+ * named_structs tracks type IDs and contained modules for every type that may -+ * contain undetected duplicates and thus may require rescanning. -+ * -+ * dwfl and dwfl_file_name identify the opened DWARF file (if any) during the -+ * second duplicates detection pass. -+ * -+ * repeat_detection is set by each phase if it considers that another round of -+ * alias fixup detection is needed. -+ */ -+struct dedup_state { -+ const char *file_name; -+ const char *module_name; -+ GHashTable *structs_seen; -+ GList *named_structs; -+ GHashTable *vars_seen; -+ char *dwfl_file_name; -+ Dwarf *dwarf; -+ Dwfl *dwfl; -+ int repeat_detection; -+}; -+ -+/* -+ * Scan and identify duplicates across the entire set of object files. -+ */ -+static void scan_dups(void); -+ -+/* -+ * Recursively detect duplicate types and types referenced by them, and -+ * determine which CTF file they should be located in, and request a -+ * dedup_alias_fixup() pass if any structures are shared. -+ * Determine the mapping from translation unit name to module name. -+ */ -+static void dedup(const char *module_name, const char *file_name, -+ Dwarf_Die *die, Dwarf_Die *parent_die, void *data); -+ -+/* -+ * Do the underlying marking of a DIE as shared, iff need be. (No variable -+ * blacklisting, non-opaque structure checks, or anything else needed only by -+ * top-level DIEs.) -+ * -+ * This function may be called multiple times for overridden DIEs that are -+ * dependent types of bitfields. -+ */ -+static void dedup_mark_inner_die(const char *module_name, Dwarf_Die *die, -+ const char *id, -+ struct die_override *overrides, -+ void *data); -+ -+/* -+ * Note in the dedup_id_file list that we will rescan a DIE in a later duplicate -+ * detection pass. -+ * -+ * A type_id() callback. -+ */ -+static void dedup_will_rescan(Dwarf_Die *die, const char *id, -+ struct die_override *overrides, void *data); -+ -+/* -+ * Note the variable referenced by this DIE in vars_seen: blacklist it if an -+ * entry for this variable already exists in vars_seen and this instance is -+ * static, or if a static entry already exists in vars_seen, whether this -+ * instance is static or not. -+ */ -+static void dedup_blacklist_var_dups(Dwarf_Die *die, -+ struct dedup_state *state); -+ -+/* -+ * Detect duplicates and mark seen types for a given type, via a type_id() -+ * callback: used to detect dependent types (particularly those at child-DIE -+ * level) as duplicates. -+ */ -+static void dedup_typeid(Dwarf_Die *die, const char *id, -+ struct die_override *overrides, void *data); -+ -+/* -+ * Mark any aggregates contained within a particular type DIE as seen. This is -+ * needed since even nameless aggregates contained within other aggregates can -+ * be used as the type of members of the outer aggregate (though they cannot -+ * possibly be found in a module different from that of their containing -+ * aggregate, any more than a structure member can). -+ */ -+static void mark_seen_contained(Dwarf_Die *die, const char *module_name, -+ struct die_override *overrides, void *data); -+ -+/* -+ * Determine if some type (whose ultimate base type is an non-opaque structure, -+ * alias, or enum) has an opaque equivalent which is shared, and mark it and -+ * all its bases as shared too if so. -+ * -+ * A list_filter() filter function. -+ */ -+static int dedup_alias_fixup(void *id_file_data, void *data); -+ -+/* -+ * Mark a basic type shared by name and intern it in all relevant hashes. (Used -+ * for marking basic types we don't have a DIE for.) -+ */ -+static void mark_shared_by_name(ctf_file_t *ctf, ctf_id_t ctf_id, -+ const char *name); -+ -+/* -+ * Determine if a type is a named struct, union, or enum. -+ * -+ * A type_id() callback. -+ */ -+static void is_named_struct_union_enum(Dwarf_Die *die, const char *unused, -+ struct die_override *overrides, -+ void *data); -+ -+/* -+ * Set up state for dedup(). A tu_init() callback. -+ */ -+static void dedup_tu_init(const char *module_name, const char *file_name, -+ Dwarf_Die *tu_die, void *data); -+ -+/* -+ * Free state for dedup(). A tu_done() callback. -+ */ -+static void dedup_tu_done(const char *module_name, const char *file_name, -+ Dwarf_Die *tu_die, void *data); -+ -+/* -+ * Free DWARF state for dedup(). -+ */ -+static void dedup_dwarf_free(struct dedup_state *state); -+ -+/* -+ * Determine if a type is duplicated and needs sharing. -+ */ -+enum needs_sharing { NS_NOT_SHARED, NS_NO_MARKING, NS_NEEDS_SHARING }; -+static enum needs_sharing type_needs_sharing(const char *module_name, -+ const char *id); -+ -+/* -+ * Mark a type (optionally, with an already-known ID) as duplicated and located -+ * in the shared CTF table. -+ * -+ * A type_id() callback (though also called directly). -+ */ -+static void mark_shared(Dwarf_Die *die, const char *id, -+ struct die_override *overrides, void *data); -+ -+/* -+ * Construct CTF out of each type. -+ */ -+static void construct_ctf(const char *module_name, const char *file_name, -+ Dwarf_Die *die, -+ Dwarf_Die *parent_die, -+ void *unused __unused__); -+ -+/* -+ * Write out the CTF files from the per_module->ctf_file into files in the -+ * output directory (if standalone), or into the output file (otherwise). -+ */ -+static void write_types(char *output, int standalone); -+ -+/* -+ * Construct CTF out of each type and return that type's ID and file. -+ */ -+static struct ctf_full_id *construct_ctf_id(const char *module_name, -+ const char *file_name, -+ Dwarf_Die *die, -+ Dwarf_Die *parent_die, -+ struct die_override *overrides); -+ -+/* -+ * Things to do after a CTF recursion step. -+ */ -+enum skip_type { SKIP_CONTINUE = 0, SKIP_SKIP, SKIP_ABORT }; -+ -+/* -+ * Recursive over a given DWARF DIE and its children andconstruct CTF out of it. -+ * -+ * Most parameters are shared with the ctf_assembly_fun: see the comment below. -+ */ -+static ctf_id_t die_to_ctf(const char *module_name, const char *file_name, -+ Dwarf_Die *die, Dwarf_Die *parent_die, -+ ctf_file_t *ctf, ctf_id_t parent_ctf_id, -+ struct die_override *overrides, int top_level_type, -+ int backwards, enum skip_type *skip, int *replace, -+ const char *id); -+ -+/* -+ * Return the next DIE, if that DIE needs to be emitted before this one. -+ */ -+static Dwarf_Die *die_emit_next_backwards(Dwarf_Die *next, Dwarf_Die *die, -+ struct die_override *overrides); -+ -+/* -+ * Look up a type through its reference: return its ctf_id_t, or -+ * recursively construct it if need be. -+ * -+ * Must be called on a DIE with a type attribute. -+ */ -+static ctf_id_t lookup_ctf_type(const char *module_name, const char *file_name, -+ Dwarf_Die *die, ctf_file_t *ctf, -+ struct die_override *overrides, -+ const char *locerrstr); -+ -+/* -+ * Assemble a given DIE and its children into CTF in some fashion, returning the -+ * ID of the top-level piece of generated CTF (only relevant for aggregates). -+ * -+ * The parent_ctf_id is the ID of the CTF entity that was or is being generated -+ * from the enclosing DWARF DIE, or 0 if population succeeded but did not yield -+ * a type ID (e.g. for variable assembly), or -1 on error. The parent_die is -+ * the parent of the current DWARF DIE, and is always populated (even if just -+ * with the CU's DIE). The parent_ctf_id is always in the same CTF file as the -+ * ctf_id, just as the parent DWARF DIE is always in the same DWARF CU: this is -+ * lexical scope, not dynamic, so referenced types themselves located at the top -+ * level have the CU as their parent. -+ * -+ * Returning an error value (see below) indicates that no CTF was generated from -+ * this DWARF DIE. -+ * -+ * Setting skip to SKIP_ABORT indicates that the translation of this entity -+ * failed, and the entire top-level type of which it is a part should be -+ * skipped. Setting it to SKIP_SKIP indicates that this entity does not need to -+ * be translated (perhaps because it already exists), so recursion into -+ * sub-entities can be skipped, but translation of the containing type should -+ * continue. Setting it to SKIP_CONTINUE indicates no error. -+ * -+ * Setting 'replace' to 1 in a child DIE indicates that this type should -+ * entirely *replace* its parent's type (generally because it has wrapped it up -+ * in something). This replacemenu takes immediate effect for later children of -+ * the same DIE. -+ * -+ * die_to_ctf() calls these functions repeatedly for every child of the -+ * requested DIE: the CTF ID eventually returned is whatever ID is returned by -+ * the last such function, and parent_ctf_id is repeatedly replaced with the ID -+ * returned by the last assembly function. Thus, assembly functions that -+ * augment an already-present ctf_id should return parent_ctf_id: assembly -+ * functions that wrap it in a new ctf_id referring to the parent_ctf_id should -+ * return the new ID. (Assembly functions should never entirely disregard the -+ * parent_ctf_id.) -+ */ -+typedef ctf_id_t (*ctf_assembly_fun)(const char *module_name, -+ const char *file_name, -+ Dwarf_Die *die, -+ Dwarf_Die *parent_die, -+ ctf_file_t *ctf, -+ ctf_id_t parent_ctf_id, -+ const char *locerrstr, -+ struct die_override *overrides, -+ int top_level_type, -+ enum skip_type *skip, -+ int *replace); -+ -+#define ASSEMBLY_FUN(name) \ -+ static ctf_id_t assemble_ctf_##name(const char *module_name, \ -+ const char *file_name, \ -+ Dwarf_Die *die, \ -+ Dwarf_Die *parent_die, \ -+ ctf_file_t *ctf, \ -+ ctf_id_t parent_ctf_id, \ -+ const char *locerrstr, \ -+ struct die_override *overrides, \ -+ int top_level_type, \ -+ enum skip_type *skip, \ -+ int *replace) -+ -+/* -+ * Defined assembly functions. -+ */ -+ASSEMBLY_FUN(base); -+ASSEMBLY_FUN(array); -+ASSEMBLY_FUN(array_dimension); -+ASSEMBLY_FUN(cvr_qual); -+ASSEMBLY_FUN(enumeration); -+ASSEMBLY_FUN(enumerator); -+ASSEMBLY_FUN(pointer); -+ASSEMBLY_FUN(struct_union); -+ASSEMBLY_FUN(su_member); -+ASSEMBLY_FUN(typedef); -+ASSEMBLY_FUN(variable); -+ -+/* -+ * An assembly filter is an optional function called with the DIE and parent DIE -+ * of a top-level type alone, before calling down into the process_file() -+ * processing function: it can be used to rapidly determine that this DIE is not -+ * worth processing. (It should return 0 in this case, and nonzero otherwise.) -+ */ -+typedef int (*ctf_assembly_filter_fun)(const char *file_name, -+ Dwarf *dwarf, -+ Dwarf_Die *die, -+ Dwarf_Die *parent_die); -+ -+/* -+ * A CTF assembly filter function which excludes all types not at the global -+ * scope (i.e. whose immediate parent is not a CU DIE) and which does not have a -+ * structure or union as its ultimate dependent type. (All structures and -+ * unions and everything dependent on them must be recorded, even inside -+ * functions, because GCC may emit references to the opaque variants of those -+ * types from file scope.) -+ */ -+static int filter_ctf_file_scope(const char *file_name, -+ Dwarf *dwarf, -+ Dwarf_Die *die, -+ Dwarf_Die *parent_die); -+ -+/* -+ * A CTF assembly filter function which excludes all names not at the global -+ * scope, all static symbols, and all names whose names are unlikely to be -+ * interesting. (DTrace userspace contains a similar list, but the two lists -+ * need not be in sync.) -+ */ -+static int filter_ctf_uninteresting(const char *file_name, -+ Dwarf *dwarf, -+ Dwarf_Die *die, -+ Dwarf_Die *parent_die); -+ -+/* -+ * Error return values from CTF assembly functions. These differ only in that -+ * die_to_ctf() reports the ctf_errmsg() if CTF_NO_ERROR_REPORTED is returned, -+ * but says nothing in the CTF_ERROR_REPORTED case. -+ */ -+#define CTF_NO_ERROR_REPORTED CTF_ERR -+#define CTF_ERROR_REPORTED (-2L) -+ -+/* -+ * The total number of type errors encountered. -+ */ -+static long num_errors; -+ -+/* -+ * A mapping from DW_TAG_* to functions which assemble this DW_TAG_* and -+ * possibly its children into the passed CTF. This table is not used -+ * directly, but rather assembled into a lookup table. -+ */ -+static struct assembly_tab_t -+{ -+ int tag; -+ ctf_assembly_filter_fun filter; -+ ctf_assembly_fun fun; -+} assembly_tab_init[] = -+{{ DW_TAG_base_type, filter_ctf_file_scope, assemble_ctf_base }, -+ { DW_TAG_array_type, filter_ctf_file_scope, assemble_ctf_array }, -+ { DW_TAG_subrange_type, NULL, assemble_ctf_array_dimension }, -+ { DW_TAG_const_type, filter_ctf_file_scope, assemble_ctf_cvr_qual }, -+ { DW_TAG_restrict_type, filter_ctf_file_scope, assemble_ctf_cvr_qual }, -+ { DW_TAG_enumeration_type, NULL, assemble_ctf_enumeration }, -+ { DW_TAG_enumerator, NULL, assemble_ctf_enumerator }, -+ { DW_TAG_pointer_type, filter_ctf_file_scope, assemble_ctf_pointer }, -+ { DW_TAG_structure_type, NULL, assemble_ctf_struct_union }, -+ { DW_TAG_union_type, NULL, assemble_ctf_struct_union }, -+ { DW_TAG_member, NULL, assemble_ctf_su_member }, -+ { DW_TAG_typedef, NULL, assemble_ctf_typedef }, -+ { DW_TAG_variable, filter_ctf_uninteresting, assemble_ctf_variable }, -+ { DW_TAG_volatile_type, filter_ctf_file_scope, assemble_ctf_cvr_qual }, -+ { 0, NULL }}; -+ -+/* -+ * The CTF assembly and filter lookup tables, in constructed form. -+ */ -+static ctf_assembly_fun *assembly_tab; -+static ctf_assembly_filter_fun *assembly_filter_tab; -+static size_t assembly_len; -+ -+/* -+ * Populate the assembly_tab and assembly_filter_tab from the assembly_tab_init. -+ */ -+static void init_assembly_tab(void); -+ -+/* -+ * A mapping from sizeof() to CTF type encoding. -+ */ -+struct type_encoding_tab { -+ size_t size; -+ int ctf_encoding; -+}; -+ -+/* -+ * Given a type encoding table, and a size, return the CTF encoding for that -+ * type, or 0 if none. -+ */ -+static int find_ctf_encoding(struct type_encoding_tab *type_tab, size_t size); -+ -+/* -+ * Count the number of members of a DWARF aggregate. -+ */ -+static long count_dwarf_members(Dwarf_Die *die); -+ -+/* -+ * Given a DIE that may contain a type attribute, look up the target of that -+ * attribute and return it, or NULL if none. -+ */ -+static Dwarf_Die *private_dwarf_type(Dwarf_Die *die, Dwarf_Die *target_die); -+ -+/* -+ * Check for existence of an attribute in a DIE, chasing through -+ * DW_AT_specification if need be. -+ */ -+static inline int private_dwarf_hasattr(Dwarf_Die *die, -+ unsigned int search_name); -+ -+/* -+ * Return a DIE attribute, chasing through DW_AT_specification if need be. -+ */ -+static inline Dwarf_Attribute *private_dwarf_attr(Dwarf_Die *die, -+ unsigned int search_name, -+ Dwarf_Attribute *result); -+ -+/* -+ * Given a DIE that contains a udata attribute, look up that attribute and -+ * return its value (optionally overridden or modified by the die_overrides). -+ */ -+static inline Dwarf_Word private_dwarf_udata(Dwarf_Die *die, int attribute, -+ struct die_override *overrides); -+ -+/* -+ * Given a DIE, return its byte size, if known and interpretable, or -1 -+ * otherwise. -+ */ -+static inline long long private_dwarf_size(Dwarf_Die *die); -+ -+/* -+ * Find an override in an override list. -+ */ -+static struct die_override * -+private_find_override(Dwarf_Die *die, -+ int attribute, -+ struct die_override *overrides); -+ -+/* -+ * Determine the dimensions of an array subrange, or 0 if variable. -+ */ -+static Dwarf_Word private_subrange_dimensions(Dwarf_Die *die); -+ -+/* -+ * A string appender working on dynamic strings. -+ */ -+static char *str_append(char *s, const char *append) -+ __attribute__((__warn_unused_result__)); -+ -+/* -+ * A vararg string appender. -+ */ -+static char *str_appendn(char *s, ...) -+ __attribute__((__warn_unused_result__, sentinel)); -+ -+/* -+ * An error-checking strdup(). -+ */ -+static char *xstrdup(const char *s) __attribute__((__nonnull__, -+ __warn_unused_result__, -+ __malloc__)); -+ -+/* -+ * Filter a GList, calling a predicate on it and removing all elements for which -+ * the predicate returns true, calling the free_func on them if set. -+ */ -+typedef int (*filter_pred_fun) (void *element, void *data); -+static GList *list_filter(GList *list, filter_pred_fun fun, -+ GDestroyNotify free_func, void *data); -+ -+/* -+ * Intern an atom in the atoms table and return it, or free it and return the -+ * existing atom if one is already interned. (Despite the type signature, this -+ * return value is constant and should not be freed.) -+ */ -+static void *intern(char *atom); -+ -+/* -+ * Figure out the (pathless, suffixless) module name for a given module file (.o -+ * or .ko), and return it in a new dynamically allocated string. -+ * -+ * Takes the object_to_module mapping into account. -+ */ -+static char *fn_to_module(const char *file_name); -+ -+/* -+ * Determine, and cache, absolute filenames. -+ */ -+static const char *abs_file_name(const char *file_name); -+ -+/* -+ * Determine absolute filenames relative to some other directory: do not cache -+ * them. It is the caller's responsibility to free them. -+ */ -+static char *rel_abs_file_name(const char *file_name, const char *relative_to); -+ -+/* -+ * Free a per_module's contents. -+ */ -+static void private_per_module_free(void *per_module); -+ -+/* -+ * Free a dedup_id_file's contents. -+ */ -+static void free_dups_id_file(void *id_file); -+ -+/* -+ * Free a fn_to_die_to_parent subhash. -+ */ -+static void private_fn_die_parent_free(void *ptr); -+ -+/* -+ * dwarf_dieoffset() with a return type better for printf(). -+ */ -+#define DIEOFFSET(die) (unsigned long) dwarf_dieoffset((die)) -+ -+/* -+ * A line-shortener with a kernel-familiar name for fprintfing to stderr. -+ */ -+#define pr_err(fmt, ...) fprintf(stderr, fmt, ## __VA_ARGS__); -+ -+/* Initialization. */ -+ -+int main(int argc, char *argv[]) -+{ -+ char *output; -+ -+ trace = getenv("DWARF2CTF_TRACE"); -+ -+ if ((argc != 4 && argc != 7) || -+ (argc == 4 && strcmp(argv[2], "-e") != 0)) { -+ pr_err("Syntax: dwarf2ctf output-file srcdir objects.builtin\n"); -+ pr_err(" modules.builtin member.blacklist filelist\n"); -+ pr_err(" or dwarf2ctf output-dir -e filelist\n" -+ "for external module use\n"); -+ exit(1); -+ } -+ -+ output = argv[1]; -+ -+ elf_version(EV_CURRENT); -+ -+ if (elf_errno()) { -+ pr_err("Version synchronization fault: %s\n", -+ elf_errmsg(elf_errno())); -+ exit(1); -+ } -+ -+ init_assembly_tab(); -+ object_to_module = g_hash_table_new_full(g_str_hash, g_str_equal, -+ free, free); -+ -+ /* -+ * When not building an external module, we run over all the arguments -+ * at once, deduplicating them. In external-module mode, we act as if -+ * independently invoked with every argument. -+ */ -+ if (strcmp(argv[2], "-e") != 0) { -+ const char *srcdir; -+ char *builtin_objects_file; -+ char *builtin_module_file; -+ char *member_blacklist_file; -+ -+ srcdir = argv[2]; -+ builtin_objects_file = argv[3]; -+ builtin_module_file = argv[4]; -+ member_blacklist_file = argv[5]; -+ deduplicating = 1; -+ -+ init_builtin(builtin_objects_file, builtin_module_file); -+ init_member_blacklist(member_blacklist_file, srcdir); -+ init_object_names(argv[6]); -+ -+ run(output, 0); -+ } else { -+ char *single_object_name; -+ char **all_object_names; -+ size_t all_object_names_cnt; -+ size_t i; -+ -+ deduplicating = 0; -+ init_object_names(argv[3]); -+ -+ /* -+ * Repeatedly populate object_names with one object name, and -+ * call run() with that. -+ */ -+ all_object_names = object_names; -+ all_object_names_cnt = object_names_cnt; -+ object_names = &single_object_name; -+ object_names_cnt = 1; -+ -+ for (i = 0; i < all_object_names_cnt; i++) { -+ single_object_name = all_object_names[i]; -+ -+ run(output, 1); -+ } -+ } -+ -+ g_hash_table_destroy(object_to_module); -+ -+ if (num_errors > 0) -+ pr_err("%li CTF construction errors.\n", num_errors); -+ -+ return 0; -+} -+ -+/* -+ * Run dwarf2ctf over a single object file or set thereof. -+ * -+ * output is the directory into which the CTF goes, if 'standalone', or the -+ * CTF archive file name otherwise. -+ */ -+static void run(char *output, int standalone) -+{ -+ size_t i; -+ -+ /* -+ * Create all the hashes, assemble the translation unit->module list for -+ * builtin modules, and create the shared CTF file if deduplicating. -+ */ -+ -+ atoms = g_hash_table_new_full(g_str_hash, g_str_equal, free, NULL); -+ id_to_type = g_hash_table_new_full(g_str_hash, g_str_equal, -+ NULL, free); -+ id_to_module = g_hash_table_new_full(g_str_hash, g_str_equal, -+ NULL, free); -+ per_module = g_hash_table_new_full(g_str_hash, g_str_equal, free, -+ private_per_module_free); -+ variable_blacklist = g_hash_table_new_full(g_str_hash, g_str_equal, -+ free, free); -+ fn_to_die_to_parent = g_hash_table_new_full(g_str_hash, -+ g_str_equal, free, -+ private_fn_die_parent_free); -+ -+ dw_ctf_trace("Initializing...\n"); -+ -+ if (deduplicating) -+ init_ctf_table("shared_ctf"); -+ -+ scan_dups(); -+ -+ /* -+ * Now construct CTF out of the types. -+ */ -+ dw_ctf_trace("CTF construction.\n"); -+ for (i = 0; i < object_names_cnt; i++) -+ process_file(object_names[i], construct_ctf, NULL, NULL, NULL); -+ -+ /* -+ * Finally, emit the types into their .ctf files, and generate the -+ * necessary linker scripts. -+ */ -+ dw_ctf_trace("Writeout.\n"); -+ write_types(output, standalone); -+ -+ g_hash_table_destroy(id_to_type); -+ g_hash_table_destroy(id_to_module); -+ g_hash_table_destroy(per_module); -+ g_hash_table_destroy(variable_blacklist); -+ g_hash_table_destroy(fn_to_die_to_parent); -+ g_hash_table_destroy(atoms); -+} -+ -+/* -+ * Populate the object_names list from the module filelist. -+ */ -+static void init_object_names(const char *object_names_file) -+{ -+ FILE *f; -+ char *line = NULL; -+ size_t line_size = 0; -+ -+ f = fopen(object_names_file, "r"); -+ if (f == NULL) { -+ pr_err("Cannot open object names file %s: %s\n", -+ object_names_file, strerror(errno)); -+ exit(1); -+ } -+ -+ /* -+ * This needs no massaging other than linefeed removal, just reading and -+ * stashing. -+ */ -+ -+ while (getline(&line, &line_size, f) >= 0) { -+ size_t len = strlen(line); -+ -+ if (len == 0) -+ continue; -+ -+ if (line[len-1] == '\n') -+ line[len-1] = '\0'; -+ -+ object_names = realloc(object_names, -+ ++object_names_cnt * -+ sizeof(char *)); -+ -+ if (object_names == NULL) { -+ pr_err("Out of memory reading %s\n", object_names_file); -+ exit(1); -+ } -+ -+ object_names[object_names_cnt-1] = xstrdup(line); -+ } -+ free(line); -+ -+ if (ferror(f)) { -+ pr_err("Error reading from %s: %s\n", object_names_file, -+ strerror(errno)); -+ exit(1); -+ } -+ -+ fclose(f); -+} -+ -+/* -+ * Populate object_to_module from the objects.builtin and modules.builtin file. -+ */ -+static void init_builtin(const char *builtin_objects_file, -+ const char *builtin_module_file) -+{ -+ FILE *f; -+ struct modules_thick_iter *i; -+ char *line = NULL; -+ size_t line_size = 0; -+ char *module_name = NULL; -+ char **paths; -+ -+ /* -+ * Iterate over all modules in modules_thick.builtin and add each to -+ * object_to_module. -+ */ -+ i = modules_thick_iter_new(builtin_module_file); -+ if (i == NULL) { -+ pr_err("Cannot iterate over builtin module file.\n"); -+ exit(1); -+ } -+ -+ while ((paths = modules_thick_iter_next(i, &module_name)) != NULL) { -+ size_t j; -+ -+ for (j = 0; paths[j] != NULL; j++) { -+ dw_ctf_trace("noting built-in module mapping %s -> %s\n", -+ module_name, paths[j]); -+ g_hash_table_replace(object_to_module, -+ strdup(paths[j]), -+ xstrdup(module_name)); -+ } -+ free(paths); -+ } -+ free(module_name); -+ modules_thick_iter_free(i); -+ -+ f = fopen(builtin_objects_file, "r"); -+ if (f == NULL) { -+ pr_err("Cannot open builtin objects file %s: %s\n", -+ builtin_objects_file, strerror(errno)); -+ exit(1); -+ } -+ -+ /* -+ * Those entries in builtin.objects that are not already known are -+ * unconditionally-built-in object files. -+ */ -+ while (getline(&line, &line_size, f) >= 0) { -+ size_t len = strlen(line); -+ -+ if (len == 0) -+ continue; -+ -+ if (line[len-1] == '\n') -+ line[len-1] = '\0'; -+ -+ if (!g_hash_table_lookup(object_to_module, line)) -+ g_hash_table_replace(object_to_module, xstrdup(line), -+ xstrdup("vmlinux")); -+ } -+ -+ if (ferror(f)) { -+ pr_err("Error reading from %s: %s\n", builtin_objects_file, -+ strerror(errno)); -+ exit(1); -+ } -+ -+ free(line); -+ fclose(f); -+} -+ -+/* -+ * Translate the assembly lookup table into the assembly_tab and -+ * assembly_filter_tab arrays. -+ */ -+static void init_assembly_tab(void) -+{ -+ struct assembly_tab_t *walk; -+ -+ for (walk = assembly_tab_init; walk->fun != NULL; walk++) { -+ if (assembly_len < walk->tag) -+ assembly_len = walk->tag; -+ } -+ assembly_len++; -+ -+ assembly_tab = calloc(sizeof(ctf_assembly_fun *), assembly_len); -+ assembly_filter_tab = calloc(sizeof(ctf_assembly_filter_fun *), -+ assembly_len); -+ if ((assembly_tab == NULL) || (assembly_filter_tab == NULL)) { -+ pr_err("Out of memory allocating assembly table\n"); -+ exit(1); -+ } -+ -+ for (walk = assembly_tab_init; walk->fun != NULL; walk++) { -+ assembly_tab[walk->tag] = walk->fun; -+ assembly_filter_tab[walk->tag] = walk->filter; -+ } -+} -+ -+/* -+ * Populate the member blacklist from the member_blacklist file. -+ */ -+static void init_member_blacklist(const char *member_blacklist_file, -+ const char *srcdir) -+{ -+ FILE *f; -+ char *line = NULL; -+ size_t line_num = 0; -+ size_t line_size = 0; -+ -+ /* -+ * Not having a member blacklist is not an error. -+ */ -+ f = fopen(member_blacklist_file, "r"); -+ if (f == NULL) -+ return; -+ -+ member_blacklist = g_hash_table_new(g_str_hash, g_str_equal); -+ -+ while (getline(&line, &line_size, f) >= 0) { -+ size_t len = strlen(line); -+ char *last_colon; -+ const char *last_dot; -+ char *absolutized; -+ -+ line_num++; -+ -+ if (len == 0) -+ continue; -+ -+ if (line[len-1] == '\n') -+ line[len-1] = '\0'; -+ -+ last_colon = strrchr(line, ':'); -+ last_dot = strrchr(last_colon + 1, '.'); -+ if (!last_colon || !last_dot) { -+ pr_err("Syntax error on line %li of %s.\n" -+ "Syntax: filename:structure.member.\n", -+ line_num, member_blacklist_file); -+ continue; -+ } -+ -+ *last_colon = '\0'; -+ last_colon++; -+ absolutized = rel_abs_file_name(line, srcdir); -+ absolutized = str_appendn(absolutized, ":", last_colon, NULL); -+ -+ g_hash_table_insert(member_blacklist, absolutized, NULL); -+ } -+ free(line); -+ -+ if (ferror(f)) { -+ pr_err("Error reading from %s: %s\n", member_blacklist_file, -+ strerror(errno)); -+ exit(1); -+ } -+ -+ fclose(f); -+} -+ -+/* -+ * Return 1 if a given DWARF DIE, which must be a DW_TAG_member, appears in the -+ * member blacklist. -+ */ -+static int member_blacklisted(Dwarf_Die *die, Dwarf_Die *parent_die) -+{ -+ const char *fname = dwarf_decl_file(die); -+ char *id; -+ int blacklisted = 0; -+ -+ /* -+ * If there is no member blacklist, do nothing. -+ */ -+ if (!member_blacklist) -+ return 0; -+ -+ /* -+ * Unnamed structure and union members cannot be blacklisted, for now. -+ */ -+ if ((dwarf_diename(parent_die) == NULL) || -+ (dwarf_diename(die) == NULL)) -+ return 0; -+ -+ /* -+ * The compiler can define its own structures, which appear in no -+ * decl_file. -+ * -+ * We can't blacklist them with this mechanism, so skip them. -+ */ -+ if (__builtin_expect(fname == NULL, 0)) -+ return 0; -+ -+ fname = abs_file_name(fname); -+ -+ if (dwarf_tag(die) != DW_TAG_member || -+ (dwarf_tag(parent_die) != DW_TAG_structure_type && -+ dwarf_tag(parent_die) != DW_TAG_union_type)) { -+ pr_err("Warning: member_blacklisted() called on " -+ "%s:%s.%s at offset %li, which is not a structure member.\n", -+ fname, dwarf_diename(parent_die), dwarf_diename(die), -+ DIEOFFSET(die)); -+ return 0; -+ } -+ -+ id = xstrdup(fname); -+ id = str_appendn(id, ":", dwarf_diename(parent_die), ".", -+ dwarf_diename(die), NULL); -+ -+ if (g_hash_table_lookup_extended(member_blacklist, id, NULL, NULL)) -+ blacklisted = 1; -+ -+ free(id); -+ return blacklisted; -+} -+ -+/* -+ * Initialize a CTF type table, and possibly fill it with those special types -+ * that appear in CTF but not in DWARF (such as 'void'). (This filling happens -+ * only for the type table named "shared_ctf", unless deduplication is turned -+ * off.) -+ * -+ * If this is a local type table, and deduplication is active, make the global -+ * type table its parent. -+ */ -+static void init_ctf_table(const char *module_name) -+{ -+ ctf_file_t *ctf_file; -+ struct per_module *new_per_mod; -+ int ctf_err; -+ -+ ctf_file = ctf_create(&ctf_err); -+ if (ctf_file == NULL) { -+ pr_err("Cannot create CTF file: %s\n", strerror(ctf_err)); -+ exit(1); -+ } -+ new_per_mod = malloc(sizeof(struct per_module)); -+ if (new_per_mod == NULL) { -+ pr_err("Out of memory allocating per-module CTF info\n"); -+ exit(1); -+ } -+ -+ new_per_mod->ctf_file = ctf_file; -+ new_per_mod->member_counts = g_hash_table_new_full(g_str_hash, -+ g_str_equal, -+ free, free); -+ g_hash_table_replace(per_module, xstrdup(module_name), new_per_mod); -+ -+ dw_ctf_trace("Initializing module: %s\n", module_name); -+ if ((strcmp(module_name, "shared_ctf") == 0) || -+ !deduplicating) { -+ ctf_encoding_t void_encoding = { CTF_INT_SIGNED, 0, 0 }; -+ ctf_encoding_t int_encoding = { CTF_INT_SIGNED, 0, -+ sizeof(int) * 8 }; -+ ctf_id_t int_type; -+ ctf_id_t func_type; -+ ctf_funcinfo_t func_info; -+ -+ /* -+ * Global types module, or deduplication is disabled. Add a -+ * type for 'void *' to point to, and a type for the return -+ * value of pointers to functions: then add the (single, -+ * universal) pointer-to-function value. -+ */ -+ ctf_void_type = ctf_add_integer(ctf_file, CTF_ADD_ROOT, -+ "void", &void_encoding); -+ int_type = ctf_add_integer(ctf_file, CTF_ADD_ROOT, "int", -+ &int_encoding); -+ mark_shared_by_name(ctf_file, ctf_void_type, "void"); -+ mark_shared_by_name(ctf_file, int_type, "int"); -+ -+ func_info.ctc_return = int_type; -+ func_info.ctc_argc = 0; -+ func_info.ctc_flags = 0; -+ func_type = ctf_add_function(ctf_file, CTF_ADD_ROOT, -+ &func_info, NULL); -+ ctf_funcptr_type = ctf_add_pointer(ctf_file, CTF_ADD_ROOT, -+ func_type); -+ -+ if (ctf_update(ctf_file) < 0) { -+ pr_err("Cannot initialize shared CTF file: %s\n", -+ ctf_errmsg(ctf_errno(ctf_file))); -+ exit(1); -+ } -+ } else { -+ /* -+ * Local types module with deduplication enabled: point the -+ * parent at the global CTF file, which must exist by this -+ * point. -+ */ -+ if (ctf_import(ctf_file, lookup_ctf_file("shared_ctf")) < 0) { -+ pr_err("Cannot set parent of CTF file for module %s: %s\n", -+ module_name, ctf_errmsg(ctf_errno(ctf_file))); -+ exit(1); -+ } -+ ctf_parent_name_set(ctf_file, "shared_ctf"); -+ } -+ -+ dw_ctf_trace("Created CTF file for module %s: %p\n", -+ module_name, ctf_file); -+} -+ -+/* DWARF walkers. */ -+ -+/* -+ * Initialize the child->parent DIE mapping for a single file. -+ */ -+static void init_parent_die(const char *file_name, Dwfl *dwfl) -+{ -+ GHashTable *offs; -+ Dwarf_Die *tu_die = NULL; -+ Dwarf_Addr junk; -+ -+ offs = g_hash_table_new(g_direct_hash, g_direct_equal); -+ if (offs == NULL) { -+ pr_err("Out of memory creating DIE offset hash\n"); -+ exit(1); -+ } -+ -+ while ((tu_die = dwfl_nextcu(dwfl, tu_die, &junk)) != NULL) { -+ init_parent_die_internal(file_name, offs, tu_die, 0, 0); -+ } -+ -+ g_hash_table_insert(fn_to_die_to_parent, -+ strdup(abs_file_name(file_name)), offs); -+} -+ -+/* -+ * Initialize one layer of a child->parent mapping. -+ * -+ * We traverse children of top-level subprograms hunting for anything we know -+ * how to emit, and record parent->child mappings for all intermediate DIEs. -+ */ -+static int init_parent_die_internal(const char *file_name, -+ GHashTable *offs, Dwarf_Die *parent, -+ int depth, int found_subprogram) -+{ -+ Dwarf_Die child; -+ int sib_ret; -+ Dwarf_Off parent_offset; -+ const char *err; -+ int add_parent = 0; -+ -+ if (dwarf_tag(parent) == DW_TAG_subprogram) -+ found_subprogram = 1; -+ -+ switch (dwarf_child(parent, &child)) { -+ case -1: -+ err = "child DIEs"; -+ goto err; -+ case 1: /* This DIE has no children */ -+ goto out; -+ } -+ -+ parent_offset = dwarf_dieoffset(parent); -+ -+ do { -+ int add_child = 0; -+ -+ /* -+ * Add links from the parent to all children for which a -+ * recursive call says they should be added, and note that we -+ * should add links to the parent too. Always look down to -+ * depth 2, since the topmost level is always -+ * DW_TAG_compile_unit, and we are interested in -+ * DW_TAG_subprograms one level below that. -+ */ -+ if (found_subprogram || depth < 2) -+ add_child = init_parent_die_internal(file_name, offs, -+ &child, depth+1, -+ found_subprogram); -+ -+ if (add_child) { -+ g_hash_table_insert(offs, -+ GUINT_TO_POINTER(dwarf_dieoffset(&child)), -+ GUINT_TO_POINTER(parent_offset)); -+ add_parent = 1; -+ } -+ } while ((sib_ret = dwarf_siblingof (&child, &child)) == 0); -+ -+ if (sib_ret == -1) { -+ err = "sibling DIEs"; -+ goto err; -+ } -+ -+out: -+ /* -+ * Emit a link for the next level up if we're under a subprogram and -+ * either we emitted a child link or the parent is itself something we -+ * know how to emit (and thus might possibly appear in a type DIE we -+ * care about). -+ */ -+ return (found_subprogram && -+ (add_parent || -+ (dwarf_tag(parent) < assembly_len && -+ assembly_tab[dwarf_tag(parent)] != NULL))); -+err: -+ pr_err("Cannot fetch %s of DIE at offset %lu in %s: %s\n", -+ err, DIEOFFSET(parent), file_name, -+ dwarf_errmsg(dwarf_errno())); -+ exit(1); -+} -+ -+/* -+ * Type ID computation. -+ * -+ * A type ID is a constant, recursively-constructed, dynamically-allocated -+ * string describing a given DWARF DIE in such a way that any DWARF file -+ * containing the same type will have the same type ID. (It even works for -+ * variables! Variables of the same name and referring to the same type have -+ * the same ID...) -+ * -+ * Optionally, call a callback with the computed ID once we know it (this is a -+ * recursive process, so the callback can be called multiple times as the ID is -+ * built up). -+ * -+ * An ID of NULL indicates that this DIE has no ID and need not be considered. -+ * -+ * It is probably an error for two DWARF DIEs representing top-level types to -+ * return the same ID, but for certain other DIEs (notably those representing -+ * the members of structures or unions), it is expected that they return the -+ * same ID as their type DIE. -+ * -+ * This function is the hottest hot spot in dwarf2ctf, so is somewhat -+ * aggressively optimized. -+ * -+ * The "overrides" allow the overriding of DWARF attributes, so that the -+ * machinery notices different DWARF from what actually appears in the -+ * debuginfo, so that the CTF that is emitted is suitably modified (and possibly -+ * duplicated). This is mostly used by type_id() to generate different IDs for -+ * dependent types of bitfields, but can be used for other purposes too, such as -+ * adjusting the offsets of types in unnamed structures, etc. Overrides are -+ * passed down if provided: overrides relating to bitfields are only applied by -+ * type_id() if no other overrides are provided. -+ * -+ * In general, you do not need to pass overrides down if you know you will only -+ * be called directly on top-level DIEs, but otherwise, you should do so. -+ */ -+static char *type_id(Dwarf_Die *die, -+ struct die_override *overrides, -+ void (*fun)(Dwarf_Die *die, -+ const char *id, -+ struct die_override *overrides, -+ void *data), -+ void *data) -+{ -+ return type_id_internal(die, overrides, fun, data, 0); -+} -+ -+/* -+ * Internal: generate the type ID for a type DIE. -+ * -+ * If there are no overrides, look for a bit_size and bit_offset and pass them -+ * down as well. -+ */ -+static char *type_id_type_die(Dwarf_Die *die, -+ Dwarf_Die *type_die, -+ struct die_override *overrides, -+ void (*fun)(Dwarf_Die *die, -+ const char *id, -+ struct die_override *overrides, -+ void *data), -+ void *data) -+{ -+ char *id; -+ -+ /* -+ * bit_size and bit_offset go together: we can assume that if a member -+ * has the one, it has the other. -+ */ -+ -+ if (private_dwarf_hasattr(die, DW_AT_bit_size)) { -+ Dwarf_Word size; -+ Dwarf_Word offset; -+ -+ size = private_dwarf_udata(die, DW_AT_bit_size, NULL); -+ offset = private_dwarf_udata(die, DW_AT_bit_offset, NULL); -+ struct die_override o[] = { -+ { DW_TAG_base_type, -+ DW_AT_bit_size, -+ DIE_OVERRIDE_REPLACE, -+ size, NULL }, -+ { DW_TAG_base_type, -+ DW_AT_bit_offset, -+ DIE_OVERRIDE_REPLACE, -+ offset, overrides }, -+ {0} -+ }; -+ id = type_id(type_die, o, fun, data); -+ } else -+ id = type_id(type_die, overrides, fun, data); -+ return id; -+} -+ -+/* -+ * Internal: allows flags to be passed to affect one (and only one) type ID -+ * recursion, without affecting other type_id()s launched from the 'fun'. -+ */ -+static char *type_id_internal(Dwarf_Die *die, -+ struct die_override *overrides, -+ void (*fun)(Dwarf_Die *die, -+ const char *id, -+ struct die_override *overrides, -+ void *data), -+ void *data, -+ int flags) -+{ -+ char *id = NULL; -+ int no_type_id = 0; -+ int decorated = 1; -+ -+ /* -+ * The ID of a null pointer is NULL. -+ */ -+ if (die == NULL) -+ return NULL; -+ -+ /* -+ * The ID of a function pointer is '//fp//', as a special case, -+ * with no location or overrides, ever. -+ */ -+ if (dwarf_tag(die) == DW_TAG_subroutine_type) { -+ id = xstrdup("//fp//"); -+ if (fun) -+ fun(die, id, NULL, data); -+ return id; -+ } -+ -+ /* -+ * If we have a type DIE, generate it first, passing any overrides down. -+ * (Base types and enumerations don't have a type DIE that CTF can -+ * encode the type of in any useful fashion.) -+ * -+ * Otherwise, note the location of this DIE, providing scoping -+ * information for all types based upon this one. Location elements are -+ * separated by //, an element impossible in a Linux path. The -+ * blacklist type prefix (if set) follows this (which is a name which, -+ * while not impossible in a Linux path, is very unlikely.) -+ * -+ * Array dimensions get none of this: they must be contained within -+ * another DIE, so will always have a location attached via that DIE, -+ * and get their type chased further down (so as to arrange that they -+ * appear inside an [].) -+ */ -+ if (dwarf_tag(die) != DW_TAG_subrange_type) { -+ if ((dwarf_tag(die) != DW_TAG_base_type) && -+ (dwarf_tag(die) != DW_TAG_enumeration_type)) { -+ Dwarf_Die type_die; -+ Dwarf_Die *diep = private_dwarf_type(die, &type_die); -+ -+ if (diep) -+ id = type_id_type_die(die, diep, overrides, -+ fun, data); -+ } -+ -+ /* -+ * Location information. We use cached realpath() results, and -+ * call str_appendn() only once, minimizing the number of -+ * strlen()s. -+ */ -+ if (id == NULL) { -+ const char *decl_file_name = dwarf_decl_file(die); -+ int decl_line_num; -+ const char *fname = ""; -+ char line_num[21] = ""; /* > than 2^64's digit count */ -+ -+ no_type_id = 1; -+ if (decl_file_name != NULL) -+ fname = abs_file_name(decl_file_name); -+ -+ if (dwarf_decl_line(die, &decl_line_num) >= 0) { -+ snprintf(line_num, sizeof(line_num), "%i", -+ decl_line_num); -+ } -+ id = str_appendn(id, fname, "//", line_num, "//", NULL); -+ } -+ } -+ -+ /* -+ * We implement this via a switch statement, rather than a jump table -+ * like the assembly_tab, simply because most cases are so small that -+ * splitting them into separate functions would do more harm than good -+ * to readability. -+ * -+ * WARNING: The spaces in the strings in this switch statement are not -+ * just for appearance: types with spaces in their names are impossible -+ * in C. If you move those spaces around for appearance's sake, please -+ * adjust mark_shared_by_name and dedup_alias_fixup(), which -+ * construct the IDs of basic types, structures, and unions by hand. -+ */ -+ switch (dwarf_tag(die)) { -+ case DW_TAG_base_type: { -+ Dwarf_Word bit_size = -1; -+ Dwarf_Word type_size = -1; -+ Dwarf_Word bit_offset = -1; -+ const char *diename = dwarf_diename(die); -+ -+ if ((flags & TI_COLLAPSE_SIZETYPE) && -+ (strcmp(diename, "long unsigned int") == 0)) -+ diename = "sizetype"; -+ -+ /* -+ * CTF encodes the size and bitwise-offset of bit-fields in the -+ * base type, so it must be stored once for each size, even if -+ * it only appears once for all sizes in the DWARF. -+ */ -+ if (private_dwarf_hasattr(die, DW_AT_bit_size) || -+ private_find_override(die, DW_AT_bit_size, -+ overrides)) -+ bit_size = private_dwarf_udata(die, DW_AT_bit_size, -+ overrides); -+ if (private_dwarf_hasattr(die, DW_AT_bit_offset) || -+ private_find_override(die, DW_AT_bit_offset, -+ overrides)) -+ bit_offset = private_dwarf_udata(die, DW_AT_bit_offset, -+ overrides); -+ -+ /* -+ * Bitfields that occupy their entire containing type are not -+ * bitfields, but just redundant DWARF. GCC emits these now and -+ * again, but the dups would trip CTF consistency checks, so -+ * must be skipped. -+ */ -+ if (bit_size > -1) { -+ /* -+ * This "may be omitted" in DWARF, but GCC doesn't: -+ * bitfields always get both. (See -+ * gcc/dwarf2out.c:gen_field_die().) -+ */ -+ type_size = private_dwarf_udata(die, DW_AT_bit_size, -+ overrides); -+ } -+ if (bit_size != type_size) { -+ char bitsize[22]; /* > 2^64's digit count */ -+ char bitoffset[22]; /* > 2^64's digit count */ -+ -+ snprintf(bitsize, sizeof(bitsize), "%li", bit_size); -+ id = str_appendn(id, diename, ":", bitsize, NULL); -+ if (bit_offset != -1) { -+ snprintf(bitoffset, sizeof(bitoffset), "%li", -+ bit_offset); -+ id = str_appendn(id, ":", bitoffset, NULL); -+ } -+ id = str_append(id, " "); -+ } else { -+ /* -+ * Ordinary (non-bit-field) base type. -+ */ -+ id = str_appendn(id, diename, " ", NULL); -+ } -+ break; -+ } -+ case DW_TAG_enumeration_type: -+ id = str_appendn(id, "enum ", dwarf_diename(die), " ", NULL); -+ break; -+ case DW_TAG_structure_type: -+ case DW_TAG_union_type: { -+ /* -+ * Incorporate the unaligned sizeof() the structure, if -+ * statically known (the offset of the last member in the DWARF) -+ * so that most structures which are redefined on the fly by -+ * preprocessor defines are disambiguated despite being defined -+ * in the same place. -+ * -+ * Only do this if this is a non-opaque structure/union -+ * definition: opaque definitions cannot have a size, but if -+ * they do by some mischance get one, notating it will mess up -+ * the several other places that manually construct opaque -+ * structure identifiers (and cannot incorporate a size, since -+ * they don't know it). -+ */ -+ const char *sou; -+ -+ if (strncmp(id, "////", 4) != 0) { -+ long long size; -+ char byte_size[24]; -+ -+ size = private_dwarf_size(die); -+ if (size > -1) { -+ sprintf(byte_size, "%lli", size); -+ id = str_appendn(id, byte_size, "//", NULL); -+ } -+ } -+ -+ if (dwarf_tag(die) == DW_TAG_union_type) -+ sou = "union "; -+ else -+ sou = "struct "; -+ -+ id = str_appendn(id, sou, dwarf_diename(die), " ", NULL); -+ break; -+ } -+ case DW_TAG_variable: -+ id = str_appendn(id, "var ", dwarf_diename(die), " ", NULL); -+ break; -+ case DW_TAG_typedef: -+ id = str_appendn(id, "typedef ", dwarf_diename(die), " ", NULL); -+ break; -+ case DW_TAG_const_type: -+ id = str_append(id, "const "); -+ break; -+ case DW_TAG_restrict_type: -+ id = str_append(id, "restrict "); -+ break; -+ case DW_TAG_volatile_type: -+ id = str_append(id, "volatile "); -+ break; -+ case DW_TAG_pointer_type: -+ if (no_type_id) -+ id = str_append(id, "void "); -+ id = str_append(id, "* "); -+ break; -+ -+ case DW_TAG_array_type: { -+ /* -+ * No explicit notation: all done per-dimension: so recurse to -+ * those. -+ */ -+ -+ int sib_ret; -+ int dimens = 0; -+ Dwarf_Die dim_die; -+ -+ switch (dwarf_child(die, &dim_die)) { -+ case -1: -+ pr_err("Corrupt DWARF: Cannot get array dimensions: %s\n", -+ dwarf_errmsg(dwarf_errno())); -+ exit(1); -+ case 1: /* No dimensions. */ -+ id = str_append(id, "[] "); -+ break; -+ default: -+ dimens = 1; -+ } -+ -+ if (!dimens) -+ break; -+ -+ do { -+ char *sub_id = type_id_internal(&dim_die, overrides, -+ fun, data, -+ TI_COLLAPSE_SIZETYPE); -+ id = str_append(id, sub_id); -+ free(sub_id); -+ } while ((sib_ret = dwarf_siblingof(&dim_die, &dim_die)) == 0); -+ -+ if (sib_ret == -1) { -+ pr_err("Corrupt DWARF: Cannot get array dimensions: %s\n", -+ dwarf_errmsg(dwarf_errno())); -+ exit(1); -+ } -+ break; -+ } -+ case DW_TAG_subrange_type: { -+ Dwarf_Word nelems = private_subrange_dimensions(die); -+ -+ id = str_append(id, "["); -+ -+ if (nelems > 0) { -+ Dwarf_Die type_die; -+ char elems[22]; /* bigger than 2^64's digit count */ -+ char *sub_id = type_id_internal(private_dwarf_type(die, &type_die), -+ overrides, fun, data, -+ TI_COLLAPSE_SIZETYPE); -+ -+ snprintf(elems, sizeof(elems), " %li", nelems); -+ id = str_appendn(id, sub_id, elems, NULL); -+ free(sub_id); -+ } -+ id = str_append(id, "] "); -+ break; -+ } -+ default: -+ /* -+ * Some tags (e.g. structure members) get the same ID as their -+ * associated type. We don't need to call the hook function -+ * again for such tags. -+ */ -+ decorated = 0; -+ } -+ -+ if (fun && decorated) -+ fun(die, id, overrides, data); -+ -+ return id; -+} -+ -+/* -+ * Process a file, calling the dwarf_process function for every top-level type -+ * found therein. Optionally call tu_init() at the start of each translation -+ * unit, and tu_done() at the end. -+ */ -+static void process_file(const char *file_name, -+ void (*dwarf_process)(const char *module_name, -+ const char *file_name, -+ Dwarf_Die *die, -+ Dwarf_Die *parent_die, -+ void *data), -+ void (*tu_init)(const char *module_name, -+ const char *file_name, -+ Dwarf_Die *tu_die, -+ void *data), -+ void (*tu_done)(const char *module_name, -+ const char *file_name, -+ Dwarf_Die *tu_die, -+ void *data), -+ void *data) -+{ -+ const char *err; -+ char *fn_module_name = fn_to_module(file_name); -+ const char *module_name = fn_module_name; -+ -+ Dwfl_Module *mod; -+ Dwfl *dwfl; -+ Dwarf *dwarf; -+ GHashTable *seen_before = g_hash_table_new_full(g_str_hash, g_str_equal, -+ free, free); -+ Dwarf_Die *tu_die = NULL; -+ Dwarf_Addr junk; -+ -+ if (seen_before == NULL) { -+ pr_err("Out of memory creating seen_before hash\n"); -+ exit(1); -+ } -+ -+ dwfl = simple_dwfl_new(file_name, &mod); -+ dwarf = dwfl_module_getdwarf(mod, &junk); -+ -+ /* -+ * On first traversal, make sure the DIE parent mapping is populated, -+ * so that filter_ctf_file_scope can use it. -+ */ -+ if (!g_hash_table_lookup_extended(fn_to_die_to_parent, -+ abs_file_name(file_name), -+ NULL, NULL)) -+ init_parent_die(file_name, dwfl); -+ -+ while ((tu_die = dwfl_nextcu(dwfl, tu_die, &junk)) != NULL) { -+ const char *tu_name; -+ -+ if (dwarf_tag(tu_die) != DW_TAG_compile_unit) { -+ err = "Malformed DWARF: non-compile_unit at top level"; -+ goto fail; -+ } -+ -+ tu_name = dwarf_diename(tu_die); -+ -+ dw_ctf_trace("Processing %s\n", tu_name); -+ -+ /* -+ * If we have seen this TU before, skip it. We assume that -+ * types in multiple identical TUs are always entirely -+ * identical. This lets us skip cases where the same object -+ * file is linked in multiple places without scanning every type -+ * in it. (Note: this may be inaccurate if a TU is built -+ * repeatedly with different #defines in force. I hope this -+ * cannot happen, but if it does, a workaround a-la libtool is -+ * simple: rename or symlink the TU for such repeated builds.) -+ * -+ * Otherwise, note the name of the module to which this TU maps, -+ * if it is not already known: otherwise, extract that name. -+ * -+ * This is purely an optimization: it breaks somewhat for -+ * multifile modules but this has no effect but a slight -+ * slowdown. -+ */ -+ if (g_hash_table_lookup_extended(seen_before, tu_name, -+ NULL, NULL)) -+ continue; -+ -+ g_hash_table_replace(seen_before, xstrdup(tu_name), NULL); -+ -+ /* -+ * We are only interested in top-level definitions within each -+ * TU. -+ */ -+ Dwarf_Die die; -+ -+ switch (dwarf_child(tu_die, &die)) { -+ case -1: -+ err = "fetch first child of TU"; -+ goto fail; -+ case 1: /* No DIEs at all in this TU */ -+ continue; -+ default: /* Child DIEs exist. */ -+ break; -+ } -+ -+ if (tu_init != NULL) -+ tu_init(module_name, file_name, tu_die, data); -+ -+ process_tu_func(module_name, file_name, dwarf, tu_die, &die, -+ dwarf_process, data); -+ -+ if (tu_done != NULL) -+ tu_done(module_name, file_name, tu_die, data); -+ } -+ -+ free(fn_module_name); -+ simple_dwfl_free(dwfl); -+ g_hash_table_destroy(seen_before); -+ -+ return; -+ -+ fail: -+ pr_err("Cannot %s for %s: %s\n", err, module_name, -+ dwarf_errmsg(dwarf_errno())); -+ exit(1); -+} -+ -+/* -+ * process_file() helper, walking over the top level and picking up types -+ * therein. -+ */ -+static void process_tu_func(const char *module_name, -+ const char *file_name, -+ Dwarf *dwarf, -+ Dwarf_Die *parent_die, -+ Dwarf_Die *die, -+ void (*dwarf_process)(const char *module_name, -+ const char *file_name, -+ Dwarf_Die *die, -+ Dwarf_Die *parent_die, -+ void *data), -+ void *data) -+{ -+ const char *err; -+ int sib_ret; -+ -+ /* -+ * We are only interested in definitions for which we can (eventually) -+ * emit CTF: call the processing function for all such. -+ */ -+ do { -+ if ((dwarf_tag(die) < assembly_len) && -+ (assembly_filter_tab[dwarf_tag(die)] == NULL || -+ assembly_filter_tab[dwarf_tag(die)](file_name, dwarf, die, -+ parent_die)) && -+ (assembly_tab[dwarf_tag(die)] != NULL)) -+ dwarf_process(module_name, file_name, die, -+ parent_die, data); -+ } while ((sib_ret = dwarf_siblingof(die, die)) == 0); -+ -+ if (sib_ret == -1) { -+ err = "fetch sibling"; -+ goto fail; -+ } -+ -+ return; -+ fail: -+ pr_err("Cannot %s for %s: %s\n", err, module_name, -+ dwarf_errmsg(dwarf_errno())); -+ exit(1); -+} -+ -+/* Duplicate detection. */ -+ -+/* -+ * Scan and identify duplicates across the entire set of object files. -+ */ -+static void scan_dups(void) -+{ -+ size_t i; -+ -+ /* -+ * First, determine which types are referenced by more than one -+ * translation unit, and construct the mapping from translation unit to -+ * non-builtin module name. -+ * -+ * The first pass detects duplicated types in need of sharing, without -+ * considering opaque/transparent structure/union aliasing. It requests -+ * an alias detection pass if any structures, or typedefs to them, are -+ * newly marked as shared. -+ * -+ * We must do this even when deduplication is disabled, because we need -+ * the TU->module-name mapping, even if in this case it is trivial. -+ */ -+ -+ struct dedup_state state = {0}; -+ -+ dw_ctf_trace("Duplicate detection: primary pass.\n"); -+ -+ /* -+ * This is merely flushed between TUs, not recreated: we create it here. -+ */ -+ state.vars_seen = g_hash_table_new_full(g_str_hash, -+ g_str_equal, -+ free, NULL); -+ -+ for (i = 0; i < object_names_cnt; i++) -+ process_file(object_names[i], dedup, -+ dedup_tu_init, dedup_tu_done, &state); -+ -+ if ((!state.repeat_detection) || !deduplicating) -+ goto out; -+ -+ do { -+ /* -+ * The second pass recognizes that opaque structures must be -+ * shared if the transparent equivalents are, and vice versa, -+ * and re-traces all transparent types that need sharing. -+ * -+ * It requests another alias detection pass if any non-opaque -+ * structures are newly marked as shared. -+ */ -+ dw_ctf_trace("Duplicate detection: alias fixup pass.\n"); -+ -+ state.repeat_detection = 0; -+ state.named_structs = list_filter(state.named_structs, -+ dedup_alias_fixup, -+ free_dups_id_file, &state); -+ } while (state.repeat_detection); -+ out: -+ g_hash_table_destroy(state.vars_seen); -+ dedup_dwarf_free(&state); -+ dw_ctf_trace("Duplicate detection: complete.\n"); -+ dw_ctf_trace("%llu distinct type IDs known.\n", -+ (unsigned long long) g_hash_table_size(id_to_module)); -+ dw_ctf_trace("%llu variables blacklisted for static/nonstatic conflicts.\n", -+ (unsigned long long) g_hash_table_size(variable_blacklist)); -+ g_list_free_full(state.named_structs, free_dups_id_file); -+} -+ -+/* -+ * Set up state for dedup(). A tu_init() callback. -+ */ -+static void dedup_tu_init(const char *module_name, const char *file_name, -+ Dwarf_Die *tu_die, void *data) -+{ -+ struct dedup_state *state = data; -+ struct per_module *per_mod; -+ -+ /* -+ * Make sure that even if this module has no types in it we still end up -+ * generating a CTF file. (Userspace depends on this, since a CTF file -+ * with no types in means the module is known and typeless, while no CTF -+ * file at all means the module is not known.) -+ */ -+ -+ per_mod = g_hash_table_lookup(per_module, module_name); -+ if (per_mod == NULL) { -+ init_ctf_table(module_name); -+ dw_ctf_trace("%s: initialized CTF file.\n", module_name); -+ } -+ -+ state->structs_seen = g_hash_table_new(g_str_hash, g_str_equal); -+ g_hash_table_remove_all(state->vars_seen); -+ state->module_name = module_name; -+} -+ -+/* -+ * Free state for dedup(). A tu_done() callback. -+ */ -+static void dedup_tu_done(const char *module_name, const char *file_name, -+ Dwarf_Die *tu_die, void *data) -+{ -+ struct dedup_state *state = data; -+ -+ /* -+ * We have to annul module_name because it is freed between object files -+ * by process_file(). Since we use that to track whether vars_seen -+ * needs reconstructing, that means we have to destroy that as well. -+ */ -+ g_hash_table_destroy(state->structs_seen); -+ state->structs_seen = NULL; -+ state->module_name = NULL; -+} -+ -+/* -+ * Free DWARF state for dedup(). -+ */ -+static void dedup_dwarf_free(struct dedup_state *state) -+{ -+ if (state->dwfl == NULL) -+ return; -+ simple_dwfl_free(state->dwfl); -+ state->dwfl = NULL; -+ state->dwarf = NULL; -+ free(state->dwfl_file_name); -+ state->dwfl_file_name = NULL; -+ if (state->structs_seen) -+ g_hash_table_destroy(state->structs_seen); -+ state->structs_seen = NULL; -+} -+ -+/* -+ * Duplicate detection. -+ * -+ * Scan for duplicate types. A duplicate type is defined as any type which -+ * appears in more than one module, or, more precisely, any type for which a -+ * type with the same ID already exists in another module. -+ * -+ * This pass also constructs the id_to_module table, so is essential even when -+ * deduplication is disabled (though then it need be run only once.) -+ */ -+ -+static void dedup(const char *module_name, const char *file_name, -+ Dwarf_Die *die, Dwarf_Die *parent_die, void *data) -+{ -+ struct dedup_state *state = data; -+ int is_sou = 0; -+ char *id = type_id(die, NULL, is_named_struct_union_enum, &is_sou); -+ -+ state->file_name = file_name; -+ /* -+ * If a DWARF-4 type signature is found, abort. While we can support -+ * DWARF-4 eventually, support in elfutils is insufficiently robust for -+ * now (elfutils 0.152). -+ */ -+ if (private_dwarf_hasattr(die, DW_AT_type)) { -+ Dwarf_Attribute type_attr; -+ -+ if ((private_dwarf_attr(die, DW_AT_type, &type_attr) != NULL) && -+ (dwarf_whatform(&type_attr) == DW_FORM_ref_sig8)) { -+ pr_err("Sorry, not yet implemented: %s contains DWARF-4 debugging information.\n", -+ module_name); -+ exit(1); -+ } -+ } -+ -+ /* -+ * Non-anonymous, non-opaque structure/union/enum types in -+ * non-dedup-blacklisted modules get their names and locations recorded -+ * for subsequent passes; all type_id()-descendant types are similarly -+ * noted. -+ */ -+ if (is_sou && strncmp(id, "////", strlen("////")) != 0) -+ free(type_id(die, NULL, dedup_will_rescan, state)); -+ -+ /* -+ * Handle static variable blacklisting. (We still shuffle blacklisted -+ * variables into the right place in id_to_module because we check for -+ * blacklisting at the lowest level, by which point we have already -+ * depended on id_to_module being correctly populated.) -+ * -+ * Avoid calling this for recursive dependent-type scans: variables -+ * cannot be dependent types. -+ */ -+ if (parent_die != NULL && dwarf_tag(die) == DW_TAG_variable) -+ dedup_blacklist_var_dups(die, state); -+ -+ dedup_mark_inner_die(module_name, die, id, NULL, data); -+ free(id); -+} -+ -+/* -+ * Do the underlying marking of a DIE as shared, iff need be. (No variable -+ * blacklisting, non-opaque structure checks, or anything else needed only by -+ * top-level DIEs.) -+ * -+ * This function may be called multiple times for overridden DIEs that are -+ * dependent types of bitfields. (On multiple calls for normal types, the -+ * second call will enter the NS_NO_MARKING case block and terminate recursion.) -+ */ -+static void dedup_mark_inner_die(const char *module_name, Dwarf_Die *die, -+ const char *id, -+ struct die_override *overrides, -+ void *data) -+{ -+ /* -+ * If we know of a single module incorporating this type, and it is not -+ * the same as the module we are currently in, then this type is -+ * duplicated across modules and belongs in the global type table. -+ * (This means that duplicated types are repeatedly so marked: this -+ * is unavoidable, because pass 3 requires re-marking structures that -+ * have already been marked, to pick up unmarked intermediate types.) -+ * -+ * We never consider types in modules on the deduplication blacklist -+ * to introduce duplicates. -+ */ -+ switch (type_needs_sharing(module_name, id)) { -+ case NS_NEEDS_SHARING: -+ mark_shared(die, NULL, overrides, data); -+ mark_seen_contained(die, "shared_ctf", overrides, data); -+ /* Fall through */ -+ case NS_NO_MARKING: -+ /* -+ * A duplicated type, but in the same module, or deduplication -+ * is disabled, so id_to_module is already correct. (When -+ * deduplication is disabled, we will be running with only one -+ * module at a time, and id_to_module will be a trivial -+ * mapping.) -+ */ -+ return; -+ case NS_NOT_SHARED: -+ break; -+ } -+ -+ /* -+ * Record that we have seen this type, and all its dependent types, in -+ * this module (or in the shared module if need be). -+ */ -+ -+ dw_ctf_trace("Marking %s as seen in %s\n", id, module_name); -+ g_hash_table_replace(id_to_module, intern(xstrdup(id)), -+ xstrdup(module_name)); -+ mark_seen_contained(die, module_name, overrides, data); -+ free(type_id(die, overrides, dedup_typeid, data)); -+} -+ -+/* -+ * Note in the dedup_id_file list that we will rescan a DIE in a later duplicate -+ * detection pass. -+ * -+ * A type_id() callback. -+ */ -+static void dedup_will_rescan(Dwarf_Die *die, const char *id, -+ struct die_override *overrides, void *data) -+{ -+ struct dedup_state *state = data; -+ struct dedup_id_file *id_file; -+ -+ /* -+ * We don't care about array index types, which will never be structures -+ * in C. -+ */ -+ if (id[0] == '[') -+ return; -+ -+ id_file = calloc(1, sizeof(struct dedup_id_file)); -+ if (id_file == NULL) { -+ pr_err("Out of memory allocating id_file\n"); -+ exit(1); -+ } -+ id_file->file_name = intern(xstrdup(state->file_name)); -+ id_file->id = intern(xstrdup(id)); -+ id_file->dieoff = dwarf_dieoffset(die); -+ state->named_structs = g_list_prepend(state->named_structs, id_file); -+} -+ -+/* -+ * Note the variable referenced by this DIE in vars_seen: blacklist it if an -+ * entry for this variable already exists in vars_seen and this instance is -+ * static, or if a static entry already exists in vars_seen, whether this -+ * instance is static or not. -+ */ -+static void dedup_blacklist_var_dups(Dwarf_Die *die, -+ struct dedup_state *state) -+{ -+ void *static_var; -+ int blacklist = 0; -+ -+ if (g_hash_table_lookup_extended(state->vars_seen, -+ dwarf_diename(die), -+ NULL, &static_var)) { -+ if (!private_dwarf_hasattr(die, DW_AT_external) && -+ !private_dwarf_hasattr(die, DW_AT_declaration)) -+ blacklist = 1; -+ if (static_var != NULL) -+ blacklist = 1; -+ } else -+ /* -+ * We need a non-NULL address here, but that is all we need. -+ * The address of a random variable will do. -+ */ -+ g_hash_table_insert(state->vars_seen, -+ xstrdup(dwarf_diename(die)), -+ (!private_dwarf_hasattr(die, DW_AT_external) && -+ !private_dwarf_hasattr(die, DW_AT_declaration)) ? -+ &static_var : NULL); -+ -+ if (blacklist) { -+ char *var = NULL; -+ var = str_appendn(var, state->module_name, "`", -+ dwarf_diename(die), NULL); -+ g_hash_table_replace(variable_blacklist, var, NULL); -+ } -+} -+ -+/* -+ * Free a dedup_id_file's contents. -+ */ -+static void free_dups_id_file(void *data) -+{ -+ struct dedup_id_file *id_file = data; -+ free(id_file); -+} -+ -+/* -+ * Determine if a type is duplicated and needs sharing. -+ */ -+static enum needs_sharing type_needs_sharing(const char *module_name, -+ const char *id) -+{ -+ const char *existing_type_module; -+ existing_type_module = g_hash_table_lookup(id_to_module, id); -+ -+ /* -+ * Types not already known about do not need sharing. -+ * -+ * Types already in the current modules and any types in external-module -+ * mode do not even need marking. -+ */ -+ if (existing_type_module == NULL) -+ return NS_NOT_SHARED; -+ -+ if ((strcmp(existing_type_module, module_name) == 0) || -+ (strcmp(existing_type_module, "shared_ctf") == 0) || -+ !deduplicating) -+ return NS_NO_MARKING; -+ -+ return NS_NEEDS_SHARING; -+} -+ -+/* -+ * Detect duplicates and mark seen types for a given type, via a type_id() -+ * callback: used to detect dependent types (particularly those at child-DIE -+ * level) as duplicates. -+ */ -+static void dedup_typeid(Dwarf_Die *die, const char *id, -+ struct die_override *overrides, void *data) -+{ -+ struct dedup_state *state = data; -+ -+ dedup_mark_inner_die(state->module_name, die, id, overrides, data); -+} -+ -+/* -+ * Mark any types contained within a particular type DIE as seen. This is -+ * needed since even nameless types contained within other aggregates can be -+ * used as the type of members in any of their enclosing aggregates (though they -+ * cannot possibly be found in a module different from that of their containing -+ * aggregate, any more than a structure member can). -+ */ -+static void mark_seen_contained(Dwarf_Die *die, const char *module_name, -+ struct die_override *overrides, -+ void *data) -+{ -+ const char *err; -+ Dwarf_Die child; -+ -+ if ((dwarf_tag(die) != DW_TAG_structure_type) && -+ (dwarf_tag(die) != DW_TAG_union_type)) -+ return; -+ -+ switch (dwarf_child(die, &child)) { -+ case -1: -+ err = "fetch first child of aggregate"; -+ goto fail; -+ case 1: /* No DIEs at all in this aggregate */ -+ return; -+ default: /* Child DIEs exist. */ -+ break; -+ } -+ -+ /* -+ * We iterate over all immediate children and recursively call ourselves -+ * for all those of type DW_TAG_structure_type and DW_TAG_union_type. -+ * -+ * Further, everything with an entry in assembly_tab other than -+ * non-bitfield members needs marking, since these may be declared at -+ * structure scope rather than being confined to global scope. -+ * Non-bitfield members are skipped because they cannot be used as the -+ * type of another field. These types cannot be duplicates if their -+ * containing type is not a duplicate, and typedefs cannot occur at this -+ * level so they cannot be aliased; thus we can mark them directly -+ * without going back into the top of dedup(). -+ * -+ * (Bit-field members are not skipped: they use different CTF from their -+ * non-bitfield equivalents, even though they refer to the same -+ * top-level DIE. The actual different CTF is handled by type_id() -+ * itself, but we do have to call it.) -+ */ -+ int sib_ret; -+ -+ do -+ switch (dwarf_tag(&child)) { -+ case DW_TAG_member: { -+ /* -+ * bit_size and bit_offset go together: we can assume -+ * that if a member has the one, it has the other, -+ * is a bitfield, and needs recursive marking. -+ */ -+ if (dwarf_tag(&child) == DW_TAG_member && -+ !private_dwarf_hasattr(&child, DW_AT_bit_size)) -+ break; -+ -+ free(type_id(&child, overrides, dedup_typeid, data)); -+ break; -+ } -+ case DW_TAG_structure_type: -+ case DW_TAG_union_type: -+ mark_seen_contained(&child, module_name, overrides, data); -+ /* fall through */ -+ default: -+ if (dwarf_tag(&child) < assembly_len && -+ assembly_tab[dwarf_tag(&child)] != NULL) { -+ -+ char *id = type_id(&child, overrides, NULL, NULL); -+ -+ dw_ctf_trace("Marking member %s as seen in " -+ "%s\n", id, module_name); -+ g_hash_table_replace(id_to_module, intern(id), -+ xstrdup(module_name)); -+ } -+ } -+ while ((sib_ret = dwarf_siblingof(&child, &child)) == 0); -+ -+ if (sib_ret == -1) { -+ err = "iterate over members"; -+ goto fail; -+ } -+ -+ return; -+ -+ fail: -+ pr_err("Cannot %s while marking aggregates as seen: %s\n", -+ err, dwfl_errmsg(dwfl_errno())); -+ exit(1); -+} -+ -+/* -+ * Mark a type as duplicated and located in the shared CTF table. Recursive, -+ * via the type_id() callback mechanism. -+ * -+ * A type_id() callback (though also called directly). -+ */ -+static void mark_shared(Dwarf_Die *die, const char *id, -+ struct die_override *overrides, void *data) -+{ -+ struct dedup_state *state = data; -+ const char *existing_module; -+ -+ /* -+ * Non-recursive call. Trigger type_id for its recursive callback, -+ * throwing the result away. -+ */ -+ if (id == NULL) { -+ free(type_id(die, overrides, mark_shared, state)); -+ return; -+ } -+ -+ existing_module = g_hash_table_lookup(id_to_module, id); -+ -+ if ((existing_module == NULL) || -+ (strcmp(existing_module, "shared_ctf") != 0)) { -+ -+ dw_ctf_trace("Marking %s as duplicate\n", id); -+ g_hash_table_replace(id_to_module, intern(xstrdup(id)), -+ xstrdup("shared_ctf")); -+ -+ /* -+ * Newly-marked structures/unions/enums must trigger a new -+ * duplicate detection pass (even if they are opaque). -+ */ -+ -+ if (((dwarf_tag(die) == DW_TAG_structure_type) || -+ (dwarf_tag(die) == DW_TAG_union_type) || -+ (dwarf_tag(die) == DW_TAG_enumeration_type)) && -+ (!state->repeat_detection)) { -+ dw_ctf_trace("Requesting another duplicate detection pass.\n"); -+ state->repeat_detection = 1; -+ } -+ } -+ -+ /* -+ * If this is a structure or union, mark its members as duplicates too. -+ * -+ * Do this even if we've seen this structure before, as this instance of -+ * the structure may have more members than the last we saw. However, -+ * if we have seen this structure before *in this translation unit*, -+ * skip it, to avoid infinite recursion in mutually referential -+ * structures. -+ */ -+ if ((dwarf_tag(die) == DW_TAG_structure_type) || -+ (dwarf_tag(die) == DW_TAG_union_type)) { -+ Dwarf_Die child; -+ -+ if (g_hash_table_lookup_extended(state->structs_seen, id, -+ NULL, NULL)) -+ return; -+ g_hash_table_replace(state->structs_seen, intern(xstrdup(id)), -+ NULL); -+ -+ switch (dwarf_child(die, &child)) { -+ case -1: -+ goto fail; -+ case 1: /* No DIEs at all in this aggregate */ -+ return; -+ } -+ -+ /* -+ * We are only interested in non-blacklisted children of type -+ * DW_TAG_member. -+ */ -+ int sib_ret; -+ -+ do -+ if ((dwarf_tag(&child) == DW_TAG_member) && -+ !member_blacklisted(&child, die)) -+ free(type_id(&child, overrides, -+ mark_shared, state)); -+ while ((sib_ret = dwarf_siblingof(&child, &child)) == 0); -+ -+ if (sib_ret == -1) -+ goto fail; -+ } -+ -+ return; -+ -+ fail: -+ pr_err("Cannot mark aggregate %s members as duplicated: %s\n", -+ dwarf_diename(die), dwarf_errmsg(dwarf_errno())); -+ exit(1); -+} -+ -+/* -+ * Determine if a type is a named struct, union, or enum. -+ * -+ * A type_id() callback. -+ */ -+static void is_named_struct_union_enum(Dwarf_Die *die, const char *unused, -+ struct die_override *overrides, -+ void *data) -+{ -+ int *is_sou = data; -+ -+ if (((dwarf_tag(die) == DW_TAG_structure_type) || -+ (dwarf_tag(die) == DW_TAG_union_type) || -+ (dwarf_tag(die) == DW_TAG_enumeration_type)) && -+ (private_dwarf_hasattr(die, DW_AT_name))) -+ *is_sou = 1; -+} -+ -+/* -+ * Duplicate detection alias fixup pass. Once the first pass is complete, we -+ * may have marked an opaque 'struct/union/enum foo' for sharing but not caught -+ * the non-opaque instance, because no users of the non-opaque instance appeared -+ * in the DWARF after the opaque copy was detected as a duplicate. This pass -+ * detects such cases, and marks their members as duplicates too. -+ * -+ * (The inverse case of a non-opaque structure/union/enum detected as a -+ * duplicate after the last usage of its opaque alias will be caught by this -+ * trap too.) -+ * -+ * Warning: this routine directly computes type_id()s without access to the -+ * corresponding type DIE, and as such is dependent on the format of type_id()s. -+ * (This is why it must run over non-opaque structures: given a non-opaque -+ * structure, its opaque alias is easy to compute, but the converse is not -+ * true.) -+ * -+ * As a list_filter() filter function, returns nonzero if this structure will -+ * not need to be checked again (because both its opaque and transparent -+ * variants are shared). -+ */ -+static int dedup_alias_fixup(void *id_file_data, void *data) -+{ -+ struct dedup_id_file *id_file = id_file_data; -+ struct dedup_state *state = data; -+ -+ int transparent_shared = 0; -+ int opaque_shared = 0; -+ int made_shared = 0; -+ -+ char *opaque_id; -+ const char *line_num; -+ const char *type_size; -+ const char *type_name; -+ -+ /* -+ * Compute the opaque variant corresponding to this transparent type, -+ * and check to see if either is marked shared, then find the DIE and -+ * mark both as shared if either is. (Unfortunately this means a double -+ * recursion in such cases, but this is unavoidable.) -+ */ -+ -+ line_num = strstr(id_file->id, "//"); -+ if (!line_num) { -+ pr_err("Internal error: type ID %s is corrupt.\n", -+ id_file->id); -+ exit(1); -+ } -+ -+ type_size = strstr(line_num + 2, "//"); -+ if (!type_size) { -+ pr_err("Internal error: type ID %s is corrupt.\n", -+ id_file->id); -+ exit(1); -+ } -+ -+ type_name = strstr(type_size + 2, "//"); -+ if (!type_name) { -+ /* -+ * That's OK: the type size is optional, so what we thought was -+ * the type size is actually the type name. -+ */ -+ type_name = type_size; -+ } -+ type_name += 2; -+ -+ opaque_id = xstrdup("////"); -+ opaque_id = str_append(opaque_id, type_name); -+ -+ const char *transparent_module = g_hash_table_lookup(id_to_module, -+ id_file->id); -+ const char *opaque_module = g_hash_table_lookup(id_to_module, -+ opaque_id); -+ -+ transparent_shared = ((transparent_module != NULL) && -+ (strcmp(transparent_module, "shared_ctf") == 0)); -+ -+ opaque_shared = ((opaque_module != NULL) && -+ (strcmp(opaque_module, "shared_ctf") == 0)); -+ -+ /* -+ * Transparent type needs sharing. -+ */ -+ if (opaque_shared && !transparent_shared) { -+ Dwarf_Die die; -+ Dwfl_Module *mod; -+ Dwarf_Addr dummy; -+ -+ /* -+ * Since we are not using process_file(), we must handle -+ * translation unit switches by hand, including resetting -+ * structs_seen. We also need to open the DWARF file, since -+ * type_id() needs access to the DIE of this type and all its -+ * dependent types as well. -+ */ -+ -+ if (state->dwfl != NULL && -+ strcmp(state->dwfl_file_name, id_file->file_name) != 0) -+ dedup_dwarf_free(state); -+ -+ if (state->dwfl_file_name == NULL) { -+ state->dwfl = simple_dwfl_new(id_file->file_name, &mod); -+ state->dwarf = dwfl_module_getdwarf(mod, &dummy); -+ state->dwfl_file_name = xstrdup(id_file->file_name); -+ if (state->structs_seen) -+ g_hash_table_destroy(state->structs_seen); -+ state->structs_seen = g_hash_table_new(g_str_hash, -+ g_str_equal); -+ } -+ if (!dwarf_offdie(state->dwarf, id_file->dieoff, -+ &die)) { -+ pr_err("Cannot look up offset %li in %s for type with ID %s\n", -+ id_file->dieoff, id_file->file_name, id_file->id); -+ exit(1); -+ } -+ mark_shared(&die, NULL, NULL, state); -+ made_shared = 1; -+ } -+ -+ /* -+ * We don't have the opaque type's DIE, so we can't use mark_shared(): -+ * this is also good since this triggers another duplicate detection -+ * pass, and we don't want to trigger another pass merely because of a -+ * nonshared opaque type (since they don't have members that may have -+ * structure or union type themselves and thus force more unshared -+ * types to become shared). -+ * -+ * Instead, do it by hand: this is simple, as member recursion is -+ * guaranteed not to be required for an opaque type. -+ */ -+ if (transparent_shared && !opaque_shared) { -+ dw_ctf_trace("Marking %s as duplicate\n", opaque_id); -+ g_hash_table_replace(id_to_module, intern(xstrdup(opaque_id)), -+ xstrdup("shared_ctf")); -+ made_shared = 1; -+ } -+ -+ free(opaque_id); -+ -+ return made_shared || (opaque_shared && transparent_shared); -+} -+ -+/* -+ * Mark a basic type shared by name and intern it in all relevant hashes. (Used -+ * for marking basic types we don't have a DIE for.) -+ */ -+static void mark_shared_by_name(ctf_file_t *ctf, ctf_id_t ctf_id, -+ const char *name) -+{ -+ struct ctf_full_id static_ctf_id = { ctf, ctf_id }; -+ struct ctf_full_id *full_ctf_id; -+ char *id = NULL; -+ -+ full_ctf_id = malloc(sizeof(struct ctf_full_id)); -+ if (full_ctf_id == NULL) { -+ pr_err("%s: out of memory\n", __func__); -+ exit(1); -+ } -+ *full_ctf_id = static_ctf_id; -+ -+ id = str_appendn(id, "////", name, " ", NULL); -+#ifdef DEBUG -+ strcpy(full_ctf_id->module_name, "shared_ctf"); -+ strcpy(full_ctf_id->file_name, "<built-in type>"); -+#endif -+ g_hash_table_replace(id_to_module, intern(xstrdup(id)), xstrdup("shared_ctf")); -+ g_hash_table_replace(id_to_type, intern(id), full_ctf_id); -+} -+ -+/* -+ * Type assembly. -+ * -+ * Given a DWARF DIE corresponding to a top-level type, call the appropriate -+ * construction function, passing it the appropriate ctf_file_t, constructing it -+ * if necessary, and stashing them in the appropriate hashes. Return the -+ * ctf_file_t and ctf_id_t of this type. -+ * -+ * Indirectly recursively called for types depending on other types, and for -+ * the types of variables (which for the sake of argument we call 'types' here -+ * too, since we treat them exactly like types, and dealing with types is our -+ * most important function). In such calls, the module_name may be 'shared_ctf' -+ * if this type is in the shared CTF repository. -+ * -+ * Select properties of the DIE can be overridden via the overrides array, if -+ * needed. -+ */ -+static struct ctf_full_id *construct_ctf_id(const char *module_name, -+ const char *file_name, -+ Dwarf_Die *die, -+ Dwarf_Die *parent_die, -+ struct die_override *overrides) -+{ -+ char *id = type_id(die, overrides, NULL, NULL); -+ char *ctf_module; -+ ctf_file_t *ctf; -+ ctf_snapshot_id_t snapshot; -+ -+ dw_ctf_trace(" %p: %s: looking up %s: %s\n", &id, -+ module_name ? module_name : "(no module)", -+ dwarf_diename(die), id); -+ /* -+ * Make sure this type does not already exist. (Recursive chasing for -+ * referenced types can lead to construct_ctf() being called on them -+ * more than once.) -+ */ -+ struct ctf_full_id *ctf_id; -+ -+ ctf_id = g_hash_table_lookup(id_to_type, id); -+ if (ctf_id != NULL) { -+ dw_ctf_trace(" %p: %p:%i found in module %s, file %s\n", &id, -+ ctf_id->ctf_file, (int) ctf_id->ctf_id, -+ ctf_id->module_name, ctf_id->file_name); -+ free(id); -+ return ctf_id; -+ } -+ -+ /* -+ * Create the CTF file for this type, if it does not exist. Verify that -+ * the duplicate-detection pass scanned this type, and that this is -+ * either the current module or the shared CTF module. -+ */ -+ -+ ctf_module = g_hash_table_lookup(id_to_module, id); -+ -+ if (ctf_module == NULL) { -+ pr_err("Internal error: within file %s, module %s, type at DIE offset %lx\n" -+ "with ID %s was not already noted by dedup().\n", -+ file_name, module_name, DIEOFFSET(die), id); -+ pr_err("dedup() is probably buggy.\n"); -+ exit(1); -+ } -+ -+ if ((strcmp(ctf_module, module_name) != 0) && -+ (strcmp(ctf_module, "shared_ctf") != 0)) { -+ pr_err("Internal error: within file %s, module %s, type at DIE offset %lx\n" -+ "with ID %s is in a different non-shared module, %s.\n", -+ file_name, module_name, DIEOFFSET(die), id, ctf_module); -+ pr_err("dedup() is probably buggy.\n"); -+ exit(1); -+ } -+ -+ ctf = lookup_ctf_file(ctf_module); -+ -+ /* -+ * Construct the CTF, then insert the top-level CTF entity into the -+ * id->type hash so that references from other types can find it, and -+ * update the CTF container. If conversion failed, roll back all -+ * changes made since the last successful call to this function. -+ * -+ * NOTE: references within DWARF to non-top-level types will currently -+ * fail, but I'm not sure if these can exist. (The type ID -+ * representation implicitly assumes that they cannot.) -+ */ -+ -+ snapshot = ctf_snapshot(ctf); -+ -+ enum skip_type skip = SKIP_CONTINUE; -+ -+ dw_ctf_trace("%p: into die_to_ctf() for %s\n", &id, id); -+ ctf_id_t this_ctf_id = die_to_ctf(ctf_module, file_name, die, -+ parent_die, ctf, -1, overrides, -+ 1, 0, &skip, NULL, id); -+ dw_ctf_trace("%p: out of die_to_ctf()\n", &id); -+ -+ ctf_id = malloc(sizeof(struct ctf_full_id)); -+ if (ctf_id == NULL) { -+ pr_err("Out of memory\n"); -+ exit(1); -+ } -+ -+ if (skip != SKIP_ABORT) { -+ ctf_id->ctf_file = ctf; -+ ctf_id->ctf_id = this_ctf_id; -+#ifdef DEBUG -+ strcpy(ctf_id->module_name, ctf_module); -+ strcpy(ctf_id->file_name, file_name); -+#endif -+ dw_ctf_trace(" %lx: %s: new type added, CTF ID %p:%li\n", -+ DIEOFFSET(die), id, ctf_id->ctf_file, -+ ctf_id->ctf_id); -+ -+ g_hash_table_replace(id_to_type, intern(id), ctf_id); -+ } else { -+ /* -+ * Failure. Remove the type from the id_to_type mapping, if it -+ * is there, and discard any added types from the CTF. -+ * -+ * If we have had to ctf_update() due to a new type getting -+ * used, the rollback will fail: discard instead. It might leave -+ * some spurious types hanging around but it will clean up as -+ * much as we can at this point. (This cannot happen when -+ * LIBDTRACE_CTF_OMISSIBLE_CTF_UPDATE, but it costs nothing to -+ * leave in: failure is a rare case.) -+ */ -+ -+ if (ctf_rollback(ctf, snapshot) < 0) -+ if (ctf_errno(ctf) == ECTF_OVERROLLBACK) -+ ctf_discard(ctf); -+ -+ free(ctf_id); -+ ctf_id = NULL; -+ -+ g_hash_table_remove(id_to_type, id); -+ free(id); -+ -+ dw_ctf_trace(" %p: (failure)\n", &id); -+ } -+ -+ return ctf_id; -+} -+ -+/* -+ * Given a DWARF DIE corresponding to a top-level type, or to an aggregate -+ * member, and the ctf_file_t where it is to be placed, call the appropriate -+ * construction function to place it and (for aggregates) its siblings there, -+ * recursing to handle contained aggregates. -+ * -+ * The parameters to this function are: -+ * -+ * module_name: The kernel module. -+ * file_name: The object file. -+ * die: The DWARF DIE. -+ * parent_die: Its parent, i.e. if a structure member, this is a structure: if -+ * top-level, this is a CU DIE. -+ * ctf: The CTF file this object should go into (possibly shared_ctf). -+ * parent_ctf_id: The CTF ID of the parent DIE, or -1 if none. -+ * struct die_override: Overrides for DWARF attributes (a NULL-terminated array, -+ * or NULL). -+ * top_level_type: 1 if this is a top-level type that can have a name and be -+ * referred to by other types. -+ * backwards: if 1, this is an internal call to process a series of bitfields -+ * with descending bit_offset and identical data_member_location. -+ * skip: The error-handling / skipping enum. -+ * replace: if 1, this type should replace its parent type entirely. -+ * id: the ID of this type. -+ * -+ * Note: id is only defined when top_level_type is 1. (We never use it -+ * in other situations, and computing it is quite expensive.) -+ */ -+static ctf_id_t die_to_ctf(const char *module_name, const char *file_name, -+ Dwarf_Die *die, Dwarf_Die *parent_die, -+ ctf_file_t *ctf, ctf_id_t parent_ctf_id, -+ struct die_override *overrides, int top_level_type, -+ int backwards, enum skip_type *skip, int *replace, -+ const char *id) -+{ -+ int sib_ret = 0; -+ ctf_id_t this_ctf_id; -+ int dummy; -+ -+ do { -+ const char *id_name; -+ const char *decl_file_name = dwarf_decl_file(die); -+ int decl_line_num; -+ int emitted_backwards = 0; -+ char locerrstr[1024]; -+ Dwarf_Die next_die; -+ -+ /* -+ * If the next DWARF DIE is at the same location as this one but -+ * with a lower bit_offset, we need to process the set of DIEs -+ * at this location in *reverse*, because DWARF has the DIEs in -+ * declaration order, while CTF wants them in in-memory order: -+ * so recurse to handle the next until we get to an element with -+ * a sibling at a different data_member_location (safe because -+ * there can't be that many of them per data_member_location), -+ * then (at the end of die_to_ctf()) exit the recursion and skip -+ * over the lot. -+ * -+ * We can ignore 'replace' and the return value of die_to_ctf -+ * because bitfields must be structure or union members and -+ * cannot be array dimensions. -+ */ -+ if (die_emit_next_backwards(&next_die, die, -+ overrides) != NULL) { -+ ctf_id_t dummy; -+ -+ dw_ctf_trace("Emitting %s:%s:%lx backwards\n", -+ module_name, file_name, -+ DIEOFFSET(&next_die)); -+ -+ dummy = die_to_ctf(module_name, file_name, &next_die, -+ parent_die, ctf, parent_ctf_id, -+ overrides, top_level_type, 1, skip, -+ replace, NULL); -+ if (*skip == SKIP_ABORT) -+ return dummy; -+ emitted_backwards = 1; -+ } -+ -+ /* -+ * Compute a name for our current location, for error messages. -+ * (The type representation could be used, but is likely to be -+ * hard for users to comprehend, and should we move to a hashed -+ * representation would be entirely useless for this purpose.) -+ */ -+ if ((decl_file_name == NULL) || -+ (dwarf_decl_line(die, &decl_line_num) < 0)) { -+ decl_file_name = "global"; -+ decl_line_num = 0; -+ } -+ -+ id_name = dwarf_diename(die); -+ if (id_name == NULL) -+ id_name = "(unnamed type)"; -+ -+ snprintf(locerrstr, sizeof(locerrstr), "%s:%i:%s", -+ decl_file_name, decl_line_num, id_name); -+ -+ dw_ctf_trace("Working over %s:%s:%s:%lx:%x with CTF file %p\n", -+ module_name, file_name, -+ dwarf_diename(die)==NULL?"NULL":dwarf_diename(die), -+ DIEOFFSET(die), dwarf_tag(die), ctf); -+ -+ /* -+ * Only process a given node, or its children, if we know how to -+ * do so. -+ */ -+ if ((dwarf_tag(die) >= assembly_len) || -+ (assembly_tab[dwarf_tag(die)] == NULL)) { -+ pr_err("%s:%i: warning: skipping identifier " -+ "%s with unknown DWARF tag %lx.\n", -+ decl_file_name, decl_line_num, id_name, -+ (unsigned long) dwarf_tag(die)); -+ return -1; -+ } -+ -+ *skip = SKIP_CONTINUE; -+ -+ this_ctf_id = assembly_tab[dwarf_tag(die)](module_name, -+ file_name, -+ die, parent_die, -+ ctf, parent_ctf_id, -+ locerrstr, -+ overrides, -+ top_level_type, -+ skip, -+ replace ? replace : -+ &dummy); -+ dw_ctf_trace("%s: out of assembly function for tag %lx with type ID %li\n", -+ locerrstr, (unsigned long) dwarf_tag(die), -+ this_ctf_id); -+ -+ if (this_ctf_id < 0) { -+ if ((this_ctf_id == CTF_NO_ERROR_REPORTED) && -+ (ctf_errno(ctf) != 0)) -+ pr_err("%s: CTF error in assembly of item with tag %i: %s\n", -+ locerrstr, dwarf_tag(die), -+ ctf_errmsg(ctf_errno(ctf))); -+ -+ num_errors++; -+#ifdef DEBUG -+ exit(1); -+#endif -+ *skip = SKIP_ABORT; -+ } -+ -+ /* -+ * Add newly-added non-skipped top-level structure or union CTF -+ * IDs to the type table at once. This allows circular type -+ * references via pointers in structure/union member DIEs to be -+ * looked up correctly. -+ */ -+ if (top_level_type && (*skip == SKIP_CONTINUE) && -+ ((dwarf_tag(die) == DW_TAG_structure_type) || -+ (dwarf_tag(die) == DW_TAG_union_type))) { -+ struct ctf_full_id full_ctf_id = { ctf, this_ctf_id }; -+ struct ctf_full_id *ctf_id; -+ -+#ifdef DEBUG -+ strcpy(full_ctf_id.module_name, module_name); -+ strcpy(full_ctf_id.file_name, file_name); -+#endif -+ -+ ctf_id = malloc(sizeof(struct ctf_full_id)); -+ if (ctf_id == NULL) { -+ fprintf(stderr, -+ "Out of memory allocating type ID\n"); -+ exit(1); -+ } -+ -+ dw_ctf_trace(" %s: immediate addition of %s, CTF ID " -+ "%p:%li in module %s, file %s\n", __func__, -+ id, full_ctf_id.ctf_file, full_ctf_id.ctf_id, -+ module_name, file_name); -+ *ctf_id = full_ctf_id; -+ -+ g_hash_table_replace(id_to_type, intern(xstrdup(id)), -+ ctf_id); -+ } -+ -+ /* -+ * Recurse to handle contained DIEs. -+ */ -+ -+ if ((dwarf_haschildren(die)) && (*skip == SKIP_CONTINUE)) { -+ Dwarf_Die child_die; -+ ctf_id_t new_id; -+ int replace = 0; -+ -+ if (dwarf_child(die, &child_die) < 0) { -+ pr_err("%s: Cannot recurse to DWARF DIE children: %s\n", -+ locerrstr, dwarf_errmsg(dwarf_errno())); -+ exit(1); -+ } -+ -+ new_id = die_to_ctf(module_name, file_name, &child_die, -+ die, ctf, this_ctf_id, overrides, 0, -+ 0, skip, &replace, NULL); -+ if (replace) -+ this_ctf_id = new_id; -+ } -+ -+ /* -+ * If we are walking backwards over a bunch of bitfields, this -+ * is a recursive walk, not an iterative one: return. -+ */ -+ if (backwards) -+ return this_ctf_id; -+ -+ /* -+ * We are not walking backwards, but this is the final stage of -+ * a bunch of backwards emissions: walk forwards until we hit -+ * the last one again. -+ */ -+ if (emitted_backwards) -+ while (die_emit_next_backwards(&next_die, die, -+ overrides) != NULL) -+ *die = next_die; -+ -+ /* -+ * Walk siblings of non-top-level types only: the sibling walk -+ * of top-level types is done by process_file(), so that -+ * construct_ctf_id() gets a chance to put each such type in the -+ * right CTF file. -+ */ -+ } while (*skip != SKIP_ABORT && !top_level_type && -+ (sib_ret = dwarf_siblingof(die, die)) == 0); -+ -+ if (sib_ret == -1) { -+ pr_err("In module %s, failure walking the sibling list: %s\n", -+ module_name, dwarf_errmsg(dwarf_errno())); -+ exit(1); -+ } -+ -+ dw_ctf_trace("New type ID: %p:%li\n", ctf, this_ctf_id); -+ return this_ctf_id; -+} -+ -+/* -+ * Calls construct_ctf_id() and throws the ID away. Used as a process_file() -+ * callback. -+ */ -+static void construct_ctf(const char *module_name, const char *file_name, -+ Dwarf_Die *die, Dwarf_Die *parent_die, -+ void *unused __unused__) -+{ -+ construct_ctf_id(module_name, file_name, die, parent_die, NULL); -+} -+ -+/* -+ * Return the next DIE, if that DIE needs to be emitted before this one. -+ */ -+static Dwarf_Die *die_emit_next_backwards(Dwarf_Die *next, Dwarf_Die *die, -+ struct die_override *overrides) -+{ -+ if (dwarf_tag(die) == DW_TAG_member && -+ dwarf_siblingof(die, next) == 0 && -+ dwarf_tag(next) == DW_TAG_member && -+ private_dwarf_hasattr(die, DW_AT_data_member_location) && -+ private_dwarf_hasattr(next, DW_AT_data_member_location) && -+ private_dwarf_udata(die, DW_AT_data_member_location, overrides) == -+ private_dwarf_udata(next, DW_AT_data_member_location, overrides) && -+ private_dwarf_hasattr(die, DW_AT_bit_offset) && -+ private_dwarf_hasattr(next, DW_AT_bit_offset) && -+ private_dwarf_udata(die, DW_AT_bit_offset, overrides) > -+ private_dwarf_udata(next, DW_AT_bit_offset, overrides)) -+ return next; -+ return NULL; -+} -+ -+/* -+ * Look up a type through its reference: return its ctf_id, or recursively -+ * construct it if need be. -+ */ -+static ctf_id_t lookup_ctf_type(const char *module_name, const char *file_name, -+ Dwarf_Die *die, ctf_file_t *ctf, -+ struct die_override *overrides, -+ const char *locerrstr) -+{ -+ Dwarf_Die tmp; -+ Dwarf_Die *type_die = private_dwarf_type(die, &tmp); -+ Dwarf_Die cu_die; -+ struct ctf_full_id *type_ref; -+ -+ /* -+ * Pointers to functions and void are special cases: there is only one -+ * of each of these in CTF, so we can use global singletons. -+ */ -+ -+ if (type_die == NULL) -+ return ctf_void_type; -+ -+ if (dwarf_tag(type_die) == DW_TAG_subroutine_type) -+ return ctf_funcptr_type; -+ -+ /* -+ * Look up or construct CTF for this type. -+ */ -+ -+ dwarf_diecu(type_die, &cu_die, NULL, NULL); -+ -+ dw_ctf_trace(" %s: Looking up dependent type at offset %lx for type %s at module %s, file %s\n", -+ locerrstr, DIEOFFSET(type_die), -+ dwarf_diename(die) ? dwarf_diename(die) : "NULL", -+ module_name, file_name); -+ -+ type_ref = construct_ctf_id(module_name, file_name, -+ type_die, &cu_die, overrides); -+ -+ /* -+ * Pass any error back up. -+ */ -+ if (type_ref == NULL) { -+ pr_err("%s: type lookup failed.\n", locerrstr); -+ return -1; -+ } -+ -+ if ((type_ref->ctf_file != ctf) && -+ type_ref->ctf_file != lookup_ctf_file("shared_ctf")) { -+#ifdef DEBUG -+ pr_err("%s: Internal error: lookup of %s found in different file: " -+ "%s/%s versus %s/%s.\n", locerrstr, -+ dwarf_diename(die) ? dwarf_diename(die) : "(unnamed)", -+ type_ref->module_name, type_ref->file_name, -+ module_name, file_name); -+#else -+ pr_err("%s: Internal error: lookup of %s found in different file.\n", -+ locerrstr, dwarf_diename(die) ? dwarf_diename(die) : -+ "(unnamed)"); -+#endif -+ pr_err("dedup() is probably buggy.\n"); -+ exit(1); -+ } -+ -+ return type_ref->ctf_id; -+} -+ -+/* Assembly functions. */ -+ -+#define CTF_DW_ENFORCE(attribute) do \ -+ if (!private_dwarf_hasattr(die, (DW_AT_##attribute))) { \ -+ pr_err("%s: %s: %lx: skipping type, %s attribute not present.\n", \ -+ locerrstr, __func__, DIEOFFSET(die), \ -+ #attribute); \ -+ *skip = SKIP_ABORT; \ -+ return CTF_ERROR_REPORTED; \ -+ } \ -+ while (0) -+ -+#define CTF_DW_ENFORCE_NOT(attribute) do \ -+ if (private_dwarf_hasattr(die, (DW_AT_##attribute))) { \ -+ pr_err("%s: %s: %lx: skipping type, %s attribute not supported.\n", \ -+ locerrstr, __func__, DIEOFFSET(die), \ -+ #attribute); \ -+ *skip = SKIP_ABORT; \ -+ return CTF_ERROR_REPORTED; \ -+ } \ -+ while (0) -+ -+#define ROOT_TYPE(x) (x) ? CTF_ADD_ROOT : CTF_ADD_NONROOT -+ -+/* -+ * A CTF assembly filter function which excludes all types not at the global -+ * scope (i.e. whose immediate parent is not a CU DIE), and all types which -+ * reference a type which is not at the global scope (thus ruling out local type -+ * definitions for which the compiler is not consistently emitting all -+ * intermediate types at the local scope). -+ */ -+static int filter_ctf_file_scope(const char *file_name, Dwarf *dwarf, -+ Dwarf_Die *die, Dwarf_Die *parent_die) -+{ -+ Dwarf_Die type_die; -+ GHashTable *parents; -+ -+ /* -+ * A type not dependent on another is acceptable iff it is at the global -+ * scope. -+ */ -+ if (private_dwarf_type(die, &type_die) == NULL) -+ return (dwarf_tag(parent_die) == DW_TAG_compile_unit); -+ -+ /* -+ * No type we reference may have a subprogram DIE as any of its parents. -+ */ -+ parents = g_hash_table_lookup(fn_to_die_to_parent, -+ abs_file_name(file_name)); -+ -+ do { -+ Dwarf_Die parent = type_die; -+ Dwarf_Off parent_off = 0; -+ -+ do { -+ if (parent_off != 0 && -+ !dwarf_offdie(dwarf, parent_off, &parent)) -+ break; -+ if (dwarf_tag(&parent) == DW_TAG_subprogram) -+ return 0; -+ } while ((parent_off = GPOINTER_TO_UINT(g_hash_table_lookup(parents, -+ GUINT_TO_POINTER(dwarf_dieoffset(&parent))))) -+ != 0); -+ } while (private_dwarf_type(&type_die, &type_die) != NULL); -+ -+ return 1; -+} -+ -+/* -+ * A CTF assembly filter function which excludes all names not at the global -+ * scope, and all names whose names are unlikely to be interesting. (DTrace -+ * userspace contains a similar list, but the two lists need not be in sync.) -+ */ -+static int filter_ctf_uninteresting(const char *file_name __unused__, -+ Dwarf *dwarf __unused__, -+ Dwarf_Die *die, Dwarf_Die *parent_die) -+{ -+ const char *sym_name = dwarf_diename(die); -+ -+ /* -+ * 'Variables' with no name are not interesting. -+ */ -+ if (sym_name == NULL) -+ return 0; -+ -+#define strstarts(var, x) (strncmp(var, x, strlen(x)) == 0) -+ return ((dwarf_tag(parent_die) == DW_TAG_compile_unit) && -+ !((strcmp(sym_name, "__per_cpu_start") == 0) || -+ (strcmp(sym_name, "__per_cpu_end") == 0) || -+ (strcmp(sym_name, "_sdt_probes") == 0) || -+ (strstarts(sym_name, "__crc_")) || -+ (strstarts(sym_name, "__ksymtab_")) || -+ (strstarts(sym_name, "__kcrctab_")) || -+ (strstarts(sym_name, "__kstrtab_")) || -+ (strstarts(sym_name, "__param_")) || -+ (strstarts(sym_name, "__syscall_meta__")) || -+ (strstarts(sym_name, "__p_syscall_meta__")) || -+ (strstarts(sym_name, "__event_")) || -+ (strstarts(sym_name, "event_")) || -+ (strstarts(sym_name, "ftrace_event_")) || -+ (strstarts(sym_name, "types__")) || -+ (strstarts(sym_name, "args__")) || -+ (strstarts(sym_name, "__tracepoint_")) || -+ (strstarts(sym_name, "__tpstrtab_")) || -+ (strstarts(sym_name, "__tpstrtab__")) || -+ (strstarts(sym_name, "__initcall_")) || -+ (strstarts(sym_name, "__setup_")) || -+ (strstarts(sym_name, "__pci_fixup_")) || -+ (strstr(sym_name, ".") != NULL))); -+#undef strstarts -+} -+ -+/* -+ * Assemble base types. -+ */ -+static ctf_id_t assemble_ctf_base(const char *module_name, -+ const char *file_name, Dwarf_Die *die, -+ Dwarf_Die *parent_die, ctf_file_t *ctf, -+ ctf_id_t parent_ctf_id, const char *locerrstr, -+ struct die_override *overrides, -+ int top_level_type, enum skip_type *skip, -+ int *replace) -+{ -+ typedef ctf_id_t (*ctf_add_fun)(ctf_file_t *, uint_t, -+ const char *, const ctf_encoding_t *); -+ -+ const char *name = dwarf_diename(die); -+ Dwarf_Word encoding, size; -+ ctf_add_fun ctf_add_func; -+ ctf_encoding_t ctf_encoding; -+ size_t encoding_search; -+ struct die_override *bit_size_override, *bit_offset_override; -+ -+ struct dwarf_encoding_tab { -+ Dwarf_Word encoding; -+ ctf_add_fun func; -+ uint_t encoding_fixed; -+ struct type_encoding_tab *size_lookup; -+ }; -+ -+ struct type_encoding_tab float_encoding[] = { -+ {sizeof(float), CTF_FP_SINGLE }, -+ {sizeof(double), CTF_FP_DOUBLE }, -+ {sizeof(long double), CTF_FP_LDOUBLE }, -+ {0, 0} -+ }; -+ -+ struct type_encoding_tab float_cplx_encoding[] = { -+ {sizeof(float), CTF_FP_CPLX }, -+ {sizeof(double), CTF_FP_DCPLX }, -+ {sizeof(long double), CTF_FP_LDCPLX }, -+ {0, 0} -+ }; -+ -+ struct type_encoding_tab float_imagry_encoding[] = { -+ {sizeof(float), CTF_FP_IMAGRY }, -+ {sizeof(double), CTF_FP_DIMAGRY }, -+ {sizeof(long double), CTF_FP_LDIMAGRY }, -+ {0, 0} -+ }; -+ -+ struct dwarf_encoding_tab all_encodings[] = { -+ {DW_ATE_boolean, ctf_add_integer, CTF_INT_BOOL, NULL}, -+ {DW_ATE_signed, ctf_add_integer, CTF_INT_SIGNED, NULL}, -+ {DW_ATE_signed_char, ctf_add_integer, -+ CTF_INT_SIGNED | CTF_INT_CHAR, NULL}, -+ {DW_ATE_unsigned, ctf_add_integer, 0, NULL}, -+ {DW_ATE_unsigned_char, ctf_add_integer, CTF_INT_CHAR, NULL}, -+ {DW_ATE_float, ctf_add_float, 0, float_encoding}, -+ {DW_ATE_complex_float, ctf_add_float, 0, float_cplx_encoding}, -+ {DW_ATE_imaginary_float, ctf_add_float, 0, -+ float_imagry_encoding}, -+ {0, 0, 0, 0} -+ }; -+ -+ CTF_DW_ENFORCE(name); -+ CTF_DW_ENFORCE(encoding); -+ CTF_DW_ENFORCE(byte_size); -+ CTF_DW_ENFORCE_NOT(endianity); -+ -+ encoding = private_dwarf_udata(die, DW_AT_encoding, overrides); -+ size = private_dwarf_udata(die, DW_AT_byte_size, overrides); -+ -+ for (encoding_search = 0; all_encodings[encoding_search].func != 0; -+ encoding_search++) { -+ if (all_encodings[encoding_search].encoding == encoding) { -+ ctf_add_func = all_encodings[encoding_search].func; -+ if (all_encodings[encoding_search].size_lookup != NULL) -+ ctf_encoding.cte_format = -+ find_ctf_encoding(all_encodings[encoding_search].size_lookup, -+ size); -+ else -+ ctf_encoding.cte_format = -+ all_encodings[encoding_search].encoding_fixed; -+ break; -+ } -+ } -+ -+ if (all_encodings[encoding_search].func == 0) { -+ pr_err("%s: skipping type, base type %li not yet implemented.\n", -+ locerrstr, (long) encoding); -+ *skip = SKIP_ABORT; -+ return CTF_ERROR_REPORTED; -+ } -+ -+ /* -+ * Handle bitfields. Only look at overrides, since bitfields can only -+ * be members of structures in C, thus derived from the referencing DIE. -+ * Bitfields are never top-level types in C, even though they are in -+ * DWARF. -+ */ -+ bit_size_override = private_find_override(die, DW_AT_bit_size, -+ overrides); -+ bit_offset_override = private_find_override(die, DW_AT_bit_offset, -+ overrides); -+ if (bit_size_override) { -+ ctf_encoding.cte_bits = bit_size_override->value; -+ top_level_type = 0; -+ } else -+ ctf_encoding.cte_bits = size * 8; -+ -+ if (bit_offset_override) { -+#if __BYTE_ORDER == __BIG_ENDIAN -+ ctf_encoding.cte_offset = bit_offset_override->value; -+#else -+ /* -+ * The figure here counts from the left to the leftmost edge of -+ * the bitfield: we want to count from the right to the -+ * rightmost edge. -+ */ -+ ctf_encoding.cte_offset = (size * 8) - -+ bit_offset_override->value - ctf_encoding.cte_bits; -+ dw_ctf_trace("Endianizing cte_offset from %x to %x\n", -+ (unsigned int) bit_offset_override->value, -+ ctf_encoding.cte_offset); -+#endif -+ } else -+ ctf_encoding.cte_offset = 0; -+ -+#ifdef DEBUG -+ if (bit_size_override || bit_offset_override) -+ dw_ctf_trace("Bitfield overrides: bit size %i; bit offset %i\n", -+ ctf_encoding.cte_bits, ctf_encoding.cte_offset); -+#endif -+ -+ return ctf_add_func(ctf, ROOT_TYPE(top_level_type), name, -+ &ctf_encoding); -+} -+ -+/* -+ * Assemble pointer types. -+ */ -+static ctf_id_t assemble_ctf_pointer(const char *module_name, -+ const char *file_name, -+ Dwarf_Die *die, Dwarf_Die *parent_die, -+ ctf_file_t *ctf, ctf_id_t parent_ctf_id, -+ const char *locerrstr, -+ struct die_override *overrides, -+ int top_level_type, -+ enum skip_type *skip, int *replace) -+{ -+ ctf_id_t type_ref; -+ -+ type_ref = lookup_ctf_type(module_name, file_name, die, ctf, -+ overrides, locerrstr); -+ if (type_ref < 0) { -+ *skip = SKIP_ABORT; -+ return CTF_ERROR_REPORTED; -+ } -+ -+ /* -+ * Pointers to functions are all the same type in CTF: don't bother -+ * adding it over again. -+ */ -+ if (type_ref == ctf_funcptr_type) -+ return type_ref; -+ -+ return ctf_add_pointer(ctf, ROOT_TYPE(top_level_type), type_ref); -+} -+ -+/* -+ * Assemble array types. This function looks up the array type, but does not do -+ * any array construction: that is left to assemble_ctf_array_dimension(). -+ */ -+static ctf_id_t assemble_ctf_array(const char *module_name, -+ const char *file_name, Dwarf_Die *die, -+ Dwarf_Die *parent_die, ctf_file_t *ctf, -+ ctf_id_t parent_ctf_id, -+ const char *locerrstr, -+ struct die_override *overrides, -+ int top_level_type, -+ enum skip_type *skip, int *replace) -+{ -+ ctf_id_t type_ref; -+ -+ CTF_DW_ENFORCE_NOT(ordering); -+ CTF_DW_ENFORCE_NOT(bit_stride); -+ CTF_DW_ENFORCE_NOT(byte_stride); -+ -+ type_ref = lookup_ctf_type(module_name, file_name, die, ctf, -+ overrides, locerrstr); -+ if (type_ref < 0) { -+ *skip = SKIP_ABORT; -+ return CTF_ERROR_REPORTED; -+ } -+ return type_ref; -+} -+ -+/* -+ * Assemble an array dimension, wrapping an array round the parent_ctf_id and -+ * replacing it. -+ */ -+static ctf_id_t assemble_ctf_array_dimension(const char *module_name, -+ const char *file_name, -+ Dwarf_Die *die, -+ Dwarf_Die *parent_die, -+ ctf_file_t *ctf, -+ ctf_id_t parent_ctf_id, -+ const char *locerrstr, -+ struct die_override *overrides, -+ int top_level_type, -+ enum skip_type *skip, -+ int *replace) -+{ -+ ctf_arinfo_t arinfo; -+ -+ CTF_DW_ENFORCE_NOT(bit_size); -+ CTF_DW_ENFORCE_NOT(byte_size); -+ CTF_DW_ENFORCE_NOT(bit_stride); -+ CTF_DW_ENFORCE_NOT(byte_stride); -+ CTF_DW_ENFORCE_NOT(lower_bound); -+ CTF_DW_ENFORCE_NOT(threads_scaled); -+ -+ arinfo.ctr_contents = parent_ctf_id; -+ -+ arinfo.ctr_index = lookup_ctf_type(module_name, file_name, -+ die, ctf, overrides, locerrstr); -+ if (arinfo.ctr_index < 0) { -+ *skip = SKIP_ABORT; -+ return CTF_ERROR_REPORTED; -+ } -+ -+ arinfo.ctr_nelems = private_subrange_dimensions(die); -+ -+ /* -+ * For each array dimension, construct an appropriate array of the -+ * type-so-far, overriding the parent type. -+ */ -+ -+ *replace = 1; -+ return ctf_add_array(ctf, ROOT_TYPE(top_level_type), &arinfo); -+} -+ -+/* -+ * Assemble an enumeration. -+ */ -+static ctf_id_t assemble_ctf_enumeration(const char *module_name, -+ const char *file_name, -+ Dwarf_Die *die, -+ Dwarf_Die *parent_die, -+ ctf_file_t *ctf, -+ ctf_id_t parent_ctf_id, -+ const char *locerrstr, -+ struct die_override *overrides, -+ int top_level_type, -+ enum skip_type *skip, -+ int *replace) -+{ -+ const char *name = dwarf_diename(die); -+ -+ return ctf_add_enum(ctf, ROOT_TYPE(top_level_type), name); -+} -+ -+/* -+ * Assemble an enumeration value. -+ */ -+static ctf_id_t assemble_ctf_enumerator(const char *module_name, -+ const char *file_name, -+ Dwarf_Die *die, -+ Dwarf_Die *parent_die, -+ ctf_file_t *ctf, -+ ctf_id_t parent_ctf_id, -+ const char *locerrstr, -+ struct die_override *overrides, -+ int top_level_type, -+ enum skip_type *skip, -+ int *replace) -+{ -+ const char *name = dwarf_diename(die); -+ Dwarf_Word value; -+ int err; -+ -+ CTF_DW_ENFORCE(name); -+ CTF_DW_ENFORCE(const_value); -+ CTF_DW_ENFORCE_NOT(bit_stride); -+ CTF_DW_ENFORCE_NOT(byte_stride); -+ -+ value = private_dwarf_udata(die, DW_AT_const_value, overrides); -+ err = ctf_add_enumerator(ctf, parent_ctf_id, name, value); -+ -+ if (err != 0) -+ return err; -+ -+ return parent_ctf_id; -+} -+ -+/* -+ * Assemble a typedef. -+ */ -+static ctf_id_t assemble_ctf_typedef(const char *module_name, -+ const char *file_name, -+ Dwarf_Die *die, -+ Dwarf_Die *parent_die, -+ ctf_file_t *ctf, -+ ctf_id_t parent_ctf_id, -+ const char *locerrstr, -+ struct die_override *overrides, -+ int top_level_type, -+ enum skip_type *skip, -+ int *replace) -+{ -+ const char *name = dwarf_diename(die); -+ ctf_id_t type_ref; -+ -+ CTF_DW_ENFORCE(name); -+ -+ type_ref = lookup_ctf_type(module_name, file_name, die, ctf, -+ overrides, locerrstr); -+ if (type_ref < 0) { -+ *skip = SKIP_ABORT; -+ return CTF_ERROR_REPORTED; -+ } -+ -+ return ctf_add_typedef(ctf, ROOT_TYPE(top_level_type), name, type_ref); -+} -+ -+/* -+ * Assemble a const/volatile/restrict qualifier. -+ */ -+static ctf_id_t assemble_ctf_cvr_qual(const char *module_name, -+ const char *file_name, -+ Dwarf_Die *die, -+ Dwarf_Die *parent_die, -+ ctf_file_t *ctf, -+ ctf_id_t parent_ctf_id, -+ const char *locerrstr, -+ struct die_override *overrides, -+ int top_level_type, -+ enum skip_type *skip, -+ int *replace) -+{ -+ ctf_id_t (*ctf_cvr_fun)(ctf_file_t *fp, uint_t flag, ctf_id_t ref); -+ ctf_id_t type_ref; -+ -+ switch (dwarf_tag(die)) { -+ case DW_TAG_const_type: ctf_cvr_fun = ctf_add_const; break; -+ case DW_TAG_volatile_type: ctf_cvr_fun = ctf_add_volatile; break; -+ case DW_TAG_restrict_type: ctf_cvr_fun = ctf_add_restrict; break; -+ default: -+ pr_err("%s: internal error: assemble_ctf_cvr_qual() called with\n" -+ "non-const/volatile/restrict: %i\n", locerrstr, dwarf_tag(die)); -+ exit(1); -+ } -+ -+ type_ref = lookup_ctf_type(module_name, file_name, die, ctf, -+ overrides, locerrstr); -+ if (type_ref < 0) { -+ *skip = SKIP_ABORT; -+ return CTF_ERROR_REPORTED; -+ } -+ -+ return ctf_cvr_fun(ctf, ROOT_TYPE(top_level_type), type_ref); -+} -+ -+/* -+ * Assemble a structure or union type. This assembles only the type itself, not -+ * its constituent members: that is done by assemble_ctf_su_member(). -+ * -+ * We assume that if a structure or union type is discovered with more members -+ * than an earlier-discovered type, that it is compatible with that earlier type -+ * and a superset of it. -+ * -+ * FIXME: in debug mode we should not assume this. -+ */ -+static ctf_id_t assemble_ctf_struct_union(const char *module_name, -+ const char *file_name, -+ Dwarf_Die *die, -+ Dwarf_Die *parent_die, -+ ctf_file_t *ctf, -+ ctf_id_t parent_ctf_id, -+ const char *locerrstr, -+ struct die_override *overrides, -+ int top_level_type, -+ enum skip_type *skip, -+ int *replace) -+{ -+ ctf_id_t (*ctf_add_sou)(ctf_file_t *fp, uint_t flag, const char *name, -+ size_t size); -+ -+ const char *name = dwarf_diename(die); -+ int is_union = (dwarf_tag(die) == DW_TAG_union_type); -+ struct ctf_memb_count *member_count = NULL; -+ ctf_id_t id; -+ long long size; -+ -+ /* -+ * FIXME: these both need handling for DWARF4 support. -+ */ -+ CTF_DW_ENFORCE_NOT(specification); -+ CTF_DW_ENFORCE_NOT(signature); -+ -+ /* -+ * Figure out the size of the type (if possible) and force it into the -+ * CTF to ensure that struct/union padding is added appropriately. -+ * -+ * If we don't know it, force a size of zero, which is interpreted as -+ * being equivalent to a call to the unsized struct/union addition -+ * function, letting libdtrace-ctf figure out a likely size as best it -+ * can. -+ */ -+ size = private_dwarf_size(die); -+ if (size < 0) -+ size = 0; -+ -+ /* -+ * Possibly we should ignore this entire structure, if we already know -+ * of one with the same name and at least as many members. If we -+ * already know of one and it is shorter, we want to use its ID rather -+ * than creating a new one. -+ * -+ * Note; by this point, the deduplicator has long run: thus we know for -+ * sure what module a potentially-shared type will end up in, and -+ * there's no need to double-check the shared CTF repository for types. -+ * We also know that the module must exist in the per_module hash. -+ */ -+ -+ if (name != NULL) { -+ char *structized_name = NULL; -+ struct per_module *ctf_pm; -+ -+ structized_name = str_appendn(structized_name, -+ is_union ? "u " : "s ", -+ name, NULL); -+ -+ ctf_pm = g_hash_table_lookup(per_module, module_name); -+ member_count = g_hash_table_lookup(ctf_pm->member_counts, -+ structized_name); -+ -+ if (member_count) { -+ free(structized_name); -+ dw_ctf_trace("%s: already exists (with ID %li) with %zi members\n" -+ "versus current %li members\n", -+ locerrstr, member_count->ctf_id, -+ member_count->count, -+ count_dwarf_members(die)); -+ -+ if (member_count->count < count_dwarf_members(die)) -+ return member_count->ctf_id; -+ -+ *skip = SKIP_SKIP; -+ return member_count->ctf_id; -+ } -+ -+ /* -+ * Not in existence yet. Create it. -+ */ -+ member_count = malloc(sizeof(struct ctf_memb_count)); -+ if (member_count == NULL) { -+ pr_err("Out of memory allocating structure/union member count\n"); -+ exit(1); -+ } -+ member_count->count = 0; -+ g_hash_table_insert(ctf_pm->member_counts, -+ structized_name, member_count); -+ } -+ -+ dw_ctf_trace("%s: adding structure %s\n", locerrstr, name); -+ -+ if (is_union) -+ ctf_add_sou = ctf_add_union_sized; -+ else -+ ctf_add_sou = ctf_add_struct_sized; -+ -+ id = ctf_add_sou(ctf, ROOT_TYPE(top_level_type), name, size); -+ -+ if (member_count != NULL) -+ member_count->ctf_id = id; -+ -+ return id; -+} -+ -+/* -+ * Figure out the offset of this type, in bits. (This is split in two -+ * for bitfields, where the bitfield itself gets represented elsewhere, -+ * in the CTF type of the member itself.) -+ * -+ * DW_AT_data_bit_offset is the simple case. DW_AT_data_member_location -+ * is trickier, and, alas, the DWARF2 variation is the complex one. -+ */ -+static int ctf_su_offset(Dwarf_Die *die, const char *locerrstr, -+ struct die_override *overrides, ulong_t *offset, -+ ulong_t *bit_offset) -+{ -+ struct die_override *o; -+ -+ if (private_dwarf_hasattr(die, DW_AT_data_bit_offset)) -+ *offset = private_dwarf_udata(die, DW_AT_data_bit_offset, NULL); -+ else if (private_dwarf_hasattr(die, DW_AT_data_member_location)) { -+ Dwarf_Attribute location_attr; -+ -+ private_dwarf_attr(die, DW_AT_data_member_location, -+ &location_attr); -+ -+ switch (dwarf_whatform(&location_attr)) { -+ case DW_FORM_data1: -+ case DW_FORM_data2: -+ case DW_FORM_data4: -+ case DW_FORM_data8: -+ case DW_FORM_udata: -+ case DW_FORM_sdata: -+ { -+ /* -+ * Byte offset, with bit_offset of containing -+ * structure/union added, if present. -+ * -+ * (No overrides supported here, yet, due to lack of -+ * sdata overrides and the desire for consistency. -+ * We can add them if we start passing down -+ * DW_AT_data_member_location overrides.) -+ */ -+ if (dwarf_whatform(&location_attr) == DW_FORM_sdata) { -+ Dwarf_Sword location; -+ -+ dwarf_formsdata(&location_attr, &location); -+ *offset = location * 8; -+ } else { -+ Dwarf_Word location; -+ -+ dwarf_formudata(&location_attr, &location); -+ *offset = location * 8; -+ } -+ break; -+ } -+ case DW_FORM_block1: -+ case DW_FORM_block2: -+ case DW_FORM_block4: -+ { -+ Dwarf_Op *location; -+ size_t nlocs; -+ -+ /* -+ * DWARF 2 block-based data_member_location. This can -+ * be quite complicated in some situations (notably C++ -+ * virtual bases), but for normal structure members it -+ * is simple. FIXME for userspace tracing of C++. -+ * -+ * This is thoroughly specific to the forms of DWARF2 -+ * emitted by GCC. We don't need to feel guilty about -+ * this because elfutils does just the same thing. -+ */ -+ -+ if (dwarf_getlocation(&location_attr, &location, -+ &nlocs) < 0) { -+ pr_err("%s: offset not a valid location expression: %s\n", -+ locerrstr, dwarf_errmsg(dwarf_errno())); -+ return CTF_ERROR_REPORTED; -+ } -+ -+ if ((nlocs != 1) || -+ ((location[0].atom != DW_OP_plus_uconst) && -+ (location[0].atom != DW_OP_constu))) { -+ pr_err("%s: complex location lists not supported:\n" -+ "either C++ or non-GCC output: skipped\n", locerrstr); -+ return CTF_ERROR_REPORTED; -+ } -+ -+ *offset = location[0].number * 8; -+ break; -+ } -+ case DW_FORM_exprloc: -+ { -+ /* -+ * We need a full DWARF expression list interpreter to -+ * handle this. -+ */ -+ pr_err("DWARF 4 expression location lists not supported.\n"); -+ exit(1); -+ } -+ default: -+ { -+ pr_err("%s: expression location lists in form %u not supported.\n", -+ locerrstr, dwarf_whatform(&location_attr)); -+ exit(1); -+ } -+ } -+ } -+ -+ /* -+ * Handle the bit offset. -+ */ -+ if (private_dwarf_hasattr(die, DW_AT_bit_offset)) { -+ Dwarf_Attribute bit_attr; -+ Dwarf_Word bit; -+ -+ private_dwarf_attr(die, DW_AT_bit_offset, -+ &bit_attr); -+ dwarf_formudata(&bit_attr, &bit); -+ *bit_offset = bit; -+ } -+ -+ /* -+ * Handle the offset value override. It does not matter which method -+ * has been used to get the value. At this point offset is always -+ * the bit distance of the member from the structure/union start. -+ * -+ * The DW_AT_data_bit_offset override is always used to pass the offset -+ * around, so that we don't need to add special override handling for -+ * various forms of the DW_AT_data_member_location as a special case. -+ * This is safe as it is not possible to have both attributes attached -+ * to the same DIE per the DWARF4 standard, and if we have one attached -+ * as an override to a DIE that has the other, we will only ever need to -+ * use one (since no DIE can be both an unnamed struct/union and a -+ * bitfield at the same time). -+ */ -+ o = private_find_override(die, DW_AT_data_bit_offset, overrides); -+ if (o != NULL) { -+ if (o->op == DIE_OVERRIDE_REPLACE) -+ *offset = o->value; -+ else -+ *offset += o->value; -+ } -+ -+ return 0; -+} -+ -+/* -+ * Assemble a structure or union member. -+ * -+ * We only assemble a member of a given name if a member by that name does not -+ * already exist, and if the member is not blacklisted. -+ */ -+static ctf_id_t assemble_ctf_su_member(const char *module_name, -+ const char *file_name, -+ Dwarf_Die *die, -+ Dwarf_Die *parent_die, -+ ctf_file_t *ctf, -+ ctf_id_t parent_ctf_id, -+ const char *locerrstr, -+ struct die_override *overrides, -+ int top_level_type, -+ enum skip_type *skip, -+ int *replace) -+{ -+ ulong_t offset = 0; -+ ulong_t bit_offset = 0; -+ struct ctf_full_id *new_type; -+ Dwarf_Attribute type_attr; -+ Dwarf_Die type_die; -+ Dwarf_Die cu_die; -+ int err; -+ struct ctf_memb_count *member_count; -+ const char *struct_name = dwarf_diename(parent_die); -+ -+ CTF_DW_ENFORCE(type); -+ -+ /* -+ * Increment the member count of named structures. This is the number -+ * of members in the DWARF, not in the CTF: blacklisted members are -+ * counted too. -+ */ -+ if (struct_name != NULL) { -+ int is_union = (dwarf_tag(parent_die) == DW_TAG_union_type); -+ char *structized_name = NULL; -+ struct per_module *ctf_pm; -+ -+ structized_name = str_appendn(structized_name, -+ is_union ? "u " : "s ", -+ struct_name, NULL); -+ -+ ctf_pm = g_hash_table_lookup(per_module, module_name); -+ member_count = g_hash_table_lookup(ctf_pm->member_counts, -+ structized_name); -+ member_count->count++; -+ free(structized_name); -+ } -+ -+ /* -+ * If this member is blacklisted, just skip it. -+ */ -+ if (member_blacklisted(die, parent_die)) { -+ dw_ctf_trace("%s: blacklisted, skipping.\n", locerrstr); -+ return parent_ctf_id; -+ } -+ -+ /* -+ * Find the associated type so we can either add a member with that type -+ * (if it is named) or add its members directly (for unnamed types, -+ * which must be unnamed structs/unions): then figure out the member's -+ * offset. -+ */ -+ private_dwarf_attr(die, DW_AT_type, &type_attr); -+ if (dwarf_formref_die(&type_attr, &type_die) == NULL) { -+ pr_err("%s: nonexistent type reference.\n" -+ "Corrupted DWARF, cannot continue.\n", locerrstr); -+ exit(1); -+ } -+ dwarf_diecu(&type_die, &cu_die, NULL, NULL); -+ -+ err = ctf_su_offset(die, locerrstr, overrides, &offset, &bit_offset); -+ if (err < 0) { -+ *skip = SKIP_ABORT; -+ return err; -+ } -+ -+ /* -+ * If this is an unnamed struct/union, call directly back to -+ * die_to_ctf() to add this struct's members to the current structure, -+ * merging it seamlessly with its parent (excepting only the member -+ * offsets). Use DW_AT_data_bit_offset because it does not require -+ * the complexity of DW_AT_data_member_location to be faked. -+ */ -+ if (!private_dwarf_hasattr(die, DW_AT_name)) { -+ Dwarf_Die child_die; -+ int dummy = 0; -+ -+ if ((dwarf_tag(&type_die) != DW_TAG_structure_type) && -+ (dwarf_tag(&type_die) != DW_TAG_union_type)) { -+ pr_err("%s:%lx: not supported: anonymous structure member\n" -+ "not a structure or union.\n", locerrstr, -+ DIEOFFSET(die)); -+ *skip = SKIP_ABORT; -+ return CTF_ERROR_REPORTED; -+ } -+ -+ /* -+ * Anonymous structure or union with no members. Silently skip. -+ */ -+ switch (dwarf_child(&type_die, &child_die)) { -+ case -1: -+ *skip = SKIP_ABORT; -+ return CTF_ERROR_REPORTED; -+ case 1: /* No DIEs at all in this aggregate */ -+ return parent_ctf_id; -+ default: /* Child DIEs exist. */ -+ break; -+ } -+ -+ /* -+ * Add override that will adjust offset of the anonymous -+ * struct/union members during inlining. The bit_offset is -+ * ignored here as it is not expected that a nested -+ * structure/union will start on a non-byte-aligned boundary. -+ */ -+ struct die_override o[] = {{ dwarf_tag(&child_die), -+ DW_AT_data_bit_offset, -+ DIE_OVERRIDE_ADD, -+ offset, overrides }, {0}}; -+ -+ die_to_ctf(module_name, file_name, &child_die, parent_die, ctf, -+ parent_ctf_id, o, 0, 0, skip, &dummy, NULL); -+ -+ return parent_ctf_id; -+ } -+ -+ /* -+ * Get the CTF ID of this member's type, by recursive lookup. -+ * -+ * If this is a bitfield, we want to note that said type's size and -+ * bit-offset should be adjusted. -+ */ -+ if (private_dwarf_hasattr(die, DW_AT_bit_size)) { -+ struct die_override o[] = { -+ { DW_TAG_base_type, -+ DW_AT_bit_size, -+ DIE_OVERRIDE_REPLACE, -+ private_dwarf_udata(die, DW_AT_bit_size, -+ NULL), -+ NULL }, -+ { DW_TAG_base_type, -+ DW_AT_bit_offset, -+ DIE_OVERRIDE_REPLACE, -+ bit_offset, -+ overrides }, -+ {0} -+ }; -+ -+ new_type = construct_ctf_id(module_name, file_name, &type_die, -+ &cu_die, o); -+ } else { -+ if (bit_offset != 0) { -+ pr_err("%s:%s: error in member %s: No DW_AT_bit_size, but nonzero bit offset\n" -+ "of %lx in overall offset of %lx\n", locerrstr, -+ dwarf_diename(&cu_die), dwarf_diename(die), -+ bit_offset, offset); -+ return CTF_ERROR_REPORTED; -+ } -+ new_type = construct_ctf_id(module_name, file_name, &type_die, -+ &cu_die, NULL); -+ } -+ -+ if (new_type == NULL) { -+ *skip = SKIP_ABORT; -+ return CTF_ERROR_REPORTED; -+ } -+ -+ if ((new_type->ctf_file != ctf) && -+ (new_type->ctf_file != lookup_ctf_file("shared_ctf"))) { -+ pr_err("%s:%s: internal error: referenced type lookup for member %s\n" -+ "yields a different CTF file: %p versus %p\n", -+ locerrstr, dwarf_diename(&cu_die), dwarf_diename(die), -+ ctf, new_type->ctf_file); -+ pr_err("dedup() is probably buggy.\n"); -+ exit(1); -+ } -+ -+ if (ctf_add_member_offset(ctf, parent_ctf_id, dwarf_diename(die), -+ new_type->ctf_id, offset) < 0) { -+ /* -+ * If we have seen this member before, as part of another -+ * definition somewhere else, that's fine. We cannot recurse -+ * from this point, so we can just return the parent CTF ID, the -+ * ID of the containing structure. -+ */ -+ if (ctf_errno(ctf) == ECTF_DUPLICATE) -+ return parent_ctf_id; -+ -+ /* -+ * We have special handling for cases where CTF doesn't know of -+ * either this member's type or the enclosing structure: when -+ * libdtrace-ctf is old enough to need it, we try a ctf_update() -+ * in case this is recently added, but no special handling for -+ * other errors, which the caller must report. -+ */ -+ -+ if (ctf_errno(ctf) != ECTF_BADID && -+ ctf_errno(ctf) != ECTF_NOTSOU) -+ return CTF_NO_ERROR_REPORTED; -+ -+#ifndef LIBDTRACE_CTF_OMISSIBLE_CTF_UPDATE -+ ctf_file_t *shared_ctf; -+ -+ /* -+ * Try an update of the current CTF file first, to bring the -+ * type ID table up to date: if that doesn't work, try an update -+ * of the shared table. (If none is needed, this is cheap.) -+ */ -+ -+ if (ctf_update(new_type->ctf_file) < 0) { -+ pr_err("Cannot update CTF file: %s\n", -+ ctf_errmsg(ctf_errno(ctf))); -+ exit(1); -+ } -+ -+ if (ctf_add_member_offset(ctf, parent_ctf_id, -+ dwarf_diename(die), -+ new_type->ctf_id, -+ offset) == 0) -+ return parent_ctf_id; -+ -+ shared_ctf = lookup_ctf_file("shared_ctf"); -+ if (ctf_update(shared_ctf) < 0) { -+ pr_err("Cannot update shared CTF: %s\n", -+ ctf_errmsg(ctf_errno(shared_ctf))); -+ exit(1); -+ } -+ -+ if (ctf_add_member_offset(ctf, parent_ctf_id, -+ dwarf_diename(die), -+ new_type->ctf_id, -+ offset) == 0) -+ return parent_ctf_id; -+#endif -+#ifdef DEBUG -+ pr_err("%s: Internal error: %s %s:%s:%p:%i\n" -+ "on member addition to ctf_file %p.\n", -+ locerrstr, ctf_errmsg(ctf_errno(ctf)), -+ new_type->module_name, new_type->file_name, -+ new_type->ctf_file, (int) new_type->ctf_id, ctf); -+#else -+ pr_err("%s: Internal error: %s %p:%i\n" -+ "on member addition to ctf_file %p.\n", -+ locerrstr, ctf_errmsg(ctf_errno(ctf)), -+ new_type->ctf_file, (int) new_type->ctf_id, -+ ctf); -+#endif -+ return CTF_ERROR_REPORTED; -+ } -+ -+ return parent_ctf_id; -+} -+ -+/* -+ * Assemble a variable. -+ */ -+static ctf_id_t assemble_ctf_variable(const char *module_name, -+ const char *file_name, -+ Dwarf_Die *die, -+ Dwarf_Die *parent_die, -+ ctf_file_t *ctf, -+ ctf_id_t parent_ctf_id, -+ const char *locerrstr, -+ struct die_override *overrides, -+ int top_level_type, -+ enum skip_type *skip, -+ int *replace) -+{ -+ const char *name = dwarf_diename(die); -+ char *blacklist_name = NULL; -+ ctf_id_t type_ref; -+ int err; -+ -+ CTF_DW_ENFORCE(name); -+ -+ /* -+ * If blacklisted, just skip it. -+ */ -+ blacklist_name = str_appendn(blacklist_name, module_name, "`", -+ dwarf_diename(die), NULL); -+ if (g_hash_table_lookup_extended(variable_blacklist, blacklist_name, -+ NULL, NULL)) { -+ dw_ctf_trace("%s: variable %s is blacklisted for static/non-static ambiguity.\n", -+ file_name, blacklist_name); -+ free(blacklist_name); -+ return 0; -+ } -+ free(blacklist_name); -+ -+ type_ref = lookup_ctf_type(module_name, file_name, die, ctf, -+ overrides, locerrstr); -+ if (type_ref < 0) { -+ *skip = SKIP_ABORT; -+ return CTF_ERROR_REPORTED; -+ } -+ -+ /* -+ * This isn't a type: full DWARF child recursion and type-id addition is -+ * not called for. -+ */ -+ *skip = SKIP_SKIP; -+ -+ err = ctf_add_variable(ctf, name, type_ref); -+ -+ if (err == 0) -+ dw_ctf_trace("%p: Added variable %s, type %i\n", ctf, name, -+ (int)type_ref); -+ -+ /* -+ * Variable references to opaque versus non-opaque structures could only -+ * get deduplicated with yet another deduplication pass. This seems -+ * pointlessly expensive when nothing can refer to them: just skip -+ * duplicates instead. -+ */ -+ if ((err < 0) && (ctf_errno(ctf) == ECTF_DUPLICATE)) -+ return 0; -+ -+ return err; -+ -+} -+ -+/* Writeout. */ -+ -+static void write_types(char *output, int standalone) -+{ -+ GHashTableIter module_iter; -+ char *module; -+ struct per_module *per_mod; -+ ctf_file_t **ctfs; -+ const char **names; -+ size_t i = 0; -+ size_t ctf_count = g_hash_table_size(per_module); -+ -+ /* -+ * Work over all the modules and write their compressed CTF data out. -+ * Standalone modules get placed in files in the output directory named -+ * with names ending in .mod.ctf.new, and the makefile moves .ctf.new -+ * over the top of .ctf iff it has changed; built-in modules and the -+ * core kernel and shared type repository are placed into a CTF archive. -+ */ -+ if (standalone) { -+ if ((mkdir(output, 0777) < 0) && errno != EEXIST) { -+ perror("Cannot create .ctf directory"); -+ exit(1); -+ } -+ } else { -+ ctfs = calloc(ctf_count, sizeof(ctf_file_t *)); -+ names = calloc(ctf_count, sizeof(char *)); -+ if (!ctfs || !names) -+ pr_err("Out of memory in CTF writeout\n"); -+ } -+ -+ /* -+ * Write the files out (in standalone mode), or construct the arrays of -+ * module names and files to put in the archive (otherwise). -+ */ -+ g_hash_table_iter_init(&module_iter, per_module); -+ while (g_hash_table_iter_next(&module_iter, (void **) &module, -+ (void **)&per_mod)) { -+ int fd; -+ -+ dw_ctf_trace("Writing out %s\n", module); -+ -+ if (ctf_update(per_mod->ctf_file) < 0) { -+ pr_err("Cannot serialize CTF file %s: %s\n", -+ module, ctf_errmsg(ctf_errno(per_mod->ctf_file))); -+ exit(1); -+ } -+ -+ if (!standalone) { -+ names[i] = module; -+ ctfs[i] = per_mod->ctf_file; -+ i++; -+ } else { -+ char *path = NULL; -+ -+ path = str_appendn(path, output, "/", module, -+ ".mod.ctf.new", NULL); -+ -+ fd = open(path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, -+ 0666); -+ if (fd < 0) { -+ pr_err("Cannot open CTF file %s for writing: %s\n", -+ path, strerror(errno)); -+ exit(1); -+ } -+ if (ctf_compress_write(per_mod->ctf_file, fd) < 0) { -+ pr_err("Cannot write to CTF file %s: " -+ "%s\n", path, -+ ctf_errmsg(ctf_errno(per_mod->ctf_file))); -+ exit(1); -+ } -+ if (close(fd) != 0) { -+ pr_err("Cannot close CTF file %s: %s\n", -+ path, strerror(errno)); -+ exit(1); -+ } -+ free(path); -+ } -+ } -+ -+ if (!standalone) { -+ int err; -+ -+ err = ctf_arc_write(output, ctfs, ctf_count, names, 4096); -+ if (err != 0) { -+ pr_err("Cannot write to CTF archive %s: %s\n", -+ output, err < ECTF_BASE ? strerror(err) : -+ ctf_errmsg(err)); -+ exit(1); -+ } -+ free(names); -+ free(ctfs); -+ } -+} -+ -+/* Utilities. */ -+ -+/* -+ * Given a DIE that may contain a type attribute, look up the target of that -+ * attribute and return it, or NULL if none. -+ */ -+static Dwarf_Die *private_dwarf_type(Dwarf_Die *die, Dwarf_Die *target_die) -+{ -+ Dwarf_Attribute type_ref_attr; -+ -+ if (private_dwarf_attr(die, DW_AT_type, &type_ref_attr) != NULL) { -+ if (dwarf_formref_die(&type_ref_attr, target_die) == NULL) { -+ pr_err("Corrupt DWARF at offset %lx: ref with no target.\n", -+ DIEOFFSET(die)); -+ exit(1); -+ } -+ return target_die; -+ } -+ -+ return NULL; -+} -+ -+/* -+ * Check for existence of an attribute in a DIE, chasing through -+ * DW_AT_specification if need be. -+ */ -+static inline int private_dwarf_hasattr(Dwarf_Die *die, -+ unsigned int search_name) -+{ -+ int hasattr = 0; -+ Dwarf_Attribute spec_ref_attr; -+ Dwarf_Die spec_die; -+ -+ /* -+ * DW_AT_declaration is not forwarded, because non-declarations can -+ * reference declarations via DW_AT_specification, without implying that -+ * the referencing DIE is a declaration. -+ */ -+ hasattr = dwarf_hasattr(die, search_name); -+ if (hasattr || (search_name == DW_AT_declaration)) -+ return hasattr; -+ -+ if (dwarf_attr(die, DW_AT_specification, &spec_ref_attr) != NULL) { -+ if (dwarf_formref_die(&spec_ref_attr, &spec_die) == NULL) { -+ pr_err("Corrupt DWARF at offset %lx: ref with no target.\n", -+ DIEOFFSET(die)); -+ exit(1); -+ } -+ return dwarf_hasattr(&spec_die, search_name); -+ } -+ return hasattr; -+} -+ -+/* -+ * Return a DIE attribute, chasing through DW_AT_specification if need be. -+ */ -+static inline Dwarf_Attribute *private_dwarf_attr(Dwarf_Die *die, -+ unsigned int search_name, -+ Dwarf_Attribute *result) -+{ -+ Dwarf_Attribute spec_ref_attr; -+ Dwarf_Die spec_die; -+ Dwarf_Attribute *ret; -+ -+ ret = dwarf_attr(die, search_name, result); -+ if (ret != NULL || (search_name == DW_AT_declaration)) -+ return ret; -+ -+ if (dwarf_attr(die, DW_AT_specification, &spec_ref_attr) != NULL) { -+ if (dwarf_formref_die(&spec_ref_attr, &spec_die) == NULL) { -+ pr_err("Corrupt DWARF at offset %lx: ref with no target.\n", -+ DIEOFFSET(die)); -+ exit(1); -+ } -+ return dwarf_attr(&spec_die, search_name, result); -+ } -+ -+ return NULL; -+} -+ -+/* -+ * Given a DIE that contains a udata attribute, look up that attribute and -+ * return its value (optionally overridden or modified by the die_overrides). -+ */ -+static inline Dwarf_Word private_dwarf_udata(Dwarf_Die *die, int attribute, -+ struct die_override *overrides) -+{ -+ Dwarf_Attribute attr; -+ Dwarf_Word value; -+ struct die_override *override; -+ -+ override = private_find_override(die, attribute, overrides); -+ -+ if (override && override->op == DIE_OVERRIDE_REPLACE) -+ return override->value; -+ -+ private_dwarf_attr(die, attribute, &attr); -+ dwarf_formudata(&attr, &value); -+ -+ if (override) -+ value += override->value; -+ -+ return value; -+} -+ -+/* -+ * Given a DIE, return its byte size, if known and interpretable, or -1 -+ * otherwise. -+ */ -+static inline long long -+private_dwarf_size(Dwarf_Die *die) -+{ -+ Dwarf_Attribute size_attr; -+ -+ if (private_dwarf_hasattr(die, DW_AT_byte_size)) { -+ private_dwarf_attr(die, DW_AT_byte_size, &size_attr); -+ -+ switch (dwarf_whatform(&size_attr)) { -+ case DW_FORM_data1: -+ case DW_FORM_data2: -+ case DW_FORM_data4: -+ case DW_FORM_data8: -+ case DW_FORM_udata: { -+ Dwarf_Word dw_size; -+ -+ dwarf_formudata(&size_attr, &dw_size); -+ return dw_size; -+ } -+ case DW_FORM_sdata: { -+ Dwarf_Sword dw_size; -+ -+ dwarf_formsdata(&size_attr, &dw_size); -+ return dw_size; -+ } -+ } -+ } -+ -+ /* -+ * exprloc or other type we don't know how to interpret yet. -+ */ -+ return -1; -+} -+ -+/* -+ * Find an override in an override list, walking up the chained overrides if -+ * need be, until one is found. -+ */ -+static struct die_override * -+private_find_override(Dwarf_Die *die, -+ int attribute, -+ struct die_override *overrides) -+{ -+ size_t i; -+ -+ if (overrides == NULL) -+ return NULL; -+ -+ while (overrides) { -+ struct die_override *chain = NULL; -+ for (i = 0; overrides[i].tag != 0; i++) { -+ chain = overrides[i].chain; -+ if ((overrides[i].tag == dwarf_tag(die)) && -+ (overrides[i].attribute == attribute)) -+ return &overrides[i]; -+ } -+ overrides = chain; -+ } -+ -+ return NULL; -+} -+ -+/* -+ * Determine the dimensions of an array subrange, or 0 if variable. -+ */ -+static Dwarf_Word private_subrange_dimensions(Dwarf_Die *die) -+{ -+ int flexible_array = 0; -+ Dwarf_Attribute nelem_attr; -+ Dwarf_Word nelems; -+ -+ if (((private_dwarf_attr(die, DW_AT_upper_bound, -+ &nelem_attr) == NULL) && -+ (private_dwarf_attr(die, DW_AT_count, -+ &nelem_attr) == NULL)) || -+ (!private_dwarf_hasattr(die, DW_AT_type))) -+ flexible_array = 1; -+ -+ if (!flexible_array) -+ switch (dwarf_whatform(&nelem_attr)) { -+ case DW_FORM_data1: -+ case DW_FORM_data2: -+ case DW_FORM_data4: -+ case DW_FORM_data8: -+ case DW_FORM_udata: -+ break; -+ default: -+ flexible_array = 1; -+ } -+ -+ if (flexible_array) -+ return 0; -+ -+ dwarf_formudata(&nelem_attr, &nelems); -+ -+ /* -+ * Upper bounds indicate that we have one more element than that, since -+ * C starts counting at zero. -+ */ -+ if (private_dwarf_hasattr(die, DW_AT_upper_bound)) -+ nelems++; -+ -+ return nelems; -+} -+ -+/* -+ * Intern an atom in the atoms table and return it, or free it and return the -+ * existing atom if one is already interned. (Despite the type signature, this -+ * return value is constant and should not be freed.) -+ */ -+static void *intern(char *atom) -+{ -+ void *foo; -+ -+ if (!g_hash_table_lookup_extended(atoms, atom, &foo, NULL)) { -+ g_hash_table_insert(atoms, atom, NULL); -+ foo = atom; -+ } else -+ free(atom); -+ -+ return foo; -+} -+ -+/* -+ * An error checking strdup(). -+ */ -+static char *xstrdup(const char *s) -+{ -+ char *s2 = strdup(s); -+ -+ if (s2 == NULL) { -+ pr_err("%s: Out of memory\n", __func__); -+ exit(1); -+ } -+ -+ return s2; -+} -+ -+/* -+ * A string appender working on dynamic strings. -+ */ -+static char *str_append(char *s, const char *append) -+{ -+ size_t s_len = 0; -+ -+ if (append == NULL) -+ return s; -+ -+ if (s != NULL) -+ s_len = strlen(s); -+ -+ size_t append_len = strlen(append); -+ -+ s = realloc(s, s_len + append_len + 1); -+ -+ if (s == NULL) { -+ pr_err("Out of memory appending a string of length %li to one of length %li\n", -+ strlen(append), s_len); -+ exit(1); -+ } -+ -+ memcpy(s + s_len, append, append_len); -+ s[s_len+append_len] = '\0'; -+ -+ return s; -+} -+ -+/* -+ * A vararg string appender. -+ */ -+static char *str_appendn(char *s, ...) -+{ -+ va_list ap; -+ const char *append; -+ size_t len, s_len = 0; -+ -+ va_start(ap, s); -+ if (s) -+ s_len = strlen(s); -+ len = s_len; -+ -+ append = va_arg(ap, const char *); -+ while (append != NULL) { -+ len += strlen(append); -+ append = va_arg(ap, char *); -+ } -+ va_end(ap); -+ -+ s = realloc(s, len + 1); -+ if (s == NULL) { -+ pr_err("Out of memory appending a string of length %li to one of length %li\n", -+ len - s_len, s_len); -+ exit(1); -+ } -+ -+ va_start(ap, s); -+ append = va_arg(ap, const char *); -+ while (append != NULL) { -+ size_t append_len = strlen(append); -+ -+ memcpy(s + s_len, append, append_len); -+ s_len += append_len; -+ -+ append = va_arg(ap, char *); -+ } -+ s[len] = '\0'; -+ va_end(ap); -+ -+ return s; -+} -+ -+/* -+ * Filter a GList, calling a predicate on it and removing all elements for which -+ * the predicate returns true, calling the free_func on them if set. -+ */ -+static GList *list_filter(GList *list, filter_pred_fun fun, -+ GDestroyNotify free_func, void *data) -+{ -+ GList *cur = list; -+ -+ while (cur) { -+ GList *next = cur->next; -+ -+ if (fun(cur->data, data)) { -+ if (free_func) -+ free_func(cur->data); -+ list = g_list_delete_link(list, cur); -+ } -+ cur = next; -+ } -+ -+ return list; -+} -+ -+/* -+ * Figure out the (pathless, suffixless) module name for a given module file (.o -+ * or .ko), and return it in a new dynamically allocated string. -+ * -+ * Takes the object_to_module mapping into account. -+ */ -+static char *fn_to_module(const char *file_name) -+{ -+ char *module_name; -+ char *chop, *dash; -+ -+ module_name = g_hash_table_lookup(object_to_module, file_name); -+ if (module_name != NULL) -+ return xstrdup(module_name); -+ -+ chop = strrchr(file_name, '/'); -+ if (chop != NULL) -+ module_name = xstrdup(++chop); -+ else -+ module_name = xstrdup(file_name); -+ -+ chop = strrchr(module_name, '.'); -+ if (chop != NULL) -+ *chop = '\0'; -+ -+ dash = module_name; -+ while (dash != NULL) { -+ dash = strchr(dash, '-'); -+ if (dash != NULL) -+ *dash = '_'; -+ } -+ -+ return module_name; -+} -+ -+/* -+ * Determine, and cache, absolute filenames. This is called in very hot -+ * paths, notably type_id(), and must be kept fast. -+ */ -+static const char *abs_file_name(const char *file_name) -+{ -+ static GHashTable *abs_file_names; -+ const char *abs_name; -+ -+ if (abs_file_names == NULL) -+ abs_file_names = g_hash_table_new_full(g_str_hash, g_str_equal, -+ free, free); -+ -+ abs_name = g_hash_table_lookup(abs_file_names, file_name); -+ -+ if (abs_name == NULL) { -+ char abspath[PATH_MAX] = ""; -+ -+ if (realpath(file_name, abspath) == NULL) -+ strcpy(abspath, file_name); -+ g_hash_table_replace(abs_file_names, -+ xstrdup(file_name), xstrdup(abspath)); -+ -+ abs_name = g_hash_table_lookup(abs_file_names, file_name); -+ } -+ -+ return abs_name; -+} -+ -+/* -+ * Determine absolute filenames relative to some other directory. This does not -+ * need to be fast. The returned name is dynamically allocated, and must be -+ * freed by the caller. -+ */ -+static char *rel_abs_file_name(const char *file_name, const char *relative_to) -+{ -+ int dir = -1; -+ static int warned = 0; -+ char *abspath; -+ /* -+ * If we can't get this name relatively, we might as well *try* to do it -+ * absolutely: but print a warning. -+ */ -+ dir = open(".", O_RDONLY | O_DIRECTORY); -+ if (dir < 0) { -+ if (!warned) { -+ perror("Cannot open current directory"); -+ warned = 1; -+ } -+ } else { -+ if (chdir(relative_to) < 0) -+ if (!warned) { -+ pr_err("Cannot change directory to " -+ "%s: %s\n", relative_to, -+ strerror(errno)); -+ warned = 1; -+ } -+ } -+ -+ abspath = realpath(file_name, NULL); -+ if (abspath == NULL) -+ abspath = xstrdup(file_name); -+ -+ if ((dir > -1) && (fchdir(dir) < 0)) { -+ perror("Cannot return to original directory after relative realpath()"); -+ exit(1); -+ } -+ -+ close(dir); -+ -+ return abspath; -+} -+ -+/* -+ * Given a type encoding table, and a size, return the CTF encoding for that -+ * type, or 0 if none. -+ */ -+static int find_ctf_encoding(struct type_encoding_tab *type_tab, size_t size) -+{ -+ size_t i; -+ -+ for (i = 0; type_tab[i].size != 0; i++) { -+ if (type_tab[i].size == size) -+ return type_tab[i].ctf_encoding; -+ } -+ return 0; -+} -+ -+/* -+ * Count the number of members of a DWARF aggregate. -+ */ -+static long count_dwarf_members(Dwarf_Die *d) -+{ -+ const char *err; -+ Dwarf_Die die; -+ -+ switch (dwarf_child(d, &die)) { -+ case -1: -+ err = "fetch first child of aggregate"; -+ goto fail; -+ case 1: /* No DIEs at all in this aggregate */ -+ return 0; -+ default: /* Child DIEs exist. */ -+ break; -+ } -+ -+ /* -+ * We are only interested in children of type DW_TAG_member. -+ */ -+ int sib_ret; -+ long count = 0; -+ -+ do -+ if (dwarf_tag(&die) == DW_TAG_member) -+ count++; -+ while ((sib_ret = dwarf_siblingof(&die, &die)) == 0); -+ -+ if (sib_ret == -1) { -+ err = "count members"; -+ goto fail; -+ } -+ -+ return count; -+ -+ fail: -+ pr_err("Cannot %s: %s\n", err, dwarf_errmsg(dwarf_errno())); -+ exit(1); -+} -+ -+/* -+ * Free a per_module's contents. -+ */ -+static void private_per_module_free(void *per_module) -+{ -+ struct per_module *per_mod = per_module; -+ -+ ctf_close(per_mod->ctf_file); -+ g_hash_table_destroy(per_mod->member_counts); -+ free(per_module); -+} -+ -+/* -+ * Free a fn_to_die_to_parent subhash. -+ */ -+static void private_fn_die_parent_free(void *ptr) -+{ -+ g_hash_table_destroy((GHashTable *) ptr); -+} -+ -+/* -+ * Get a ctf_file out of the per_module hash for a given module. -+ */ -+static ctf_file_t *lookup_ctf_file(const char *module_name) -+{ -+ struct per_module *per_mod; -+ -+ per_mod = g_hash_table_lookup(per_module, module_name); -+ if (per_mod == NULL) -+ return NULL; -+ return per_mod->ctf_file; -+} -diff --git a/scripts/dwarf2ctf/eu_simple.c b/scripts/dwarf2ctf/eu_simple.c -new file mode 100644 -index 0000000000000000000000000000000000000000..49886e5e541105ff517694db0ed3f00a096d16ae ---- /dev/null -+++ b/scripts/dwarf2ctf/eu_simple.c -@@ -0,0 +1,2 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+#include "../eu_simple.c" -diff --git a/scripts/dwarf2ctf/member.blacklist b/scripts/dwarf2ctf/member.blacklist -new file mode 100644 -index 0000000000000000000000000000000000000000..85122def7b5f652881aa6588c407f91abf641017 ---- /dev/null -+++ b/scripts/dwarf2ctf/member.blacklist -@@ -0,0 +1 @@ -+include/linux/netfilter/ipset/ip_set_ahash.h:ip_set_hash.next -diff --git a/scripts/eu_simple.c b/scripts/eu_simple.c -new file mode 100644 -index 0000000000000000000000000000000000000000..e2736f29d00113912534c07cae6b41d97ffe8db0 ---- /dev/null -+++ b/scripts/eu_simple.c -@@ -0,0 +1,356 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Convenience wrappers for functions in elfutils. -+ * -+ * (C) 2014, 2017 Oracle, Inc. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <errno.h> -+#include <stdio.h> -+#include <stdlib.h> -+#include <string.h> -+ -+#include <elfutils/libdwfl.h> -+#include <elfutils/version.h> -+ -+#include <eu_simple.h> -+ -+#define __unused__ __attribute__((__unused__)) -+ -+/* -+ * A version of dwfl_report_elf() that compensates for parameter changes in -+ * newer elfutils. -+ */ -+static Dwfl_Module *private_dwfl_report_elf(Dwfl *dwfl, const char *name, -+ const char *file_name, int fd, -+ GElf_Addr base) -+{ -+#if _ELFUTILS_PREREQ(0,156) -+ return dwfl_report_elf(dwfl, name, file_name, fd, base, 0); -+#else -+ return dwfl_report_elf(dwfl, name, file_name, fd, base); -+#endif -+} -+ -+/* -+ * Stub libdwfl callback, use only the ELF handle passed in. -+ */ -+static int no_debuginfo(Dwfl_Module *mod __unused__, -+ void **userdata __unused__, -+ const char *modname __unused__, -+ Dwarf_Addr base __unused__, -+ const char *file_name __unused__, -+ const char *debuglink_file __unused__, -+ GElf_Word debuglink_crc __unused__, -+ char **debuginfo_file_name __unused__) -+{ -+ return -1; -+} -+ -+/* -+ * Wrap up dwfl_new() complexities. -+ */ -+Dwfl *simple_dwfl_new(const char *file_name, Dwfl_Module **module) -+{ -+ const char *err; -+ -+ static Dwfl_Callbacks cb = { -+ .find_debuginfo = no_debuginfo, -+ .section_address = dwfl_offline_section_address -+ }; -+ Dwfl *dwfl = dwfl_begin(&cb); -+ Dwfl_Module *mod; -+ -+ if (dwfl == NULL) { -+ err = "initialize libdwfl"; -+ goto fail; -+ } -+ -+ mod = private_dwfl_report_elf(dwfl, "", file_name, -1, 0); -+ if (mod == NULL) { -+ err = "open object file with libdwfl"; -+ goto fail; -+ } -+ if (module) -+ *module = mod; -+ -+ if (dwfl_report_end(dwfl, NULL, NULL) != 0) { -+ err = "finish opening object file with libdwfl"; -+ goto fail; -+ } -+ -+ return dwfl; -+ fail: -+ fprintf(stderr, "Cannot %s for %s: %s\n", err, file_name, -+ dwfl_errmsg(dwfl_errno())); -+ exit(1); -+} -+ -+/* -+ * A variant of simple_dwfl_new() that iterates over multiple object files. -+ * (Used for thin archives.) -+ * -+ * Takes ownership of the paths, until free. -+ */ -+struct simple_dwfl_multi * -+simple_dwfl_new_multi(char **paths) -+{ -+ struct simple_dwfl_multi *multi; -+ -+ multi = malloc(sizeof(struct simple_dwfl_multi)); -+ if (multi == NULL) -+ return NULL; -+ -+ multi->paths = paths; -+ multi->i = -1; -+ multi->dwfl = NULL; -+ multi->last_die = NULL; -+ -+ return multi; -+} -+ -+/* -+ * A variant of dwfl_nextcu() that crosses file boundaries as needed, -+ * using the state in the simple_dwfl_multi. -+ */ -+Dwarf_Die * -+simple_dwfl_nextcu(struct simple_dwfl_multi *multi) -+{ -+ Dwarf_Addr junk; -+ -+ /* -+ * Switch object files as needed (and always, the first time). -+ */ -+ -+ if (multi->i >= 0) -+ multi->last_die = dwfl_nextcu(multi->dwfl, multi->last_die, -+ &junk); -+ -+ while (multi->last_die == NULL) { -+ simple_dwfl_free(multi->dwfl); -+ if (multi->paths[++multi->i] == NULL) { -+ multi->i = -1; -+ multi->dwfl = NULL; -+ multi->last_die = NULL; -+ return NULL; -+ } -+ -+ multi->dwfl = simple_dwfl_new(multi->paths[multi->i], NULL); -+ multi->last_die = dwfl_nextcu(multi->dwfl, multi->last_die, -+ &junk); -+ } -+ return multi->last_die; -+} -+ -+/* -+ * Free a simple_dwfl_new_multi: return its contained paths so the caller can -+ * free them again. (They are not changed, so the caller can just hang on to -+ * them if preferred.) -+ */ -+char ** -+simple_dwfl_free_multi(struct simple_dwfl_multi *multi) -+{ -+ char **paths = multi->paths; -+ simple_dwfl_free(multi->dwfl); -+ free(multi); -+ return paths; -+} -+ -+/* -+ * The converse of simple_dwfl_new(). -+ */ -+void simple_dwfl_free(Dwfl *dwfl) -+{ -+ if (dwfl != NULL) { -+ dwfl_report_end(dwfl, NULL, NULL); -+ dwfl_end(dwfl); -+ } -+} -+ -+ -+/* -+ * Read a modules_thick.builtin file and translate it into a stream of -+ * arguments suitable for simple_dwfl_new_multi(). -+ */ -+ -+/* -+ * Construct a modules_thick.builtin iterator. -+ */ -+struct modules_thick_iter * -+modules_thick_iter_new(const char *modules_thick_file) -+{ -+ struct modules_thick_iter *i; -+ -+ i = calloc(1, sizeof(struct modules_thick_iter)); -+ if (i == NULL) -+ return NULL; -+ -+ i->f = fopen(modules_thick_file, "r"); -+ -+ if (i->f == NULL) { -+ fprintf(stderr, "Cannot open builtin module file %s: %s\n", -+ modules_thick_file, strerror(errno)); -+ return NULL; -+ } -+ -+ return i; -+} -+ -+/* -+ * Iterate, returning a new null-terminated array of object file names, and a -+ * new dynamically-allocated module name. (The module name passed in is freed.) -+ * -+ * The array of object file names should be freed by the caller: the strings it -+ * points to are owned by the iterator, and should not be freed. -+ */ -+ -+char ** __attribute__((__nonnull__)) -+modules_thick_iter_next(struct modules_thick_iter *i, char **module_name) -+{ -+ size_t npaths = 1; -+ char **module_paths; -+ char *last_slash; -+ char *last_dot; -+ char *trailing_linefeed; -+ char *object_name = i->line; -+ char *dash; -+ int composite = 0; -+ -+ /* -+ * Read in all module entries, computing the suffixless, pathless name -+ * of the module and building the next arrayful of object file names for -+ * return. -+ * -+ * Modules can consist of multiple files: in this case, the portion -+ * before the colon is the path to the module (as before): the portion -+ * after the colon is a space-separated list of files that should be * -+ * considered part of this module. In this case, the portion before the -+ * name is an "object file" that does not actually exist: it is merged -+ * into built-in.a without ever being written out. -+ * -+ * All module names have - translated to _, to match what is done to the -+ * names of the same things when built as modules. -+ */ -+ -+ /* -+ * Reinvocation of exhausted iterator. Return NULL, once. -+ */ -+retry: -+ if (getline(&i->line, &i->line_size, i->f) < 0) { -+ if (ferror(i->f)) { -+ fprintf(stderr, "Error reading from modules_thick file:" -+ " %s\n", strerror(errno)); -+ exit(1); -+ } -+ rewind(i->f); -+ return NULL; -+ } -+ -+ if (i->line[0] == '\0') -+ goto retry; -+ -+ /* -+ * Slice the line in two at the colon, if any. If there is anything -+ * past the ': ', this is a composite module. (We allow for no colon -+ * for robustness, even though one should always be present.) -+ */ -+ if (strchr(i->line, ':') != NULL) { -+ char *name_start; -+ -+ object_name = strchr(i->line, ':'); -+ *object_name = '\0'; -+ object_name++; -+ name_start = object_name + strspn(object_name, " \n"); -+ if (*name_start != '\0') { -+ composite = 1; -+ object_name = name_start; -+ } -+ } -+ -+ /* -+ * Figure out the module name. -+ */ -+ last_slash = strrchr(i->line, '/'); -+ last_slash = (!last_slash) ? i->line : -+ last_slash + 1; -+ free(*module_name); -+ *module_name = strdup(last_slash); -+ dash = *module_name; -+ -+ while (dash != NULL) { -+ dash = strchr(dash, '-'); -+ if (dash != NULL) -+ *dash = '_'; -+ } -+ -+ last_dot = strrchr(*module_name, '.'); -+ if (last_dot != NULL) -+ *last_dot = '\0'; -+ -+ trailing_linefeed = strchr(object_name, '\n'); -+ if (trailing_linefeed != NULL) -+ *trailing_linefeed = '\0'; -+ -+ /* -+ * Multifile separator? Object file names explicitly stated: -+ * slice them up and shuffle them in. -+ * -+ * The array size may be an overestimate if any object file -+ * names start or end with spaces (very unlikely) but cannot be -+ * an underestimate. (Check for it anyway.) -+ */ -+ if (composite) { -+ char *one_object; -+ -+ for (npaths = 0, one_object = object_name; -+ one_object != NULL; -+ npaths++, one_object = strchr(one_object + 1, ' ')); -+ } -+ -+ module_paths = malloc((npaths + 1) * sizeof(char *)); -+ if (!module_paths) { -+ fprintf(stderr, "%s: out of memory on module %s\n", __func__, -+ *module_name); -+ exit(1); -+ } -+ -+ if (composite) { -+ char *one_object; -+ size_t i = 0; -+ -+ while ((one_object = strsep(&object_name, " ")) != NULL) { -+ if (i >= npaths) { -+ fprintf(stderr, "%s: num_objs overflow on module " -+ "%s: this is a bug.\n", __func__, -+ *module_name); -+ exit(1); -+ } -+ -+ module_paths[i++] = one_object; -+ } -+ } else -+ module_paths[0] = i->line; /* untransformed module name */ -+ -+ module_paths[npaths] = NULL; -+ -+ return module_paths; -+} -+ -+/* -+ * Free an iterator. Can be called while iteration is underway, so even -+ * state that is freed at the end of iteration must be freed here too. -+ */ -+void -+modules_thick_iter_free(struct modules_thick_iter *i) -+{ -+ if (i == NULL) -+ return; -+ fclose(i->f); -+ free(i->line); -+ free(i); -+} -diff --git a/scripts/eu_simple.h b/scripts/eu_simple.h -new file mode 100644 -index 0000000000000000000000000000000000000000..8ef9f96550772495c219d24136e75bcaf26aa62c ---- /dev/null -+++ b/scripts/eu_simple.h -@@ -0,0 +1,91 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Simplifying wrappers for functions in elfutils, and functions to -+ * feed them data. -+ * -+ * (C) 2014, 2017 Oracle, Inc. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#ifndef _LINUX_EU_SIMPLE_H -+#define _LINUX_EU_SIMPLE_H -+ -+#include <stdio.h> -+#include <stddef.h> -+#include <elfutils/libdwfl.h> -+ -+/* -+ * Iteration state for simple_dwfl_new_multi(). -+ */ -+struct simple_dwfl_multi { -+ char **paths; -+ ssize_t i; -+ Dwfl *dwfl; -+ Dwarf_Die *last_die; -+}; -+ -+/* -+ * Wrap up dwfl_new() complexities. -+ */ -+Dwfl *simple_dwfl_new(const char *file_name, Dwfl_Module **module); -+ -+/* -+ * A variant of simple_dwfl_new() that iterates over multiple object files. -+ * (Used for thin archives.) -+ * -+ * Takes ownership of the paths, until free. -+ */ -+struct simple_dwfl_multi *simple_dwfl_new_multi(char **paths); -+ -+/* -+ * A variant of dwfl_nextcu() that crosses file boundaries as needed, -+ * using the state in the simple_dwfl_multi. -+ */ -+Dwarf_Die *simple_dwfl_nextcu(struct simple_dwfl_multi *multi); -+ -+/* -+ * Free a simple_dwfl_new_multi: return its contained paths so the caller -+ * free them again. (They are not changed, so the caller can just hang on to -+ * them if preferred.) -+ */ -+char **simple_dwfl_free_multi(struct simple_dwfl_multi *multi); -+ -+/* -+ * The converse of simple_dwfl_new(). -+ */ -+void simple_dwfl_free(Dwfl *dwfl); -+ -+/* -+ * modules_thick.builtin iteration state. -+ */ -+struct modules_thick_iter { -+ FILE *f; -+ char *line; -+ size_t line_size; -+}; -+ -+/* -+ * Construct a modules_thick.builtin iterator. -+ */ -+struct modules_thick_iter * -+modules_thick_iter_new(const char *modules_thick_file); -+ -+/* -+ * Iterate, returning a new null-terminated array of object file names, and a -+ * new dynamically-allocated module name. (The module name passed in is freed.) -+ * -+ * The array of object file names should be freed by the caller: the strings it -+ * points to are owned by the iterator, and should not be freed. -+ */ -+ -+char ** __attribute__((__nonnull__)) -+modules_thick_iter_next(struct modules_thick_iter *i, char **module_name); -+ -+void -+modules_thick_iter_free(struct modules_thick_iter *i); -+ -+#endif -diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c -index a39d93e3c6ae8d34f617b835d8ebcf5900cbad89..12445a834698db42be674f907f2e82422d8eb8e2 100644 ---- a/scripts/kconfig/confdata.c -+++ b/scripts/kconfig/confdata.c -@@ -710,6 +710,25 @@ static struct conf_printer header_printer_cb = - .print_comment = header_print_comment, - }; - -+/* -+ * Tristate printer -+ * -+ * This printer is used when generating the `include/config/tristate.conf' file. -+ */ -+static void -+tristate_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg) -+{ -+ -+ if (sym->type == S_TRISTATE && *value != 'n') -+ fprintf(fp, "%s%s=%c\n", CONFIG_, sym->name, (char)toupper(*value)); -+} -+ -+static struct conf_printer tristate_printer_cb = -+{ -+ .print_symbol = tristate_print_symbol, -+ .print_comment = kconfig_print_comment, -+}; -+ - static void conf_write_symbol(FILE *fp, struct symbol *sym, - struct conf_printer *printer, void *printer_arg) - { -@@ -1043,7 +1062,7 @@ int conf_write_autoconf(int overwrite) - struct symbol *sym; - const char *name; - const char *autoconf_name = conf_get_autoconfig_name(); -- FILE *out, *out_h; -+ FILE *out, *tristate, *out_h; - int i; - - if (!overwrite && is_present(autoconf_name)) -@@ -1058,6 +1077,13 @@ int conf_write_autoconf(int overwrite) - if (!out) - return 1; - -+ tristate = fopen(".tmpconfig_tristate", "w"); -+ if (!tristate) { -+ fclose(out); -+ fclose(tristate); -+ return 1; -+ } -+ - out_h = fopen(".tmpconfig.h", "w"); - if (!out_h) { - fclose(out); -@@ -1065,6 +1091,7 @@ int conf_write_autoconf(int overwrite) - } - - conf_write_heading(out, &kconfig_printer_cb, NULL); -+ conf_write_heading(tristate, &tristate_printer_cb, NULL); - conf_write_heading(out_h, &header_printer_cb, NULL); - - for_all_symbols(i, sym) { -@@ -1072,11 +1099,13 @@ int conf_write_autoconf(int overwrite) - if (!(sym->flags & SYMBOL_WRITE) || !sym->name) - continue; - -- /* write symbols to auto.conf and autoconf.h */ -+ /* write symbols to auto.conf, tristate and header files */ - conf_write_symbol(out, sym, &kconfig_printer_cb, (void *)1); -+ conf_write_symbol(tristate, sym, &tristate_printer_cb, (void *)1); - conf_write_symbol(out_h, sym, &header_printer_cb, NULL); - } - fclose(out); -+ fclose(tristate); - fclose(out_h); - - name = getenv("KCONFIG_AUTOHEADER"); -@@ -1087,6 +1116,14 @@ int conf_write_autoconf(int overwrite) - if (rename(".tmpconfig.h", name)) - return 1; - -+ name = getenv("KCONFIG_TRISTATE"); -+ if (!name) -+ name = "include/config/tristate.conf"; -+ if (make_parent_dir(name)) -+ return 1; -+ if (rename(".tmpconfig_tristate", name)) -+ return 1; -+ - if (make_parent_dir(autoconf_name)) - return 1; - /* -diff --git a/scripts/move-if-change b/scripts/move-if-change -new file mode 100755 -index 0000000000000000000000000000000000000000..eb745af5d972bd147b0e8bc9e3be643dde25e91e ---- /dev/null -+++ b/scripts/move-if-change -@@ -0,0 +1,8 @@ -+#!/bin/sh -+# SPDX-License-Identifier: GPL-2.0+ -+ -+if test -r "$2" && cmp -s "$1" "$2"; then -+ rm -f "$1" -+else -+ mv -f "$1" "$2" -+fi -diff --git a/scripts/package/mkspec b/scripts/package/mkspec -index 7c477ca7dc9826a0d4bd63e332b4d5959894836a..e9ff22c6fb4c7c7082767c7c9b164e94735ea1e7 100755 ---- a/scripts/package/mkspec -+++ b/scripts/package/mkspec -@@ -27,6 +27,13 @@ if grep -q CONFIG_DRM=y .config; then - PROVIDES=kernel-drm - fi - -+# set CTF when configured -+if grep -q CONFIG_CTF=y .config; then -+ C= -+else -+ C=DEL -+fi -+ - PROVIDES="$PROVIDES kernel-$KERNELRELEASE" - __KERNELRELEASE=$(echo $KERNELRELEASE | sed -e "s/-/_/g") - EXCLUDES="$RCS_TAR_IGNORE --exclude=*vmlinux* --exclude=*.mod \ -@@ -38,6 +45,7 @@ EXCLUDES="$RCS_TAR_IGNORE --exclude=*vmlinux* --exclude=*.mod \ - # Labels: - # $S: this line is enabled only when building source package - # $M: this line is enabled only when CONFIG_MODULES is enabled -+# $C: this line is enabled only when CONFIG_CTF is enabled - sed -e '/^DEL/d' -e 's/^\t*//' <<EOF - Name: kernel - Summary: The Linux Kernel -@@ -48,6 +56,8 @@ sed -e '/^DEL/d' -e 's/^\t*//' <<EOF - Vendor: The Linux Community - URL: https://www.kernel.org - $S Source: kernel-$__KERNELRELEASE.tar.gz -+$C BuildRequires: libdtrace-ctf >= 0.5.0 -+$C BuildRequires: libdtrace-ctf-devel >= 0.5.0 - Provides: $PROVIDES - %define __spec_install_post /usr/lib/rpm/brp-compress || : - %define debug_package %{nil} -@@ -74,12 +84,14 @@ $S$M AutoReqProv: no - $S$M %description -n kernel-devel - $S$M This package provides kernel headers and makefiles sufficient to build modules - $S$M against the $__KERNELRELEASE kernel package. -+$C Requires: libdtrace-ctf >= 0.5.0 - $S$M - $S %prep - $S %setup -q - $S - $S %build - $S $MAKE %{?_smp_mflags} KBUILD_BUILD_VERSION=%{release} -+$S$C $MAKE %{?_smp_mflags} ctf - $S - %install - mkdir -p %{buildroot}/boot --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/dtrace-patches/0002-kallsyms-introduce-new-proc-kallmodsyms-including-bu.patch b/sys-kernel/cairn-sources/files/5.10.14/dtrace-patches/0002-kallsyms-introduce-new-proc-kallmodsyms-including-bu.patch deleted file mode 100644 index 96fcb3a363bb..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/dtrace-patches/0002-kallsyms-introduce-new-proc-kallmodsyms-including-bu.patch +++ /dev/null @@ -1,1050 +0,0 @@ -From 6ded42dd15783a073c9a15ad4abae87bcf234c40 Mon Sep 17 00:00:00 2001 -From: Nick Alcock <nick.alcock@oracle.com> -Date: Wed, 14 Nov 2018 20:09:28 +0000 -Subject: [PATCH 02/19] kallsyms: introduce new /proc/kallmodsyms including - builtin modules too - -/proc/kallsyms is very useful for tracers and other tools that need to -map kernel symbols to addresses (sinful though it is to export such -addresses to userspace). However, for some uses it does not suffice. -We would like to be able to establish a mapping between module name and -kernel symbol that only changes when the kernel source code is changed: -if the kernel is recompiled so that some module becomes built in, it is -a desirable property for portability of tracing scripts that can include -module names if the name of this module does not change. - -i.e., as with the previous dwarf2ctf commit, we would like to report -e.g. ext4 symbols as residing in [ext4] even if ext4 happens to be built -into the kernel: it is enough that it *could* be built as a module. - -We use machinery shared with dwarf2ctf (in eu_simple.c) in conjunction -with a link map to compute the mapping from the address ranges -associated with built-in object files in vmlinux.o to module names, then -drop a list of these modules and pointers into that list into new -kallsyms sections (kallsyms_modules and kallsyms_symbol_modules). - -We also need symbol sizes to determine whether a given probe hit is -within a symbol or outside it (possibly miles outside it in a gap -between symbols). Adding that is much simpler, with only one new -section, kallsyms_sizes. - -The resulting file looks like this: - -ffffffff8b013d20 409 t pt_buffer_setup_aux -ffffffff8b014130 11f T intel_pt_interrupt -ffffffff8b014250 2d T cpu_emergency_stop_pt -ffffffff8b014280 13a t rapl_pmu_event_init [intel_rapl_perf] -ffffffff8b0143c0 bb t rapl_event_update [intel_rapl_perf] -ffffffff8b014480 10 t rapl_pmu_event_read [intel_rapl_perf] -ffffffff8b014490 a3 t rapl_cpu_offline [intel_rapl_perf] -ffffffff8b014540 24 t __rapl_event_show [intel_rapl_perf] -ffffffff8b014570 f2 t rapl_pmu_event_stop [intel_rapl_perf] - -This is emitted even if intel_rapl_perf is built into the kernel. - -As with /proc/kallsyms, non-root usage produces addresses that are -all-zero. (I am amenable to producing all-zero sizes, too, but without -the addresses this seems like pure paranoia.) - -Programs that consume /proc/kallmodsyms should note that unlike -/proc/kallsyms, kernel symbols for built-in modules may appear -interspersed with other symbols that are part of different modules or -part of no module at all. - -Signed-off-by: Nick Alcock <nick.alcock@oracle.com> -Signed-off-by: Kris Van Hees <kris.van.hees@oracle.com> -Signed-off-by: Tomas Jedlicka <tomas.jedlicka@oracle.com> -Signed-off-by: Eugene Loh <eugene.loh@oracle.com> -Signed-off-by: David Mc Lean <david.mclean@oracle.com> -Signed-off-by: Vincent Lim <vincent.lim@oracle.com> ---- - Makefile | 2 +- - include/linux/kallsyms.h | 21 +++ - include/linux/module.h | 7 +- - init/Kconfig | 10 ++ - kernel/kallsyms.c | 163 +++++++++++++-------- - kernel/module.c | 4 +- - scripts/Makefile | 10 ++ - scripts/kallsyms.c | 301 +++++++++++++++++++++++++++++++++++++-- - scripts/link-vmlinux.sh | 22 ++- - 9 files changed, 466 insertions(+), 74 deletions(-) - -diff --git a/Makefile b/Makefile -index e94e5bfc9c4f5d9c64c08c83d877c2c9394bc2c7..c21d2a09c9ca1419369295c2d29535e37135e6a4 100644 ---- a/Makefile -+++ b/Makefile -@@ -1406,7 +1406,7 @@ modules.order: $(subdir-modorder) FORCE - - targets += modules.order - --ifneq (CONFIG_CTF@,'@') -+ifneq (CONFIG_CTF@CONFIG_KALLMODSYMS,'@') - - # We need to force everything to be built, since we need the .o files below. - KBUILD_BUILTIN := 1 -diff --git a/include/linux/kallsyms.h b/include/linux/kallsyms.h -index 481273f0c72d4256979ee0ba2b02a4b9629f4497..1246b75f5c5798177cb18d100c2faa60399ef5a9 100644 ---- a/include/linux/kallsyms.h -+++ b/include/linux/kallsyms.h -@@ -8,6 +8,7 @@ - - #include <linux/errno.h> - #include <linux/kernel.h> -+#include <linux/module.h> - #include <linux/stddef.h> - #include <linux/mm.h> - #include <linux/module.h> -@@ -72,6 +73,24 @@ static inline void *dereference_symbol_descriptor(void *ptr) - } - - #ifdef CONFIG_KALLSYMS -+/* To avoid using get_symbol_offset for every symbol, we carry prefix along. */ -+struct kallsym_iter { -+ loff_t pos; -+ loff_t pos_arch_end; -+ loff_t pos_mod_end; -+ loff_t pos_ftrace_mod_end; -+ loff_t pos_bpf_end; -+ unsigned long value; -+ unsigned int nameoff; /* If iterating in core kernel symbols. */ -+ unsigned long size; -+ char type; -+ char name[KSYM_NAME_LEN]; -+ char module_name[MODULE_NAME_LEN]; -+ int builtin_module; -+ int exported; -+ int show_value; -+}; -+ - /* Lookup the address for a symbol. Returns 0 if not found. */ - unsigned long kallsyms_lookup_name(const char *name); - -@@ -101,6 +120,8 @@ int lookup_symbol_attrs(unsigned long addr, unsigned long *size, unsigned long * - /* How and when do we show kallsyms values? */ - extern bool kallsyms_show_value(const struct cred *cred); - -+extern void kallsyms_iter_reset(struct kallsym_iter *, loff_t); -+extern int kallsyms_iter_update(struct kallsym_iter *, loff_t); - #else /* !CONFIG_KALLSYMS */ - - static inline unsigned long kallsyms_lookup_name(const char *name) -diff --git a/include/linux/module.h b/include/linux/module.h -index 6264617bab4d46c542f86803a860d5a0a51c6214..d44fe50d7c7fec29c95e8b07865201410216d9d3 100644 ---- a/include/linux/module.h -+++ b/include/linux/module.h -@@ -599,7 +599,8 @@ struct symsearch { - /* Returns 0 and fills in value, defined and namebuf, or -ERANGE if - symnum out of range. */ - int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type, -- char *name, char *module_name, int *exported); -+ char *name, char *module_name, unsigned long *size, -+ int *exported); - - /* Look for this name: can be of form module:name. */ - unsigned long module_kallsyms_lookup_name(const char *name); -@@ -780,8 +781,8 @@ static inline int lookup_module_symbol_attrs(unsigned long addr, unsigned long * - } - - static inline int module_get_kallsym(unsigned int symnum, unsigned long *value, -- char *type, char *name, -- char *module_name, int *exported) -+ char *type, char *name, char *module_name, -+ unsigned long *size, int *exported) - { - return -ERANGE; - } -diff --git a/init/Kconfig b/init/Kconfig -index 0872a5a2e7590c0ade132f624af8d6e39de61544..05d377ccc0e08c27391242886bbd8904a17b4ef4 100644 ---- a/init/Kconfig -+++ b/init/Kconfig -@@ -1472,6 +1472,16 @@ config POSIX_TIMERS - - If unsure say y. - -+config KALLMODSYMS -+ default y -+ bool "Enable support for /proc/kallmodsyms" if EXPERT -+ depends on KALLSYMS -+ help -+ This option enables the /proc/kallmodsyms file, which maps symbols -+ to addresses and their associated modules. This support requires -+ a fairly recent elfutils: 0.152 -- 0.172 have been tested. -+ elfutils before 0.142 will definitely not work. -+ - config PRINTK - default y - bool "Enable support for printk" if EXPERT -diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c -index fe9de067771c34eb89d021df40579c38d8974298..7371f8f9cf74cba744f525f78dffb0175bece48d 100644 ---- a/kernel/kallsyms.c -+++ b/kernel/kallsyms.c -@@ -33,6 +33,7 @@ - */ - extern const unsigned long kallsyms_addresses[] __weak; - extern const int kallsyms_offsets[] __weak; -+extern const unsigned long kallsyms_sizes[] __weak; - extern const u8 kallsyms_names[] __weak; - - /* -@@ -47,6 +48,8 @@ __section(".rodata") __attribute__((weak)); - - extern const char kallsyms_token_table[] __weak; - extern const u16 kallsyms_token_index[] __weak; -+extern const char kallsyms_modules[] __weak; -+extern const u32 kallsyms_symbol_modules[] __weak; - - extern const unsigned int kallsyms_markers[] __weak; - -@@ -195,12 +198,24 @@ int kallsyms_on_each_symbol(int (*fn)(void *, const char *, struct module *, - return module_kallsyms_on_each_symbol(fn, data); - } - -+/* -+ * The caller passes in an address, and we return an index to the symbol -- -+ * potentially also size and offset information. -+ * But an address might map to multiple symbols because: -+ * - some symbols might have zero size -+ * - some symbols might be aliases of one another -+ * - some symbols might span (encompass) others -+ * The symbols should already be ordered so that, for a particular address, -+ * we first have the zero-size ones, then the biggest, then the smallest. -+ * So we find the index by: -+ * - finding the last symbol with the target address -+ * - backing the index up so long as both the address and size are unchanged -+ */ - static unsigned long get_symbol_pos(unsigned long addr, - unsigned long *symbolsize, - unsigned long *offset) - { -- unsigned long symbol_start = 0, symbol_end = 0; -- unsigned long i, low, high, mid; -+ unsigned long low, high, mid; - - /* This kernel should never had been booted. */ - if (!IS_ENABLED(CONFIG_KALLSYMS_BASE_RELATIVE)) -@@ -221,36 +236,17 @@ static unsigned long get_symbol_pos(unsigned long addr, - } - - /* -- * Search for the first aliased symbol. Aliased -- * symbols are symbols with the same address. -+ * Search for the first aliased symbol. - */ -- while (low && kallsyms_sym_address(low-1) == kallsyms_sym_address(low)) -+ while (low -+ && kallsyms_sym_address(low-1) == kallsyms_sym_address(low) -+ && kallsyms_sizes[low-1] == kallsyms_sizes[low]) - --low; - -- symbol_start = kallsyms_sym_address(low); -- -- /* Search for next non-aliased symbol. */ -- for (i = low + 1; i < kallsyms_num_syms; i++) { -- if (kallsyms_sym_address(i) > symbol_start) { -- symbol_end = kallsyms_sym_address(i); -- break; -- } -- } -- -- /* If we found no next symbol, we use the end of the section. */ -- if (!symbol_end) { -- if (is_kernel_inittext(addr)) -- symbol_end = (unsigned long)_einittext; -- else if (IS_ENABLED(CONFIG_KALLSYMS_ALL)) -- symbol_end = (unsigned long)_end; -- else -- symbol_end = (unsigned long)_etext; -- } -- - if (symbolsize) -- *symbolsize = symbol_end - symbol_start; -+ *symbolsize = kallsyms_sizes[low]; - if (offset) -- *offset = addr - symbol_start; -+ *offset = addr - kallsyms_sym_address(low); - - return low; - } -@@ -270,6 +266,7 @@ int kallsyms_lookup_size_offset(unsigned long addr, unsigned long *symbolsize, - return !!module_address_lookup(addr, symbolsize, offset, NULL, namebuf) || - !!__bpf_address_lookup(addr, symbolsize, offset, namebuf); - } -+EXPORT_SYMBOL_GPL(kallsyms_lookup_size_offset); - - /* - * Lookup an address -@@ -432,22 +429,6 @@ int sprint_backtrace(char *buffer, unsigned long address) - return __sprint_symbol(buffer, address, -1, 1); - } - --/* To avoid using get_symbol_offset for every symbol, we carry prefix along. */ --struct kallsym_iter { -- loff_t pos; -- loff_t pos_arch_end; -- loff_t pos_mod_end; -- loff_t pos_ftrace_mod_end; -- loff_t pos_bpf_end; -- unsigned long value; -- unsigned int nameoff; /* If iterating in core kernel symbols. */ -- char type; -- char name[KSYM_NAME_LEN]; -- char module_name[MODULE_NAME_LEN]; -- int exported; -- int show_value; --}; -- - int __weak arch_get_kallsym(unsigned int symnum, unsigned long *value, - char *type, char *name) - { -@@ -473,7 +454,9 @@ static int get_ksymbol_mod(struct kallsym_iter *iter) - int ret = module_get_kallsym(iter->pos - iter->pos_arch_end, - &iter->value, &iter->type, - iter->name, iter->module_name, -- &iter->exported); -+ &iter->size, &iter->exported); -+ iter->builtin_module = 0; -+ - if (ret < 0) { - iter->pos_mod_end = iter->pos; - return 0; -@@ -536,10 +519,22 @@ static int get_ksymbol_kprobe(struct kallsym_iter *iter) - static unsigned long get_ksymbol_core(struct kallsym_iter *iter) - { - unsigned off = iter->nameoff; -+ u32 mod_index = 0; -+ -+ if (kallsyms_symbol_modules) -+ mod_index = kallsyms_symbol_modules[iter->pos]; - -- iter->module_name[0] = '\0'; -+ if (mod_index == 0 || kallsyms_modules == NULL) { -+ iter->module_name[0] = '\0'; -+ iter->builtin_module = 0; -+ } else { -+ strcpy(iter->module_name, &kallsyms_modules[mod_index]); -+ iter->builtin_module = 1; -+ } -+ iter->exported = 0; - iter->value = kallsyms_sym_address(iter->pos); - -+ iter->size = kallsyms_sizes[iter->pos]; - iter->type = kallsyms_get_symbol_type(off); - - off = kallsyms_expand_symbol(off, iter->name, ARRAY_SIZE(iter->name)); -@@ -547,7 +542,7 @@ static unsigned long get_ksymbol_core(struct kallsym_iter *iter) - return off - iter->nameoff; - } - --static void reset_iter(struct kallsym_iter *iter, loff_t new_pos) -+void kallsyms_iter_reset(struct kallsym_iter *iter, loff_t new_pos) - { - iter->name[0] = '\0'; - iter->nameoff = get_symbol_offset(new_pos); -@@ -559,6 +554,7 @@ static void reset_iter(struct kallsym_iter *iter, loff_t new_pos) - iter->pos_bpf_end = 0; - } - } -+EXPORT_SYMBOL_GPL(kallsyms_iter_reset); - - /* - * The end position (last + 1) of each additional kallsyms section is recorded -@@ -589,7 +585,7 @@ static int update_iter_mod(struct kallsym_iter *iter, loff_t pos) - } - - /* Returns false if pos at or past end of file. */ --static int update_iter(struct kallsym_iter *iter, loff_t pos) -+int kallsyms_iter_update(struct kallsym_iter *iter, loff_t pos) - { - /* Module symbols can be accessed randomly. */ - if (pos >= kallsyms_num_syms) -@@ -597,26 +593,27 @@ static int update_iter(struct kallsym_iter *iter, loff_t pos) - - /* If we're not on the desired position, reset to new position. */ - if (pos != iter->pos) -- reset_iter(iter, pos); -+ kallsyms_iter_reset(iter, pos); - - iter->nameoff += get_ksymbol_core(iter); - iter->pos++; - - return 1; - } -+EXPORT_SYMBOL_GPL(kallsyms_iter_update); - - static void *s_next(struct seq_file *m, void *p, loff_t *pos) - { - (*pos)++; - -- if (!update_iter(m->private, *pos)) -+ if (!kallsyms_iter_update(m->private, *pos)) - return NULL; - return p; - } - - static void *s_start(struct seq_file *m, loff_t *pos) - { -- if (!update_iter(m->private, *pos)) -+ if (!kallsyms_iter_update(m->private, *pos)) - return NULL; - return m->private; - } -@@ -625,7 +622,7 @@ static void s_stop(struct seq_file *m, void *p) - { - } - --static int s_show(struct seq_file *m, void *p) -+static int s_show_internal(struct seq_file *m, void *p, int builtin_modules) - { - void *value; - struct kallsym_iter *iter = m->private; -@@ -636,7 +633,9 @@ static int s_show(struct seq_file *m, void *p) - - value = iter->show_value ? (void *)iter->value : NULL; - -- if (iter->module_name[0]) { -+ if ((iter->builtin_module == 0 && iter->module_name[0]) || -+ (iter->builtin_module != 0 && iter->module_name[0] && -+ builtin_modules != 0)) { - char type; - - /* -@@ -645,14 +644,32 @@ static int s_show(struct seq_file *m, void *p) - */ - type = iter->exported ? toupper(iter->type) : - tolower(iter->type); -- seq_printf(m, "%px %c %s\t[%s]\n", value, -- type, iter->name, iter->module_name); -- } else -+ if (builtin_modules) -+ seq_printf(m, "%px %lx %c %s\t[%s]\n", value, -+ iter->size, type, iter->name, -+ iter->module_name); -+ else -+ seq_printf(m, "%px %c %s\t[%s]\n", value, -+ type, iter->name, iter->module_name); -+ } else if (builtin_modules) -+ seq_printf(m, "%px %lx %c %s\n", value, iter->size, -+ iter->type, iter->name); -+ else - seq_printf(m, "%px %c %s\n", value, - iter->type, iter->name); - return 0; - } - -+static int s_show(struct seq_file *m, void *p) -+{ -+ return s_show_internal(m, p, 0); -+} -+ -+static int s_mod_show(struct seq_file *m, void *p) -+{ -+ return s_show_internal(m, p, 1); -+} -+ - static const struct seq_operations kallsyms_op = { - .start = s_start, - .next = s_next, -@@ -695,7 +712,15 @@ bool kallsyms_show_value(const struct cred *cred) - } - } - --static int kallsyms_open(struct inode *inode, struct file *file) -+static const struct seq_operations kallmodsyms_op = { -+ .start = s_start, -+ .next = s_next, -+ .stop = s_stop, -+ .show = s_mod_show -+}; -+ -+static int kallsyms_open_internal(struct inode *inode, struct file *file, -+ const struct seq_operations *ops) - { - /* - * We keep iterator in m->private, since normal case is to -@@ -703,10 +728,10 @@ static int kallsyms_open(struct inode *inode, struct file *file) - * using get_symbol_offset for every symbol. - */ - struct kallsym_iter *iter; -- iter = __seq_open_private(file, &kallsyms_op, sizeof(*iter)); -+ iter = __seq_open_private(file, ops, sizeof(*iter)); - if (!iter) - return -ENOMEM; -- reset_iter(iter, 0); -+ kallsyms_iter_reset(iter, 0); - - /* - * Instead of checking this on every s_show() call, cache -@@ -716,6 +741,16 @@ static int kallsyms_open(struct inode *inode, struct file *file) - return 0; - } - -+static int kallsyms_open(struct inode *inode, struct file *file) -+{ -+ return kallsyms_open_internal(inode, file, &kallsyms_op); -+} -+ -+static int kallmodsyms_open(struct inode *inode, struct file *file) -+{ -+ return kallsyms_open_internal(inode, file, &kallmodsyms_op); -+} -+ - #ifdef CONFIG_KGDB_KDB - const char *kdb_walk_kallsyms(loff_t *pos) - { -@@ -723,10 +758,10 @@ const char *kdb_walk_kallsyms(loff_t *pos) - if (*pos == 0) { - memset(&kdb_walk_kallsyms_iter, 0, - sizeof(kdb_walk_kallsyms_iter)); -- reset_iter(&kdb_walk_kallsyms_iter, 0); -+ kallsyms_iter_reset(&kdb_walk_kallsyms_iter, 0); - } - while (1) { -- if (!update_iter(&kdb_walk_kallsyms_iter, *pos)) -+ if (!kallsyms_iter_update(&kdb_walk_kallsyms_iter, *pos)) - return NULL; - ++*pos; - /* Some debugging symbols have no name. Ignore them. */ -@@ -743,9 +778,17 @@ static const struct proc_ops kallsyms_proc_ops = { - .proc_release = seq_release_private, - }; - -+static const struct proc_ops kallmodsyms_proc_ops = { -+ .proc_open = kallmodsyms_open, -+ .proc_read = seq_read, -+ .proc_lseek = seq_lseek, -+ .proc_release = seq_release_private, -+}; -+ - static int __init kallsyms_init(void) - { - proc_create("kallsyms", 0444, NULL, &kallsyms_proc_ops); -+ proc_create("kallmodsyms", 0444, NULL, &kallmodsyms_proc_ops); - return 0; - } - device_initcall(kallsyms_init); -diff --git a/kernel/module.c b/kernel/module.c -index e20499309b2af6aca7cafcf95962b94065d4fe83..9e471dbedc83a1a080612bf4f4ffabf09f3b8aa8 100644 ---- a/kernel/module.c -+++ b/kernel/module.c -@@ -4241,7 +4241,8 @@ int lookup_module_symbol_attrs(unsigned long addr, unsigned long *size, - } - - int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type, -- char *name, char *module_name, int *exported) -+ char *name, char *module_name, unsigned long *size, -+ int *exported) - { - struct module *mod; - -@@ -4260,6 +4261,7 @@ int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type, - strlcpy(name, kallsyms_symbol_name(kallsyms, symnum), KSYM_NAME_LEN); - strlcpy(module_name, mod->name, MODULE_NAME_LEN); - *exported = is_exported(name, *value, mod); -+ *size = kallsyms->symtab[symnum].st_size; - preempt_enable(); - return 0; - } -diff --git a/scripts/Makefile b/scripts/Makefile -index 041bcf48cc5c7613d072cf50eae142a21d31153e..efa1ff4dff951222a8c98326c29f2146d7e4c587 100644 ---- a/scripts/Makefile -+++ b/scripts/Makefile -@@ -12,6 +12,16 @@ hostprogs-always-$(CONFIG_MODULE_SIG_FORMAT) += sign-file - hostprogs-always-$(CONFIG_SYSTEM_TRUSTED_KEYRING) += extract-cert - hostprogs-always-$(CONFIG_SYSTEM_EXTRA_CERTIFICATE) += insert-sys-cert - -+kallsyms-objs := kallsyms.o -+ -+ifeq ($(CONFIG_KALLMODSYMS),y) -+kallsyms-objs += eu_simple.o -+ -+HOSTCFLAGS_eu_simple.o := -I$(srctree)/scripts -+HOSTCFLAGS_kallsyms.o := $(shell pkg-config --cflags glib-2.0) -I$(srctree)/scripts -+HOSTLDLIBS_kallsyms := $(shell pkg-config --libs glib-2.0) -ldw -+endif -+ - HOSTCFLAGS_sorttable.o = -I$(srctree)/tools/include - HOSTCFLAGS_asn1_compiler.o = -I$(srctree)/include - HOSTLDLIBS_sign-file = -lcrypto -diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c -index 7ecd2ccba531bb4c46a01b4ecad7ea8078f29027..884ac793bdf417a34060a95f4239034680e09ea9 100644 ---- a/scripts/kallsyms.c -+++ b/scripts/kallsyms.c -@@ -5,7 +5,10 @@ - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * -- * Usage: nm -n vmlinux | scripts/kallsyms [--all-symbols] > symbols.S -+ * Usage: nm -n -S vmlinux | scripts/kallsyms [--all-symbols] -+ * [--symbol-prefix=<prefix char>] -+ * [--builtin=modules_thick.builtin] -+ * > symbols.S - * - * Table compression uses all the unused char codes on the symbols and - * maps these to the most used substrings (tokens). For instance, it might -@@ -18,12 +21,27 @@ - * - */ - -+#define _GNU_SOURCE 1 - #include <stdbool.h> - #include <stdio.h> - #include <stdlib.h> - #include <string.h> - #include <ctype.h> - #include <limits.h> -+#include <errno.h> -+#include <unistd.h> -+ -+#include "../include/generated/autoconf.h" -+ -+#ifdef CONFIG_KALLMODSYMS -+#include <libelf.h> -+#include <dwarf.h> -+#include <elfutils/libdwfl.h> -+#include <elfutils/libdw.h> -+#include <glib.h> -+ -+#include <eu_simple.h> -+#endif - - #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) - -@@ -31,9 +49,13 @@ - - struct sym_entry { - unsigned long long addr; -+ unsigned long long size; - unsigned int len; - unsigned int start_pos; - unsigned int percpu_absolute; -+#ifdef CONFIG_KALLMODSYMS -+ unsigned int module; -+#endif - unsigned char sym[]; - }; - -@@ -67,11 +89,33 @@ static int token_profit[0x10000]; - static unsigned char best_table[256][2]; - static unsigned char best_table_len[256]; - -+#ifdef CONFIG_KALLMODSYMS -+/* -+ * The builtin module names. The "offset" points to the name as if -+ * all builtin module names were concatenated to a single string. -+ */ -+static unsigned int builtin_module_size; /* number allocated */ -+static unsigned int builtin_module_len; /* number assigned */ -+static char **builtin_modules; /* array of module names */ -+static unsigned int *builtin_module_offsets; /* offset */ -+ -+/* -+ * An ordered list of address ranges and how they map to built-in modules. -+ */ -+struct addrmap_entry { -+ unsigned long long addr; -+ unsigned long long size; -+ unsigned int module; -+}; -+static struct addrmap_entry *addrmap; -+static int addrmap_num, addrmap_alloced; -+#endif - - static void usage(void) - { - fprintf(stderr, "Usage: kallsyms [--all-symbols] " -- "[--base-relative] < in.map > out.S\n"); -+ "[--base-relative] [--builtin=modules_thick.builtin] " -+ "< in.map > out.S\n"); - exit(1); - } - -@@ -99,6 +143,8 @@ static bool is_ignored_symbol(const char *name, char type) - "kallsyms_markers", - "kallsyms_token_table", - "kallsyms_token_index", -+ "kallsyms_symbol_modules", -+ "kallsyms_modules", - /* Exclude linker generated symbols which vary between passes */ - "_SDA_BASE_", /* ppc */ - "_SDA2_BASE_", /* ppc */ -@@ -189,6 +235,20 @@ static void check_symbol_range(const char *sym, unsigned long long addr, - } - } - -+#ifdef CONFIG_KALLMODSYMS -+static int addrmap_compare(const void *keyp, const void *rangep) -+{ -+ unsigned long long addr = *((const unsigned long long *)keyp); -+ const struct addrmap_entry *range = (const struct addrmap_entry *)rangep; -+ -+ if (addr < range->addr) -+ return -1; -+ if (addr < range->addr + range->size) -+ return 0; -+ return 1; -+} -+#endif -+ - static struct sym_entry *read_symbol(FILE *in) - { - char name[500], type; -@@ -196,9 +256,14 @@ static struct sym_entry *read_symbol(FILE *in) - unsigned int len; - struct sym_entry *sym; - int rc; -- -- rc = fscanf(in, "%llx %c %499s\n", &addr, &type, name); -- if (rc != 3) { -+ unsigned long long size; -+#ifdef CONFIG_KALLMODSYMS -+ struct addrmap_entry *range; -+ unsigned int module; -+#endif -+ -+ rc = fscanf(in, "%llx %llx %c %499s\n", &addr, &size, &type, name); -+ if (rc != 4) { - if (rc != EOF && fgets(name, 500, in) == NULL) - fprintf(stderr, "Read error or end of file.\n"); - return NULL; -@@ -220,6 +285,16 @@ static struct sym_entry *read_symbol(FILE *in) - check_symbol_range(name, addr, text_ranges, ARRAY_SIZE(text_ranges)); - check_symbol_range(name, addr, &percpu_range, 1); - -+#ifdef CONFIG_KALLMODSYMS -+ /* look up the builtin module this is part of (if any) */ -+ range = (struct addrmap_entry *) bsearch(&addr, -+ addrmap, addrmap_num, sizeof(*addrmap), &addrmap_compare); -+ if (range) -+ module = builtin_module_offsets[range->module]; -+ else -+ module = 0; -+#endif -+ - /* include the type field in the symbol name, so that it gets - * compressed together */ - -@@ -236,6 +311,10 @@ static struct sym_entry *read_symbol(FILE *in) - sym->sym[0] = type; - strcpy(sym_name(sym), name); - sym->percpu_absolute = 0; -+ sym->size = size; -+#ifdef CONFIG_KALLMODSYMS -+ sym->module = module; -+#endif - - return sym; - } -@@ -445,6 +524,11 @@ static void write_src(void) - printf("\n"); - } - -+ output_label("kallsyms_sizes"); -+ for (i = 0; i < table_cnt; i++) -+ printf("\tPTR\t%#llx\n", table[i]->size); -+ printf("\n"); -+ - output_label("kallsyms_num_syms"); - printf("\t.long\t%u\n", table_cnt); - printf("\n"); -@@ -494,8 +578,22 @@ static void write_src(void) - for (i = 0; i < 256; i++) - printf("\t.short\t%d\n", best_idx[i]); - printf("\n"); --} - -+#ifdef CONFIG_KALLMODSYMS -+ output_label("kallsyms_modules"); -+ for (i = 0; i < builtin_module_len; i++) -+ printf("\t.asciz\t\"%s\"\n", builtin_modules[i]); -+ printf("\n"); -+ -+ for (i = 0; i < builtin_module_len; i++) -+ free(builtin_modules[i]); -+ -+ output_label("kallsyms_symbol_modules"); -+ for (i = 0; i < table_cnt; i++) -+ printf("\t.int\t%d\n", table[i]->module); -+ printf("\n"); -+#endif -+} - - /* table lookup compression functions */ - -@@ -697,6 +795,18 @@ static int compare_symbols(const void *a, const void *b) - if (sa->addr < sb->addr) - return -1; - -+ /* zero-size markers before nonzero-size symbols */ -+ if (sa->size > 0 && sb->size == 0) -+ return 1; -+ if (sa->size == 0 && sb->size > 0) -+ return -1; -+ -+ /* sort by size (large size preceding symbols it encompasses) */ -+ if (sa->size < sb->size) -+ return 1; -+ if (sa->size > sb->size) -+ return -1; -+ - /* sort by "weakness" type */ - wa = (sa->sym[0] == 'w') || (sa->sym[0] == 'W'); - wb = (sb->sym[0] == 'w') || (sb->sym[0] == 'W'); -@@ -756,23 +866,198 @@ static void record_relative_base(void) - } - } - -+#ifdef CONFIG_KALLMODSYMS -+/* Built-in module list computation. */ -+ -+/* -+ * Expand the builtin modules list. -+ */ -+static void expand_builtin_modules(void) -+{ -+ builtin_module_size += 50; -+ -+ builtin_modules = realloc(builtin_modules, -+ sizeof(*builtin_modules) * -+ builtin_module_size); -+ builtin_module_offsets = realloc(builtin_module_offsets, -+ sizeof(*builtin_module_offsets) * -+ builtin_module_size); -+ -+ if (!builtin_modules || !builtin_module_offsets) { -+ fprintf(stderr, "kallsyms failure: out of memory.\n"); -+ exit(EXIT_FAILURE); -+ } -+} -+ -+/* -+ * Add a single built-in module (possibly composed of many files) to the -+ * modules list. Take the offset of the current module and return it -+ * (purely for simplicity's sake in the caller). -+ */ -+static size_t add_builtin_module(const char *module_name, char **module_paths, -+ GHashTable *obj2mod, size_t offset) -+{ -+ gpointer val = GUINT_TO_POINTER(builtin_module_len); -+ -+ /* map the module's object paths to the module offset */ -+ while (*module_paths) { -+ g_hash_table_insert(obj2mod, strdup(*module_paths), val); -+ module_paths++; -+ } -+ -+ /* add the module name */ -+ if (builtin_module_size <= builtin_module_len) -+ expand_builtin_modules(); -+ builtin_modules[builtin_module_len] = strdup(module_name); -+ builtin_module_offsets[builtin_module_len] = offset; -+ builtin_module_len++; -+ -+ return (offset + strlen(module_name) + 1); -+} -+ -+/* -+ * Read the linker map. -+ */ -+static void read_linker_map(GHashTable *obj2mod) -+{ -+ unsigned long long addr, size; -+ char obj[PATH_MAX+1]; -+ FILE *f = fopen(".tmp_vmlinux.ranges", "r"); -+ -+ if (!f) { -+ fprintf(stderr, "Cannot open '.tmp_vmlinux.ranges'.\n"); -+ exit(1); -+ } -+ -+ addrmap_num = 0; -+ addrmap_alloced = 4096; -+ addrmap = malloc(sizeof(*addrmap) * addrmap_alloced); -+ if (!addrmap) -+ goto oom; -+ -+ /* -+ * For each address range (addr,size) and object, add to addrmap -+ * the range and the built-in module to which the object maps. -+ */ -+ while (fscanf(f, "%llx %llx %s\n", &addr, &size, obj) == 3) { -+ int m = GPOINTER_TO_UINT(g_hash_table_lookup(obj2mod, obj)); -+ -+ if (addr == 0 || size == 0 || m == 0) -+ continue; -+ -+ if (addrmap_num >= addrmap_alloced) { -+ addrmap_alloced *= 2; -+ addrmap = realloc(addrmap, -+ sizeof(*addrmap) * addrmap_alloced); -+ if (!addrmap) -+ goto oom; -+ } -+ -+ addrmap[addrmap_num].addr = addr; -+ addrmap[addrmap_num].size = size; -+ addrmap[addrmap_num].module = m; -+ addrmap_num++; -+ } -+ fclose(f); -+ return; -+ -+oom: -+ fprintf(stderr, "kallsyms: out of memory\n"); -+ exit(1); -+} -+ -+/* -+ * Read the list of built-in modules. Construct: -+ * - builtin_modules: array of module names -+ * - builtin_module_offsets: array of offsets to find module names -+ * - obj2mod: mapping from each object-file path to a module index -+ * (which can be used in the arrays) -+ * Finally, read the linker map. -+ */ -+static void read_modules(const char *modules_builtin) -+{ -+ struct modules_thick_iter *i; -+ size_t offset = 0; -+ char *module_name = NULL; -+ char **module_paths; -+ GHashTable *obj2mod; -+ -+ obj2mod = g_hash_table_new_full(g_str_hash, g_str_equal, free, NULL); -+ if (!obj2mod) { -+ fprintf(stderr, "kallsyms: out of memory\n"); -+ exit(1); -+ } -+ -+ /* -+ * builtin_modules[0] is a null entry signifying a symbol that cannot be -+ * modular. -+ */ -+ builtin_module_size = 50; -+ builtin_modules = malloc(sizeof(*builtin_modules) * -+ builtin_module_size); -+ builtin_module_offsets = malloc(sizeof(*builtin_module_offsets) * -+ builtin_module_size); -+ if (!builtin_modules || !builtin_module_offsets) { -+ fprintf(stderr, "kallsyms: out of memory\n"); -+ exit(1); -+ } -+ builtin_modules[0] = strdup(""); -+ builtin_module_offsets[0] = 0; -+ builtin_module_len = 1; -+ offset++; -+ -+ /* -+ * Iterate over all modules in modules_thick.builtin and add each. -+ */ -+ i = modules_thick_iter_new(modules_builtin); -+ if (i == NULL) { -+ fprintf(stderr, "Cannot iterate over builtin modules.\n"); -+ exit(1); -+ } -+ -+ while ((module_paths = modules_thick_iter_next(i, &module_name)) != NULL) { -+ offset = add_builtin_module(module_name, module_paths, -+ obj2mod, offset); -+ free(module_paths); -+ module_paths = NULL; -+ } -+ -+ free(module_name); -+ modules_thick_iter_free(i); -+ -+ /* -+ * Read linker map. -+ */ -+ read_linker_map(obj2mod); -+ -+ g_hash_table_destroy(obj2mod); -+} -+#else -+static void read_modules(const char *unused) {} -+#endif /* CONFIG_KALLMODSYMS */ -+ - int main(int argc, char **argv) - { -- if (argc >= 2) { -+ const char *modules_builtin = "modules_thick.builtin"; -+ -+ if (argc >= 1) { - int i; - for (i = 1; i < argc; i++) { -- if(strcmp(argv[i], "--all-symbols") == 0) -+ if (strcmp(argv[i], "--all-symbols") == 0) - all_symbols = 1; - else if (strcmp(argv[i], "--absolute-percpu") == 0) - absolute_percpu = 1; - else if (strcmp(argv[i], "--base-relative") == 0) - base_relative = 1; -+ else if (strncmp(argv[i], "--builtin=", 10) == 0) -+ modules_builtin = &argv[i][10]; - else - usage(); - } - } else if (argc != 1) - usage(); - -+ read_modules(modules_builtin); - read_map(stdin); - shrink_table(); - if (absolute_percpu) -diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh -index 6eded325c8378c8cff94c379a180060c0b154ec4..bc533252fa3c39482a870654036caf3897946123 100755 ---- a/scripts/link-vmlinux.sh -+++ b/scripts/link-vmlinux.sh -@@ -109,6 +109,7 @@ vmlinux_link() - --start-group \ - ${KBUILD_VMLINUX_LIBS} \ - --end-group \ -+ -Map=.tmp_vmlinux.map \ - ${@}" - - ${LD} ${KBUILD_LDFLAGS} ${LDFLAGS_vmlinux} \ -@@ -122,6 +123,7 @@ vmlinux_link() - -Wl,--start-group \ - ${KBUILD_VMLINUX_LIBS} \ - -Wl,--end-group \ -+ -Wl,-Map=.tmp_vmlinux.map \ - ${@}" - - ${CC} ${CFLAGS_vmlinux} \ -@@ -174,6 +176,19 @@ kallsyms() - { - local kallsymopt; - -+ # read the linker map to identify ranges of addresses: -+ # - for each *.o file, report address, size, pathname -+ # - most such lines will have four fields -+ # - but sometimes there is a line break after the first field -+ # - start reading at "Linker script and memory map" -+ # - stop reading at ".brk" -+ ${AWK} ' -+ /\.o$/ && start==1 { print $(NF-2), $(NF-1), $NF } -+ /^Linker script and memory map/ { start = 1 } -+ /^\.brk/ { exit(0) } -+ ' .tmp_vmlinux.map | sort > .tmp_vmlinux.ranges -+ -+ # get kallsyms options - if [ -n "${CONFIG_KALLSYMS_ALL}" ]; then - kallsymopt="${kallsymopt} --all-symbols" - fi -@@ -186,8 +201,13 @@ kallsyms() - kallsymopt="${kallsymopt} --base-relative" - fi - -+ # "nm -S" does not print symbol size when size is 0 -+ # Therefore use awk to regularize the data: -+ # - when there are only three fields, add an explicit "0" -+ # - when there are already four fields, pass through as is - info KSYMS ${2} -- ${NM} -n ${1} | scripts/kallsyms ${kallsymopt} > ${2} -+ ${NM} -n -S ${1} | ${AWK} 'NF==3 {print $1, 0, $2, $3}; NF==4' | \ -+ scripts/kallsyms ${kallsymopt} > ${2} - } - - # Perform one step in kallsyms generation, including temporary linking of --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/dtrace-patches/0003-waitfd-new-syscall-implementing-waitpid-over-fds.patch b/sys-kernel/cairn-sources/files/5.10.14/dtrace-patches/0003-waitfd-new-syscall-implementing-waitpid-over-fds.patch deleted file mode 100644 index 437715c7dd30..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/dtrace-patches/0003-waitfd-new-syscall-implementing-waitpid-over-fds.patch +++ /dev/null @@ -1,809 +0,0 @@ -From 7cbd018b36da6838efe3adba191adf3acd4ef9bd Mon Sep 17 00:00:00 2001 -From: Nick Alcock <nick.alcock@oracle.com> -Date: Wed, 14 Nov 2018 20:28:51 +0000 -Subject: [PATCH 03/19] waitfd: new syscall implementing waitpid() over fds - -This syscall, originally due to Casey Dahlin but significantly modified -since, is called quite like waitid(): - - fd = waitfd(P_PID, some_pid, WEXITED | WSTOPPED, 0); - -This returns a file descriptor which becomes ready whenever waitpid() -would return, and when read() returns the return value waitpid() would -have returned. (Alternatively, you can use it as a pure indication that -waitpid() is callable without hanging, and then call waitpid()). See the -example in tools/testing/selftests/waitfd/. - -The original reason for rejection of this patch back in 2009 was that it -was redundant to waitpid()ing in a separate thread and transmitting -process information to another thread that polls: but this is only the -case for the conventional child-process use of waitpid(). Other -waitpid() uses, such as ptrace() returns, are targetted on a single -thread, so without waitfd or something like it, it is impossible to have -a thread that both accepts requests for servicing from other threads -over an fd *and* manipulates the state of a ptrace()d process in -response to those requests without ugly CPU-chewing polling (accepting -requests requires blocking in poll() or select(): handling the ptraced -process requires blocking in waitpid()). - -There is one ugliness in this patch which I would appreciate suggestions -to improve (due to me, not due to Casey, don't blame him). The poll() -machinery expects to be used with files, or things enough like files -that the wake_up key contains an indication as to whether this wakeup -corresponds to a POLLIN / POLLOUT / POLLERR event on this fd. You can -override this in your poll_queue_proc, but the poll() and epoll() queue -procs both have this interpretation. - -Unfortunately, this is not true for waitfds, which wait on the the -wait_chldexit waitqueue, whose key is a pointer to the task_struct of -the task being killed. We can't do anything with this key, but we -certainly don't want the poll machinery treating it as a bitmask and -checking it against poll events! - -So we introduce a new poll_wait() analogue, poll_wait_fixed(). This is used -for poll_wait() calls which know they must wait on waitqueues whose keys are -not a typecast representation of poll events, and passes in an extra -argument to the poll_queue_proc, which if nonzero is the event which a -wakeup on this waitqueue should be considered as equivalent to. The -poll_queue_proc can then skip adding entirely if that fixed event is not -included in the set to be caught by this poll(). - -We also add a new poll_table_entry.fixed_key. The poll_queue_proc can -record the fixed key it is passed in here, and reuse it at wakeup time to -track that a nonzero fixed key was passed in to poll_wait_fixed() and that -the key should be ignored in preference to fixed_key. - -With this in place, you can say, e.g. (as waitfd does) - - poll_wait_fixed(file, ¤t->signal->wait_chldexit, wait, - POLLIN); - -and the key passed to wakeups on the wait_chldexit waitqueue will be -ignored: the fd will always be treated as having raised POLLIN, waking -up poll()s and epoll()s that have specified that event. (Obviously, a -poll function that calls this should return the same value from the poll -function as was passed to poll_wait_fixed(), or, as usual, zero if this -was a spurious wakeup.) - -I do not like this scheme: it's sufficiently arcane that I had to go -back to my old commit messages to figure out what it was doing and -why. But I don't see another way to cause poll() to return on -appropriate activity on waitqueues that do not actually correspond to -files. (I do wonder how signalfd works. It doesn't seem to need any of -this and I don't understand why not. I would be overjoyed to remove the -whole invasive poll_wait_fixed() mess, but I'm not sure what to replace -it with.) - -Signed-off-by: Nick Alcock <nick.alcock@oracle.com> -Signed-off-by: Kris Van Hees <kris.van.hees@oracle.com> -Signed-off-by: Tomas Jedlicka <tomas.jedlicka@oracle.com> -Signed-off-by: Eugene Loh <eugene.loh@oracle.com> -Signed-off-by: David Mc Lean <david.mclean@oracle.com> -Signed-off-by: Vincent Lim <vincent.lim@oracle.com> ---- - arch/x86/entry/syscalls/syscall_32.tbl | 3 + - arch/x86/entry/syscalls/syscall_64.tbl | 3 + - drivers/vfio/virqfd.c | 3 +- - drivers/vhost/vhost.c | 2 +- - fs/Makefile | 1 + - fs/aio.c | 2 +- - fs/eventpoll.c | 22 +++- - fs/io_uring.c | 5 +- - fs/select.c | 21 +++- - fs/waitfd.c | 130 ++++++++++++++++++++++++ - include/linux/poll.h | 14 ++- - include/linux/syscalls.h | 3 + - include/uapi/asm-generic/unistd.h | 5 +- - init/Kconfig | 16 +++ - kernel/exit.c | 13 ++- - kernel/sys_ni.c | 1 + - mm/memcontrol.c | 2 +- - net/9p/trans_fd.c | 3 +- - tools/testing/selftests/waitfd/Makefile | 28 +++++ - tools/testing/selftests/waitfd/waitfd.c | 116 +++++++++++++++++++++ - virt/kvm/eventfd.c | 2 +- - 21 files changed, 376 insertions(+), 19 deletions(-) - create mode 100644 fs/waitfd.c - create mode 100644 tools/testing/selftests/waitfd/Makefile - create mode 100644 tools/testing/selftests/waitfd/waitfd.c - -diff --git a/arch/x86/entry/syscalls/syscall_32.tbl b/arch/x86/entry/syscalls/syscall_32.tbl -index 0d0667a9fbd70aeb9e297342b9f855a457d45ea4..5605708e4c31f920411aec2682d7c0d17271054f 100644 ---- a/arch/x86/entry/syscalls/syscall_32.tbl -+++ b/arch/x86/entry/syscalls/syscall_32.tbl -@@ -445,3 +445,6 @@ - 438 i386 pidfd_getfd sys_pidfd_getfd - 439 i386 faccessat2 sys_faccessat2 - 440 i386 process_madvise sys_process_madvise -+# This one is a temporary number, designed for no clashes. -+# Nothing but DTrace should use it. -+473 i386 waitfd sys_waitfd -diff --git a/arch/x86/entry/syscalls/syscall_64.tbl b/arch/x86/entry/syscalls/syscall_64.tbl -index 379819244b91d275b2c98f7ff38a59049c24b42a..4f4e0585c65fc04ecf50c997d3b9e21375b7a88b 100644 ---- a/arch/x86/entry/syscalls/syscall_64.tbl -+++ b/arch/x86/entry/syscalls/syscall_64.tbl -@@ -362,6 +362,9 @@ - 438 common pidfd_getfd sys_pidfd_getfd - 439 common faccessat2 sys_faccessat2 - 440 common process_madvise sys_process_madvise -+# This one is a temporary number, designed for no clashes. -+# Nothing but DTrace should use it. -+473 common waitfd sys_waitfd - - # - # Due to a historical design error, certain syscalls are numbered differently -diff --git a/drivers/vfio/virqfd.c b/drivers/vfio/virqfd.c -index 997cb5d0a657cb1cb795ca609704f886c7ffc276..6bfafa889af2181fc6a88aa8e63a7513393cc4ca 100644 ---- a/drivers/vfio/virqfd.c -+++ b/drivers/vfio/virqfd.c -@@ -76,7 +76,8 @@ static int virqfd_wakeup(wait_queue_entry_t *wait, unsigned mode, int sync, void - } - - static void virqfd_ptable_queue_proc(struct file *file, -- wait_queue_head_t *wqh, poll_table *pt) -+ wait_queue_head_t *wqh, poll_table *pt, -+ unsigned long unused) - { - struct virqfd *virqfd = container_of(pt, struct virqfd, pt); - add_wait_queue(wqh, &virqfd->wait); -diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c -index a262e12c6dc26f76810ac28a833ea5deb1e70d74..31128cadd1b20b24bba7b365e34e416c185d2c7c 100644 ---- a/drivers/vhost/vhost.c -+++ b/drivers/vhost/vhost.c -@@ -152,7 +152,7 @@ static void vhost_flush_work(struct vhost_work *work) - } - - static void vhost_poll_func(struct file *file, wait_queue_head_t *wqh, -- poll_table *pt) -+ poll_table *pt, unsigned long unused) - { - struct vhost_poll *poll; - -diff --git a/fs/Makefile b/fs/Makefile -index 999d1a23f036c9f96a06e056d333e2e3832cdc37..ad5fc1399484685eb956e934b5af56b431a4275f 100644 ---- a/fs/Makefile -+++ b/fs/Makefile -@@ -31,6 +31,7 @@ obj-$(CONFIG_SIGNALFD) += signalfd.o - obj-$(CONFIG_TIMERFD) += timerfd.o - obj-$(CONFIG_EVENTFD) += eventfd.o - obj-$(CONFIG_USERFAULTFD) += userfaultfd.o -+obj-$(CONFIG_WAITFD) += waitfd.o - obj-$(CONFIG_AIO) += aio.o - obj-$(CONFIG_IO_URING) += io_uring.o - obj-$(CONFIG_IO_WQ) += io-wq.o -diff --git a/fs/aio.c b/fs/aio.c -index 6a21d8919409c4aa2c0378108337724a1f73eb35..3485fe7913ef824cc7636205c13707041ee9fe95 100644 ---- a/fs/aio.c -+++ b/fs/aio.c -@@ -1718,7 +1718,7 @@ struct aio_poll_table { - - static void - aio_poll_queue_proc(struct file *file, struct wait_queue_head *head, -- struct poll_table_struct *p) -+ struct poll_table_struct *p, unsigned long fixed_event) - { - struct aio_poll_table *pt = container_of(p, struct aio_poll_table, pt); - -diff --git a/fs/eventpoll.c b/fs/eventpoll.c -index 117b1c395ae4ad7d16fc3b705ec3185065159dbb..e3c9f4ea9ec6aa1b62342976af425318c7624294 100644 ---- a/fs/eventpoll.c -+++ b/fs/eventpoll.c -@@ -157,6 +157,9 @@ struct epitem { - /* Number of active wait queue attached to poll operations */ - int nwait; - -+ /* fd always raises this fixed event. */ -+ unsigned long fixed_event; -+ - /* List containing poll wait queues */ - struct list_head pwqlist; - -@@ -867,7 +870,7 @@ static int ep_eventpoll_release(struct inode *inode, struct file *file) - static __poll_t ep_read_events_proc(struct eventpoll *ep, struct list_head *head, - void *priv); - static void ep_ptable_queue_proc(struct file *file, wait_queue_head_t *whead, -- poll_table *pt); -+ poll_table *pt, unsigned long fixed_event); - - /* - * Differs from ep_eventpoll_poll() in that internal callers already have -@@ -1283,6 +1286,13 @@ static int ep_poll_callback(wait_queue_entry_t *wait, unsigned mode, int sync, v - if (!(epi->event.events & EPOLLEXCLUSIVE)) - ewake = 1; - -+ /* -+ * If this fd type has a hardwired event which should override the key -+ * (e.g. if it is waiting on a non-file waitqueue), jam it in here. -+ */ -+ if (epi->fixed_event) -+ key = (void *)epi->fixed_event; -+ - if (pollflags & POLLFREE) { - /* - * If we race with ep_remove_wait_queue() it can miss -@@ -1307,11 +1317,17 @@ static int ep_poll_callback(wait_queue_entry_t *wait, unsigned mode, int sync, v - * target file wakeup lists. - */ - static void ep_ptable_queue_proc(struct file *file, wait_queue_head_t *whead, -- poll_table *pt) -+ poll_table *pt, unsigned long fixed_event) - { - struct epitem *epi = ep_item_from_epqueue(pt); - struct eppoll_entry *pwq; - -+ if (fixed_event & !(epi->event.events & fixed_event)) -+ return; -+ -+ if (fixed_event) -+ epi->fixed_event = fixed_event; -+ - if (epi->nwait >= 0 && (pwq = kmem_cache_alloc(pwq_cache, GFP_KERNEL))) { - init_waitqueue_func_entry(&pwq->wait, ep_poll_callback); - pwq->whead = whead; -@@ -1512,6 +1528,7 @@ static int ep_insert(struct eventpoll *ep, const struct epoll_event *event, - ep_set_ffd(&epi->ffd, tfile, fd); - epi->event = *event; - epi->nwait = 0; -+ epi->fixed_event = 0; - epi->next = EP_UNACTIVE_PTR; - if (epi->event.events & EPOLLWAKEUP) { - error = ep_create_wakeup_source(epi); -@@ -2410,7 +2427,6 @@ static int __init eventpoll_init(void) - * We can have many thousands of epitems, so prevent this from - * using an extra cache line on 64-bit (and smaller) CPUs - */ -- BUILD_BUG_ON(sizeof(void *) <= 8 && sizeof(struct epitem) > 128); - - /* Allocates slab cache used to allocate "struct epitem" items */ - epi_cache = kmem_cache_create("eventpoll_epi", sizeof(struct epitem), -diff --git a/fs/io_uring.c b/fs/io_uring.c -index fd12d9327ee5b86120f2370aafa457c08f3a5de4..0d0162ab5301200c05db06dc78535bf70ab6fe6b 100644 ---- a/fs/io_uring.c -+++ b/fs/io_uring.c -@@ -5109,7 +5109,8 @@ static void __io_queue_proc(struct io_poll_iocb *poll, struct io_poll_table *pt, - } - - static void io_async_queue_proc(struct file *file, struct wait_queue_head *head, -- struct poll_table_struct *p) -+ struct poll_table_struct *p, -+ unsigned long fixed_event) - { - struct io_poll_table *pt = container_of(p, struct io_poll_table, pt); - struct async_poll *apoll = pt->req->apoll; -@@ -5405,7 +5406,7 @@ static int io_poll_wake(struct wait_queue_entry *wait, unsigned mode, int sync, - } - - static void io_poll_queue_proc(struct file *file, struct wait_queue_head *head, -- struct poll_table_struct *p) -+ struct poll_table_struct *p, unsigned long fixed_event) - { - struct io_poll_table *pt = container_of(p, struct io_poll_table, pt); - -diff --git a/fs/select.c b/fs/select.c -index 37aaa8317f3ae1a6a9aa9153f336eefa6c2b1aa4..ec91d05beb7d58ab596c17751afd952450edb183 100644 ---- a/fs/select.c -+++ b/fs/select.c -@@ -116,7 +116,7 @@ struct poll_table_page { - * poll table. - */ - static void __pollwait(struct file *filp, wait_queue_head_t *wait_address, -- poll_table *p); -+ poll_table *p, unsigned long fixed_event); - - void poll_initwait(struct poll_wqueues *pwq) - { -@@ -212,6 +212,14 @@ static int pollwake(wait_queue_entry_t *wait, unsigned mode, int sync, void *key - struct poll_table_entry *entry; - - entry = container_of(wait, struct poll_table_entry, wait); -+ -+ /* -+ * If this fd type has a hardwired key which should override the key -+ * (e.g. if it is waiting on a non-file waitqueue), jam it in here. -+ */ -+ if (entry->fixed_key) -+ key = (void *)entry->fixed_key; -+ - if (key && !(key_to_poll(key) & entry->key)) - return 0; - return __pollwake(wait, mode, sync, key); -@@ -219,15 +227,22 @@ static int pollwake(wait_queue_entry_t *wait, unsigned mode, int sync, void *key - - /* Add a new entry */ - static void __pollwait(struct file *filp, wait_queue_head_t *wait_address, -- poll_table *p) -+ poll_table *p, unsigned long fixed_event) - { - struct poll_wqueues *pwq = container_of(p, struct poll_wqueues, pt); -- struct poll_table_entry *entry = poll_get_entry(pwq); -+ struct poll_table_entry *entry; -+ -+ if (fixed_event && !(p->_key & fixed_event)) -+ return; -+ -+ entry = poll_get_entry(pwq); - if (!entry) - return; -+ - entry->filp = get_file(filp); - entry->wait_address = wait_address; - entry->key = p->_key; -+ entry->fixed_key = fixed_event; - init_waitqueue_func_entry(&entry->wait, pollwake); - entry->wait.private = pwq; - add_wait_queue(wait_address, &entry->wait); -diff --git a/fs/waitfd.c b/fs/waitfd.c -new file mode 100644 -index 0000000000000000000000000000000000000000..311f84d7b85fdf71c2caf908050953bc8aef8430 ---- /dev/null -+++ b/fs/waitfd.c -@@ -0,0 +1,130 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * fs/waitfd.c -+ * -+ * Copyright (C) 2008 Red Hat, Casey Dahlin <cdahlin@redhat.com> -+ * -+ * Largely derived from fs/signalfd.c -+ */ -+ -+#include <linux/file.h> -+#include <linux/poll.h> -+#include <linux/init.h> -+#include <linux/fs.h> -+#include <linux/sched.h> -+#include <linux/slab.h> -+#include <linux/kernel.h> -+#include <linux/signal.h> -+#include <linux/list.h> -+#include <linux/anon_inodes.h> -+#include <linux/syscalls.h> -+ -+long kernel_wait4(pid_t upid, int __user *stat_addr, -+ int options, struct rusage __user *ru); -+ -+struct waitfd_ctx { -+ int options; -+ pid_t upid; -+}; -+ -+static int waitfd_release(struct inode *inode, struct file *file) -+{ -+ kfree(file->private_data); -+ return 0; -+} -+ -+static unsigned int waitfd_poll(struct file *file, poll_table *wait) -+{ -+ struct waitfd_ctx *ctx = file->private_data; -+ long value; -+ -+ poll_wait_fixed(file, ¤t->signal->wait_chldexit, wait, -+ POLLIN); -+ -+ value = kernel_wait4(ctx->upid, NULL, ctx->options | WNOHANG | WNOWAIT, -+ NULL); -+ if (value > 0 || value == -ECHILD) -+ return POLLIN | POLLRDNORM; -+ -+ return 0; -+} -+ -+/* -+ * Returns a multiple of the size of a stat_addr, or a negative error code. The -+ * "count" parameter must be at least sizeof(int). -+ */ -+static ssize_t waitfd_read(struct file *file, char __user *buf, size_t count, -+ loff_t *ppos) -+{ -+ struct waitfd_ctx *ctx = file->private_data; -+ int __user *stat_addr = (int *)buf; -+ int flags = ctx->options; -+ ssize_t ret, total = 0; -+ -+ count /= sizeof(int); -+ if (!count) -+ return -EINVAL; -+ -+ if (file->f_flags & O_NONBLOCK) -+ flags |= WNOHANG; -+ -+ do { -+ ret = kernel_wait4(ctx->upid, stat_addr, flags, NULL); -+ if (ret == 0) -+ ret = -EAGAIN; -+ if (ret == -ECHILD) -+ ret = 0; -+ if (ret <= 0) -+ break; -+ -+ stat_addr++; -+ total += sizeof(int); -+ } while (--count); -+ -+ return total ? total : ret; -+} -+ -+static const struct file_operations waitfd_fops = { -+ .release = waitfd_release, -+ .poll = waitfd_poll, -+ .read = waitfd_read, -+ .llseek = noop_llseek, -+}; -+ -+SYSCALL_DEFINE4(waitfd, int __maybe_unused, which, pid_t, upid, int, options, -+ int __maybe_unused, flags) -+{ -+ int ufd; -+ struct waitfd_ctx *ctx; -+ -+ /* -+ * Options validation from kernel_wait4(), minus WNOWAIT, which is -+ * only used by our polling implementation. If WEXITED or WSTOPPED -+ * are provided, silently remove them (for backward compatibility with -+ * older callers). -+ */ -+ options &= ~(WEXITED | WSTOPPED); -+ if (options & ~(WNOHANG|WUNTRACED|WCONTINUED| -+ __WNOTHREAD|__WCLONE|__WALL)) -+ return -EINVAL; -+ -+ ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); -+ if (!ctx) -+ return -ENOMEM; -+ -+ ctx->options = options; -+ ctx->upid = upid; -+ -+ ufd = anon_inode_getfd("[waitfd]", &waitfd_fops, ctx, -+ O_RDWR | flags | ((options & WNOHANG) ? -+ O_NONBLOCK | 0 : 0)); -+ /* -+ * Use the fd's nonblocking state from now on, since that can change. -+ */ -+ ctx->options &= ~WNOHANG; -+ -+ if (ufd < 0) -+ kfree(ctx); -+ -+ return ufd; -+} -diff --git a/include/linux/poll.h b/include/linux/poll.h -index 1cdc32b1f1b0836e6dccf2ecf446b9aeab0a950b..1c06718f39bc8562c12dd22ae61967f2c8b332b5 100644 ---- a/include/linux/poll.h -+++ b/include/linux/poll.h -@@ -34,7 +34,8 @@ struct poll_table_struct; - /* - * structures and helpers for f_op->poll implementations - */ --typedef void (*poll_queue_proc)(struct file *, wait_queue_head_t *, struct poll_table_struct *); -+typedef void (*poll_queue_proc)(struct file *, wait_queue_head_t *, -+ struct poll_table_struct *, unsigned long fixed_event); - - /* - * Do not touch the structure directly, use the access functions -@@ -48,7 +49,15 @@ typedef struct poll_table_struct { - static inline void poll_wait(struct file * filp, wait_queue_head_t * wait_address, poll_table *p) - { - if (p && p->_qproc && wait_address) -- p->_qproc(filp, wait_address, p); -+ p->_qproc(filp, wait_address, p, 0); -+} -+ -+static inline void poll_wait_fixed(struct file *filp, -+ wait_queue_head_t *wait_address, poll_table *p, -+ unsigned long fixed_event) -+{ -+ if (p && p->_qproc && wait_address) -+ p->_qproc(filp, wait_address, p, fixed_event); - } - - /* -@@ -93,6 +102,7 @@ static inline __poll_t vfs_poll(struct file *file, struct poll_table_struct *pt) - struct poll_table_entry { - struct file *filp; - __poll_t key; -+ unsigned long fixed_key; - wait_queue_entry_t wait; - wait_queue_head_t *wait_address; - }; -diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h -index aea0ce9f3b745ad8f8bfeed1b74ad9c1307f1c28..0db3a09986d7b856267c6e6d801e04cbbd294ef7 100644 ---- a/include/linux/syscalls.h -+++ b/include/linux/syscalls.h -@@ -1366,6 +1366,9 @@ long ksys_old_shmctl(int shmid, int cmd, struct shmid_ds __user *buf); - long compat_ksys_semtimedop(int semid, struct sembuf __user *tsems, - unsigned int nsops, - const struct old_timespec32 __user *timeout); -+#ifdef CONFIG_DTRACE -+asmlinkage long sys_waitfd(int which, pid_t upid, int options, int flags); -+#endif - - int __sys_getsockopt(int fd, int level, int optname, char __user *optval, - int __user *optlen); -diff --git a/include/uapi/asm-generic/unistd.h b/include/uapi/asm-generic/unistd.h -index 2056318988f774931c4e0a3104144bf4a75ff52f..58238d6fbbcba9e52cf799d5b283851c3e593b82 100644 ---- a/include/uapi/asm-generic/unistd.h -+++ b/include/uapi/asm-generic/unistd.h -@@ -860,8 +860,11 @@ __SYSCALL(__NR_faccessat2, sys_faccessat2) - #define __NR_process_madvise 440 - __SYSCALL(__NR_process_madvise, sys_process_madvise) - -+#define __NR_waitfd 473 -+__SYSCALL(__NR_waitfd, sys_waitfd) -+ - #undef __NR_syscalls --#define __NR_syscalls 441 -+#define __NR_syscalls 474 - - /* - * 32 bit systems traditionally used different -diff --git a/init/Kconfig b/init/Kconfig -index 05d377ccc0e08c27391242886bbd8904a17b4ef4..5a86bbbf43e052f9092da824536c8e223c4a4329 100644 ---- a/init/Kconfig -+++ b/init/Kconfig -@@ -1562,6 +1562,22 @@ config EPOLL - Disabling this option will cause the kernel to be built without - support for epoll family of system calls. - -+config WAITFD -+ bool "Enable waitfd() system call" if EXPERT -+ select ANON_INODES -+ default n -+ help -+ Enable the waitfd() system call that allows receiving child state -+ changes from a file descriptor. This permits use of poll() to -+ monitor waitpid() output simultaneously with other fd state changes, -+ even if the waitpid() output is coming from thread-targetted sources -+ such as ptrace(). -+ -+ Note: this system call is not upstream: its syscall number is not -+ finalized, so the call itself should only be used with caution. -+ -+ If unsure, say N. -+ - config SIGNALFD - bool "Enable signalfd() system call" if EXPERT - default y -diff --git a/kernel/exit.c b/kernel/exit.c -index d13d67fc5f4e2085f93c46b77440ca1eeb908833..5c5859a9ba75afff23fcdffcb01eef159724c6df 100644 ---- a/kernel/exit.c -+++ b/kernel/exit.c -@@ -1586,7 +1586,10 @@ long kernel_wait4(pid_t upid, int __user *stat_addr, int options, - enum pid_type type; - long ret; - -- if (options & ~(WNOHANG|WUNTRACED|WCONTINUED| -+ /* -+ * As for wait4(), except that waitfd() additionally needs WNOWAIT. -+ */ -+ if (options & ~(WNOHANG|WNOWAIT|WUNTRACED|WCONTINUED| - __WNOTHREAD|__WCLONE|__WALL)) - return -EINVAL; - -@@ -1641,7 +1644,13 @@ SYSCALL_DEFINE4(wait4, pid_t, upid, int __user *, stat_addr, - int, options, struct rusage __user *, ru) - { - struct rusage r; -- long err = kernel_wait4(upid, stat_addr, options, ru ? &r : NULL); -+ long err; -+ -+ if (options & ~(WNOHANG|WUNTRACED|WCONTINUED| -+ __WNOTHREAD|__WCLONE|__WALL)) -+ return -EINVAL; -+ -+ err = kernel_wait4(upid, stat_addr, options, ru ? &r : NULL); - - if (err > 0) { - if (ru && copy_to_user(ru, &r, sizeof(struct rusage))) -diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c -index f27ac94d5fa7270ba9f272be1bcba6a903149206..53900d50a8af730dbc419cf35e9bafe2f29024e5 100644 ---- a/kernel/sys_ni.c -+++ b/kernel/sys_ni.c -@@ -391,6 +391,7 @@ COND_SYSCALL(subpage_prot); - * include/uapi/asm-generic/unistd.h and wanted by >= 1 arch - */ - -+COND_SYSCALL(waitfd); - /* __ARCH_WANT_SYSCALL_NO_FLAGS */ - COND_SYSCALL(epoll_create); - COND_SYSCALL(inotify_init); -diff --git a/mm/memcontrol.c b/mm/memcontrol.c -index 8fc23d53f55009064c3160a0f6fab047bff6acf8..a5d4a1d4f8683a8138c836021c85c16978c53e68 100644 ---- a/mm/memcontrol.c -+++ b/mm/memcontrol.c -@@ -4839,7 +4839,7 @@ static int memcg_event_wake(wait_queue_entry_t *wait, unsigned mode, - } - - static void memcg_event_ptable_queue_proc(struct file *file, -- wait_queue_head_t *wqh, poll_table *pt) -+ wait_queue_head_t *wqh, poll_table *pt, unsigned long unused) - { - struct mem_cgroup_event *event = - container_of(pt, struct mem_cgroup_event, pt); -diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c -index 8f528e783a6c533f604371228b7e31c28ea87577..d4890a86c0ce717009e31562f03ff0bcb3cffc3f 100644 ---- a/net/9p/trans_fd.c -+++ b/net/9p/trans_fd.c -@@ -545,7 +545,8 @@ static int p9_pollwake(wait_queue_entry_t *wait, unsigned int mode, int sync, vo - */ - - static void --p9_pollwait(struct file *filp, wait_queue_head_t *wait_address, poll_table *p) -+p9_pollwait(struct file *filp, wait_queue_head_t *wait_address, poll_table *p, -+ unsigned long unused) - { - struct p9_conn *m = container_of(p, struct p9_conn, pt); - struct p9_poll_wait *pwait = NULL; -diff --git a/tools/testing/selftests/waitfd/Makefile b/tools/testing/selftests/waitfd/Makefile -new file mode 100644 -index 0000000000000000000000000000000000000000..f85c80b54f05ed71c4ad8cadc1ba6fc766a303d6 ---- /dev/null -+++ b/tools/testing/selftests/waitfd/Makefile -@@ -0,0 +1,28 @@ -+uname_M := $(shell uname -m 2>/dev/null || echo not) -+ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/) -+ifeq ($(ARCH),i386) -+ ARCH := X86 -+ CFLAGS := -DCONFIG_X86_32 -D__i386__ -+endif -+ifeq ($(ARCH),x86_64) -+ ARCH := X86 -+ CFLAGS := -DCONFIG_X86_64 -D__x86_64__ -+endif -+ -+CFLAGS += -I../../../../arch/x86/include/generated/ -+CFLAGS += -I../../../../include/ -+CFLAGS += -I../../../../usr/include/ -+CFLAGS += -I../../../../arch/x86/include/ -+ -+all: -+ifeq ($(ARCH),X86) -+ gcc $(CFLAGS) waitfd.c -o waitfd -+else -+ echo "Not an x86 target, can't build waitfd selftest" -+endif -+ -+run_tests: all -+ @./waitfd || echo "waitfd: [FAIL]" -+ -+clean: -+ rm -fr ./waitfd -diff --git a/tools/testing/selftests/waitfd/waitfd.c b/tools/testing/selftests/waitfd/waitfd.c -new file mode 100644 -index 0000000000000000000000000000000000000000..2df60bbdbb3569384dccca820ca77593abc67988 ---- /dev/null -+++ b/tools/testing/selftests/waitfd/waitfd.c -@@ -0,0 +1,116 @@ -+// SPDX-License-Identifier: GPL-2.0 -+/* waitfd testcase. */ -+ -+#define _GNU_SOURCE 1 -+#include <linux/unistd.h> -+#include <sys/syscall.h> -+#include <sys/ptrace.h> -+#include <sys/types.h> -+#include <sys/wait.h> -+#include <errno.h> -+#include <stdio.h> -+#include <stdlib.h> -+#include <unistd.h> -+#include <signal.h> -+#include <string.h> -+#include <poll.h> -+ -+int waitfd(int which, pid_t upid, int options, int flags) -+{ -+ return syscall(__NR_waitfd, which, upid, options, flags); -+} -+ -+void sleeper(void) -+{ -+ sleep(10); -+ exit(0); -+} -+ -+int main (void) -+{ -+ pid_t die_pid, ptrace_pid; -+ int die_fd, ptrace_fd; -+ int status; -+ struct pollfd pfd[2]; -+ int procs_left = 2; -+ -+ memset(pfd, 0, sizeof(pfd)); -+ -+ /* -+ * Fork off two children, one of which waits for a ptrace(). -+ * Both just sleep after that. Make sure we can use __WNOTHREAD, -+ * __WALL, and WUNTRACED without getting an -EINVAL. -+ */ -+ -+ die_pid = fork(); -+ -+ if (die_pid == 0) -+ sleeper(); -+ -+ ptrace_pid = fork(); -+ if (ptrace_pid == 0) { -+ ptrace(PTRACE_TRACEME, 0, 0, 0); -+ sleeper(); -+ } -+ -+ die_fd = waitfd(P_PID, die_pid, 0, 0); -+ ptrace_fd = waitfd(P_PID, ptrace_pid, __WNOTHREAD | __WALL | WUNTRACED, 0); -+ -+ if (die_fd < 0 || ptrace_fd < 0) { -+ perror("Cannot waitfd()"); -+ exit(1); -+ } -+ -+ pfd[0].fd = die_fd; -+ pfd[0].events = POLLIN; -+ pfd[1].fd = ptrace_fd; -+ pfd[1].events = POLLIN; -+ -+ /* -+ * Hit the ptrace PID with a signal -+ */ -+ kill(ptrace_pid, SIGABRT); -+ -+ while (procs_left > 0) { -+ ssize_t bytes; -+ -+ if (poll(pfd, 2, -1) < 0) -+ perror ("poll() failed"); -+ -+ if (pfd[0].revents != 0) { -+ bytes = read(die_fd, &status, sizeof(int)); -+ if (bytes < sizeof(int)) { -+ fprintf(stderr, "Only read %zi bytes\n", bytes); -+ exit(1); -+ } -+ -+ printf("die_fd returned %i via waitfd read: revents are %x\n", -+ status, pfd[0].revents); -+ pfd[0].fd *= -1; -+ procs_left--; -+ } -+ -+ if (pfd[1].revents != 0) { -+ pid_t check_pid; -+ status = 0; -+ check_pid = waitpid(ptrace_pid, &status, __WNOTHREAD | -+ __WALL | WUNTRACED | WNOHANG); -+ if (check_pid < 0) { -+ fprintf(stderr, "waitpid() failed: %s\n", -+ strerror(errno)); -+ exit(1); -+ } -+ if (check_pid != ptrace_pid) { -+ fprintf(stderr, "waitfd() said PID %i was ready, but waitpid() says it isn't: %i\n", -+ ptrace_pid, check_pid); -+ exit(1); -+ } -+ printf("ptrace_fd returned status %i via waitpid; revents are %x\n", -+ status, pfd[1].revents); -+ pfd[1].fd *= -1; -+ procs_left--; -+ } -+ } -+ -+ return 0; -+} -diff --git a/virt/kvm/eventfd.c b/virt/kvm/eventfd.c -index c2323c27a28b52dd14c6405dcbc8d54b1356efe0..8da91bb7015c1a354e6e0e3b973a8a828a19d7a5 100644 ---- a/virt/kvm/eventfd.c -+++ b/virt/kvm/eventfd.c -@@ -232,7 +232,7 @@ irqfd_wakeup(wait_queue_entry_t *wait, unsigned mode, int sync, void *key) - - static void - irqfd_ptable_queue_proc(struct file *file, wait_queue_head_t *wqh, -- poll_table *pt) -+ poll_table *pt, unsigned long unused) - { - struct kvm_kernel_irqfd *irqfd = - container_of(pt, struct kvm_kernel_irqfd, pt); --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/dtrace-patches/0004-dtrace-core-and-x86.patch b/sys-kernel/cairn-sources/files/5.10.14/dtrace-patches/0004-dtrace-core-and-x86.patch deleted file mode 100644 index 7731639119d8..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/dtrace-patches/0004-dtrace-core-and-x86.patch +++ /dev/null @@ -1,8053 +0,0 @@ -From 6b71ecc990f6b40c944f31ec14a75032e4e09235 Mon Sep 17 00:00:00 2001 -From: Kris Van Hees <kris.van.hees@oracle.com> -Date: Mon, 19 Nov 2018 22:21:36 +0000 -Subject: [PATCH 04/19] dtrace: core and x86 - -This implements DTrace's core kernel (linked-in) components, -including platform-dependent portions for x86. (Most of this -machinery is not used until the next commit.) - -Signed-off-by: Nick Alcock <nick.alcock@oracle.com> -Signed-off-by: Kris Van Hees <kris.van.hees@oracle.com> -Signed-off-by: Tomas Jedlicka <tomas.jedlicka@oracle.com> -Signed-off-by: Eugene Loh <eugene.loh@oracle.com> -Signed-off-by: David Mc Lean <david.mclean@oracle.com> -Signed-off-by: Vincent Lim <vincent.lim@oracle.com> ---- - Makefile | 7 +- - arch/x86/Kconfig | 3 + - arch/x86/include/asm/dtrace_arch.h | 28 + - arch/x86/include/asm/dtrace_cpuinfo.h | 14 + - arch/x86/include/asm/dtrace_util.h | 16 + - arch/x86/kernel/dtrace_util.c | 244 ++++ - arch/x86/mm/fault.c | 28 +- - fs/exec.c | 5 + - include/asm-generic/qrwlock.h | 24 + - include/dtrace/dtrace_impl.h | 1236 +++++++++++++++++ - include/dtrace/dtrace_impl_defines.h | 173 +++ - include/dtrace/provider.h | 971 +++++++++++++ - include/dtrace/provider_defines.h | 41 + - include/dtrace/types.h | 131 ++ - include/linux/cpuhotplug.h | 1 + - include/linux/cyclic.h | 49 + - include/linux/dtrace/cpu_defines.h | 61 + - include/linux/dtrace_cpu.h | 53 + - include/linux/dtrace_cpu_defines.h | 2 + - include/linux/dtrace_os.h | 120 ++ - include/linux/dtrace_psinfo.h | 59 + - include/linux/dtrace_task.h | 38 + - include/linux/dtrace_task_impl.h | 28 + - include/linux/dtrace_types.h | 13 + - include/linux/ktime.h | 8 + - include/linux/module.h | 3 + - include/linux/mutex.h | 16 + - include/linux/rwlock.h | 7 + - include/linux/sched.h | 4 + - include/linux/spinlock_up.h | 5 + - include/uapi/linux/dtrace/Kbuild | 35 + - include/uapi/linux/dtrace/actions.h | 14 + - include/uapi/linux/dtrace/actions_defines.h | 181 +++ - include/uapi/linux/dtrace/arg.h | 42 + - include/uapi/linux/dtrace/arg_defines.h | 21 + - include/uapi/linux/dtrace/buffer.h | 43 + - include/uapi/linux/dtrace/buffer_defines.h | 21 + - include/uapi/linux/dtrace/conf.h | 35 + - include/uapi/linux/dtrace/conf_defines.h | 21 + - include/uapi/linux/dtrace/cpu_defines.h | 17 + - include/uapi/linux/dtrace/dif.h | 60 + - include/uapi/linux/dtrace/dif_defines.h | 288 ++++ - include/uapi/linux/dtrace/difo.h | 57 + - include/uapi/linux/dtrace/difo_defines.h | 21 + - include/uapi/linux/dtrace/dof.h | 196 +++ - include/uapi/linux/dtrace/dof_defines.h | 192 +++ - include/uapi/linux/dtrace/dtrace.h | 33 + - include/uapi/linux/dtrace/enabling.h | 76 + - include/uapi/linux/dtrace/enabling_defines.h | 25 + - include/uapi/linux/dtrace/fasttrap.h | 56 + - include/uapi/linux/dtrace/fasttrap_defines.h | 25 + - include/uapi/linux/dtrace/fasttrap_ioctl.h | 19 + - include/uapi/linux/dtrace/faults.h | 20 + - include/uapi/linux/dtrace/faults_defines.h | 39 + - include/uapi/linux/dtrace/helpers.h | 101 ++ - include/uapi/linux/dtrace/helpers_defines.h | 21 + - include/uapi/linux/dtrace/ioctl.h | 47 + - include/uapi/linux/dtrace/metadesc.h | 81 ++ - include/uapi/linux/dtrace/metadesc_defines.h | 24 + - include/uapi/linux/dtrace/options.h | 20 + - include/uapi/linux/dtrace/options_defines.h | 72 + - include/uapi/linux/dtrace/stability.h | 52 + - include/uapi/linux/dtrace/stability_defines.h | 53 + - include/uapi/linux/dtrace/status.h | 50 + - include/uapi/linux/dtrace/universal.h | 47 + - init/Kconfig | 2 + - init/main.c | 10 + - kernel/Makefile | 1 + - kernel/dtrace/Kconfig | 54 + - kernel/dtrace/Makefile | 12 + - kernel/dtrace/cyclic.c | 526 +++++++ - kernel/dtrace/dtrace_cpu.c | 61 + - kernel/dtrace/dtrace_os.c | 332 +++++ - kernel/dtrace/dtrace_psinfo.c | 212 +++ - kernel/dtrace/dtrace_task.c | 237 ++++ - kernel/exit.c | 4 + - kernel/fork.c | 23 + - kernel/module.c | 14 + - kernel/sched/core.c | 10 + - kernel/sched/sched.h | 4 + - kernel/time/timekeeping.c | 2 + - scripts/coccinelle/dtrace/enum-elision.cocci | 29 + - .../coccinelle/dtrace/typedef-elision.cocci | 83 ++ - scripts/package/mkspec | 1 + - 84 files changed, 7106 insertions(+), 4 deletions(-) - create mode 100644 arch/x86/include/asm/dtrace_arch.h - create mode 100644 arch/x86/include/asm/dtrace_cpuinfo.h - create mode 100644 arch/x86/include/asm/dtrace_util.h - create mode 100644 arch/x86/kernel/dtrace_util.c - create mode 100644 include/dtrace/dtrace_impl.h - create mode 100644 include/dtrace/dtrace_impl_defines.h - create mode 100644 include/dtrace/provider.h - create mode 100644 include/dtrace/provider_defines.h - create mode 100644 include/dtrace/types.h - create mode 100644 include/linux/cyclic.h - create mode 100644 include/linux/dtrace/cpu_defines.h - create mode 100644 include/linux/dtrace_cpu.h - create mode 100644 include/linux/dtrace_cpu_defines.h - create mode 100644 include/linux/dtrace_os.h - create mode 100644 include/linux/dtrace_psinfo.h - create mode 100644 include/linux/dtrace_task.h - create mode 100644 include/linux/dtrace_task_impl.h - create mode 100644 include/linux/dtrace_types.h - create mode 100644 include/uapi/linux/dtrace/Kbuild - create mode 100644 include/uapi/linux/dtrace/actions.h - create mode 100644 include/uapi/linux/dtrace/actions_defines.h - create mode 100644 include/uapi/linux/dtrace/arg.h - create mode 100644 include/uapi/linux/dtrace/arg_defines.h - create mode 100644 include/uapi/linux/dtrace/buffer.h - create mode 100644 include/uapi/linux/dtrace/buffer_defines.h - create mode 100644 include/uapi/linux/dtrace/conf.h - create mode 100644 include/uapi/linux/dtrace/conf_defines.h - create mode 100644 include/uapi/linux/dtrace/cpu_defines.h - create mode 100644 include/uapi/linux/dtrace/dif.h - create mode 100644 include/uapi/linux/dtrace/dif_defines.h - create mode 100644 include/uapi/linux/dtrace/difo.h - create mode 100644 include/uapi/linux/dtrace/difo_defines.h - create mode 100644 include/uapi/linux/dtrace/dof.h - create mode 100644 include/uapi/linux/dtrace/dof_defines.h - create mode 100644 include/uapi/linux/dtrace/dtrace.h - create mode 100644 include/uapi/linux/dtrace/enabling.h - create mode 100644 include/uapi/linux/dtrace/enabling_defines.h - create mode 100644 include/uapi/linux/dtrace/fasttrap.h - create mode 100644 include/uapi/linux/dtrace/fasttrap_defines.h - create mode 100644 include/uapi/linux/dtrace/fasttrap_ioctl.h - create mode 100644 include/uapi/linux/dtrace/faults.h - create mode 100644 include/uapi/linux/dtrace/faults_defines.h - create mode 100644 include/uapi/linux/dtrace/helpers.h - create mode 100644 include/uapi/linux/dtrace/helpers_defines.h - create mode 100644 include/uapi/linux/dtrace/ioctl.h - create mode 100644 include/uapi/linux/dtrace/metadesc.h - create mode 100644 include/uapi/linux/dtrace/metadesc_defines.h - create mode 100644 include/uapi/linux/dtrace/options.h - create mode 100644 include/uapi/linux/dtrace/options_defines.h - create mode 100644 include/uapi/linux/dtrace/stability.h - create mode 100644 include/uapi/linux/dtrace/stability_defines.h - create mode 100644 include/uapi/linux/dtrace/status.h - create mode 100644 include/uapi/linux/dtrace/universal.h - create mode 100644 kernel/dtrace/Kconfig - create mode 100644 kernel/dtrace/Makefile - create mode 100644 kernel/dtrace/cyclic.c - create mode 100644 kernel/dtrace/dtrace_cpu.c - create mode 100644 kernel/dtrace/dtrace_os.c - create mode 100644 kernel/dtrace/dtrace_psinfo.c - create mode 100644 kernel/dtrace/dtrace_task.c - create mode 100644 scripts/coccinelle/dtrace/enum-elision.cocci - create mode 100644 scripts/coccinelle/dtrace/typedef-elision.cocci - -diff --git a/Makefile b/Makefile -index c21d2a09c9ca1419369295c2d29535e37135e6a4..fb9393fa10f082c29ab717aefcc812e34f8caf9d 100644 ---- a/Makefile -+++ b/Makefile -@@ -1106,15 +1106,15 @@ core-y += kernel/ certs/ mm/ fs/ ipc/ security/ crypto/ block/ - - vmlinux-dirs := $(patsubst %/,%,$(filter %/, \ - $(core-y) $(core-m) $(drivers-y) $(drivers-m) \ -- $(libs-y) $(libs-m))) -+ $(libs-y) $(libs-m) $(dtrace-y) $(dtrace-m))) - - vmlinux-alldirs := $(sort $(vmlinux-dirs) Documentation \ - $(patsubst %/,%,$(filter %/, $(core-) \ -- $(drivers-) $(libs-)))) -+ $(drivers-) $(libs-) $(dtrace-)))) - - subdir-modorder := $(addsuffix modules.order,$(filter %/, \ - $(core-y) $(core-m) $(libs-y) $(libs-m) \ -- $(drivers-y) $(drivers-m))) -+ $(drivers-y) $(drivers-m) $(dtrace-y) $(dtrace-m))) - - build-dirs := $(vmlinux-dirs) - clean-dirs := $(vmlinux-alldirs) -@@ -1129,6 +1129,7 @@ else - KBUILD_VMLINUX_LIBS := $(patsubst %/,%/lib.a, $(libs-y)) - endif - KBUILD_VMLINUX_OBJS += $(patsubst %/,%/built-in.a, $(drivers-y)) -+KBUILD_VMLINUX_OBJS += $(patsubst %/,%/built-in.a, $(dtrace-y)) - - export KBUILD_VMLINUX_OBJS KBUILD_VMLINUX_LIBS - export KBUILD_LDS := arch/$(SRCARCH)/kernel/vmlinux.lds -diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig -index 3a5ecb1039bfb8e9033f56d404ba9db20a2beddd..372e81191f8e42e6deba09586db9d81cd03b80fe 100644 ---- a/arch/x86/Kconfig -+++ b/arch/x86/Kconfig -@@ -371,6 +371,9 @@ config PGTABLE_LEVELS - default 3 if X86_PAE - default 2 - -+config ARCH_SUPPORTS_DTRACE -+ def_bool y if X86_64 -+ - config CC_HAS_SANE_STACKPROTECTOR - bool - default $(success,$(srctree)/scripts/gcc-x86_64-has-stack-protector.sh $(CC)) if 64BIT -diff --git a/arch/x86/include/asm/dtrace_arch.h b/arch/x86/include/asm/dtrace_arch.h -new file mode 100644 -index 0000000000000000000000000000000000000000..74e27f08a873c9cd3ed329d911e8e18505ae5b62 ---- /dev/null -+++ b/arch/x86/include/asm/dtrace_arch.h -@@ -0,0 +1,28 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+ -+/* -+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+#ifndef _X86_DTRACE_ARCH_H -+#define _X86_DTRACE_ARCH_H -+ -+/* Number of arguments stored inside the mstate. */ -+#define DTRACE_MSTATE_ARGS_MAX 6 -+ -+typedef uint8_t asm_instr_t; -+ -+typedef int (*prov_exit_f)(void); -+ -+/* -+ * Structure to hold DTrace specific information about modules (including the -+ * core kernel module). Note that each module (and the main kernel) already -+ * has one field that relates to probing: -+ * - pdata: pointer to a dtrace_module struct (for DTrace) -+ */ -+struct dtrace_module { -+ int enabled_cnt; -+ prov_exit_f prov_exit; /* Called with module_mutex held */ -+}; -+ -+#endif /* _X86_DTRACE_ARCH_H */ -diff --git a/arch/x86/include/asm/dtrace_cpuinfo.h b/arch/x86/include/asm/dtrace_cpuinfo.h -new file mode 100644 -index 0000000000000000000000000000000000000000..47024e169ec4f93eeea38a6c03922e3385d9e282 ---- /dev/null -+++ b/arch/x86/include/asm/dtrace_cpuinfo.h -@@ -0,0 +1,14 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+ -+/* Copyright (C) 2013-2014 Oracle, Inc. */ -+ -+#ifndef _ASM_X86_DTRACE_CPUINFO_H_ -+#define _ASM_X86_DTRACE_CPUINFO_H_ -+ -+#include <asm/processor.h> -+ -+typedef struct cpuinfo_x86 cpuinfo_arch_t; -+ -+#define dtrace_cpuinfo_chip(ci) ((ci)->phys_proc_id) -+ -+#endif /* _ASM_X86_DTRACE_CPUINFO_H_ */ -diff --git a/arch/x86/include/asm/dtrace_util.h b/arch/x86/include/asm/dtrace_util.h -new file mode 100644 -index 0000000000000000000000000000000000000000..4d9843bbc95b92dcc3c20d4aa1d2b762b7376d91 ---- /dev/null -+++ b/arch/x86/include/asm/dtrace_util.h -@@ -0,0 +1,16 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+#ifndef _X86_DTRACE_UTIL_H -+#define _X86_DTRACE_UTIL_H -+ -+#ifndef __ASSEMBLY__ -+ -+#include <asm/dtrace_arch.h> -+#include <asm/ptrace.h> -+ -+#endif -+ -+#endif /* _X86_DTRACE_UTIL_H */ -diff --git a/arch/x86/kernel/dtrace_util.c b/arch/x86/kernel/dtrace_util.c -new file mode 100644 -index 0000000000000000000000000000000000000000..d3d552c062f7ea425567cdb867b31f65d0242cac ---- /dev/null -+++ b/arch/x86/kernel/dtrace_util.c -@@ -0,0 +1,244 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_util.c -+ * DESCRIPTION: Dynamic Tracing: Architecture utility functions -+ * -+ * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+#include <linux/dtrace_cpu.h> -+#include <linux/dtrace_os.h> -+#include <linux/dtrace_task_impl.h> -+#include <linux/kdebug.h> -+#include <linux/mm.h> -+#include <linux/module.h> -+#include <linux/memory.h> -+#include <linux/notifier.h> -+#include <linux/ptrace.h> -+#include <linux/sched.h> -+#include <linux/slab.h> -+#include <linux/uaccess.h> -+#include <linux/sched/task_stack.h> -+#include <asm/insn.h> -+#include <asm/pgtable.h> -+#include <asm/ptrace.h> -+#include <asm/text-patching.h> -+#include <asm/dtrace_arch.h> -+#include <asm/dtrace_util.h> -+ -+int dtrace_instr_size(const asm_instr_t *addr) -+{ -+ struct insn insn; -+ -+ kernel_insn_init(&insn, addr, MAX_INSN_SIZE); -+ insn_get_length(&insn); -+ -+ return insn_complete(&insn) ? insn.length : -1; -+} -+EXPORT_SYMBOL(dtrace_instr_size); -+ -+/* -+ * Move the instruction pointer forward to the next instruction, effectiely -+ * skipping the current one. -+ */ -+static void dtrace_skip_instruction(struct pt_regs *regs) -+{ -+ int delta; -+ -+ delta = dtrace_instr_size((asm_instr_t *)regs->ip); -+ BUG_ON(delta <= 0); -+ -+ regs->ip += delta; -+} -+ -+void dtrace_handle_badaddr(struct pt_regs *regs) -+{ -+ unsigned long addr = read_cr2(); -+ -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); -+ this_cpu_core->cpuc_dtrace_illval = addr; -+ -+ dtrace_skip_instruction(regs); -+} -+ -+/* -+ * Trap notification handler. -+ */ -+int dtrace_die_notifier(struct notifier_block *nb, unsigned long val, -+ void *args) -+{ -+ struct die_args *dargs = args; -+ -+ switch (val) { -+ case DIE_PAGE_FAULT: { -+ if (!DTRACE_CPUFLAG_ISSET(CPU_DTRACE_NOFAULT)) -+ return NOTIFY_DONE; -+ -+ dtrace_handle_badaddr(dargs->regs); -+ -+ return NOTIFY_OK | NOTIFY_STOP_MASK; -+ } -+ case DIE_GPF: { -+ if (!DTRACE_CPUFLAG_ISSET(CPU_DTRACE_NOFAULT)) -+ return NOTIFY_DONE; -+ -+ dtrace_handle_badaddr(dargs->regs); -+ -+ return NOTIFY_OK | NOTIFY_STOP_MASK; -+ } -+ /* fallthrough */ -+ default: -+ return NOTIFY_DONE; -+ } -+} -+ -+static inline int dtrace_bad_address(void *addr) -+{ -+ unsigned long dummy; -+ -+ return get_kernel_nofault(dummy, (unsigned long *)addr); -+} -+ -+static int dtrace_user_addr_is_exec(uintptr_t addr) -+{ -+ struct mm_struct *mm = current->mm; -+ pgd_t *pgd; -+ -+#if CONFIG_PGTABLE_LEVELS > 3 -+ p4d_t *p4d; -+#endif -+ -+ pud_t *pud; -+ pmd_t *pmd; -+ pte_t *pte; -+ unsigned long flags; -+ int ret = 0; -+ -+ if (mm == NULL) -+ return 0; -+ -+ addr &= PAGE_MASK; -+ -+ local_irq_save(flags); -+ -+ pgd = pgd_offset(mm, addr); -+ if (dtrace_bad_address(pgd)) -+ goto out; -+ if (pgd_none(*pgd) || !pgd_present(*pgd)) -+ goto out; -+ -+#if CONFIG_PGTABLE_LEVELS > 3 -+ p4d = p4d_offset(pgd, addr); -+ if (dtrace_bad_address(p4d)) -+ goto out; -+ if (p4d_none(*p4d) || !p4d_present(*p4d)) -+ goto out; -+ -+ pud = pud_offset(p4d, addr); -+#else -+ pud = pud_offset(pgd, addr); -+#endif -+ -+ if (dtrace_bad_address(pud)) -+ goto out; -+ if (pud_none(*pud) || !pud_present(*pud)) -+ goto out; -+ if (unlikely(pud_large(*pud))) { -+ pte = (pte_t *)pud; -+ if (dtrace_bad_address(pte)) -+ goto out; -+ -+ ret = pte_exec(*pte); -+ goto out; -+ } -+ -+ pmd = pmd_offset(pud, addr); -+ if (dtrace_bad_address(pmd)) -+ goto out; -+ if (pmd_none(*pmd)) -+ goto out; -+ if (unlikely(pmd_large(*pmd) || !pmd_present(*pmd))) { -+ pte = (pte_t *)pmd; -+ if (dtrace_bad_address(pte)) -+ goto out; -+ -+ ret = pte_exec(*pte); -+ goto out; -+ } -+ -+ pte = pte_offset_map(pmd, addr); -+ if (dtrace_bad_address(pte)) -+ goto out; -+ if (pte_protnone(*pte)) -+ goto out; -+ if ((pte_flags(*pte) & (_PAGE_PRESENT|_PAGE_USER|_PAGE_SPECIAL)) != -+ (_PAGE_PRESENT|_PAGE_USER)) -+ goto out; -+ -+ ret = pte_exec(*pte); -+ -+out: -+ local_irq_restore(flags); -+ -+ return ret; -+} -+ -+void dtrace_user_stacktrace(struct stacktrace_state *st) -+{ -+ struct pt_regs *regs = current_pt_regs(); -+ uint64_t *pcs = st->pcs; -+ int limit = st->limit; -+ unsigned long *bos; -+ unsigned long *sp = (unsigned long *)user_stack_pointer(regs); -+ int ret; -+ -+ if (!user_mode(regs)) -+ goto out; -+ -+ if (current->dt_task == NULL) -+ goto out; -+ -+ bos = current->dt_task->dt_ustack; -+ -+ st->depth = 1; -+ if (pcs) -+ *pcs++ = (uint64_t)instruction_pointer(regs); -+ limit--; -+ -+ if (!limit) -+ goto out; -+ -+ while (sp <= bos && limit) { -+ unsigned long pc; -+ -+ pagefault_disable(); -+ ret = __copy_from_user_inatomic(&pc, sp, sizeof(pc)); -+ pagefault_enable(); -+ -+ if (ret) -+ break; -+ -+ if (dtrace_user_addr_is_exec(pc)) { -+ if (pcs) -+ *pcs++ = pc; -+ limit--; -+ st->depth++; -+ } -+ -+ sp++; -+ } -+ -+out: -+ if (pcs) { -+ while (limit--) -+ *pcs++ = 0; -+ } -+} -+ -+void dtrace_mod_pdata_init(struct dtrace_module *pdata) -+{ -+} -+ -+void dtrace_mod_pdata_cleanup(struct dtrace_module *pdata) -+{ -+} -diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c -index 82bf37a5c9eccadcc3a9b0ba875d6bdb2d5df1eb..5b16183100d07fb85d26163b11694097b774a751 100644 ---- a/arch/x86/mm/fault.c -+++ b/arch/x86/mm/fault.c -@@ -18,6 +18,7 @@ - #include <linux/uaccess.h> /* faulthandler_disabled() */ - #include <linux/efi.h> /* efi_recover_from_page_fault()*/ - #include <linux/mm_types.h> -+#include <linux/dtrace_os.h> /* dtrace_no_pf */ - - #include <asm/cpufeature.h> /* boot_cpu_has, ... */ - #include <asm/traps.h> /* dotraplinkage, ... */ -@@ -680,6 +681,16 @@ no_context(struct pt_regs *regs, unsigned long error_code, - (((unsigned long)tsk->stack - 1 - address < PAGE_SIZE) || - address - ((unsigned long)tsk->stack + THREAD_SIZE) < PAGE_SIZE)) { - unsigned long stack = __this_cpu_ist_top_va(DF) - sizeof(void *); -+ -+ /* -+ * Allow for the possibility that we know what we are doing and -+ * ignore this fault. E.g. the address may come from a source -+ * we cannot trust and it is OK if we cannot access it. -+ */ -+ if (notify_die(DIE_PAGE_FAULT, "page fault", regs, error_code, -+ 14, SIGKILL) == NOTIFY_STOP) -+ return; -+ - /* - * We're likely to be running with very little stack space - * left. It's plausible that we'd hit this condition but -@@ -728,8 +739,13 @@ no_context(struct pt_regs *regs, unsigned long error_code, - oops: - /* - * Oops. The kernel tried to access some bad page. We'll have to -- * terminate things with extreme prejudice: -+ * terminate things with extreme prejudice, unless a notifier decides -+ * to let this one slide. - */ -+ if (notify_die(DIE_PAGE_FAULT, "page fault", regs, error_code, 14, -+ SIGKILL) == NOTIFY_STOP) -+ return; -+ - flags = oops_begin(); - - show_fault_oops(regs, error_code, address); -@@ -1223,10 +1239,20 @@ void do_user_addr_fault(struct pt_regs *regs, - tsk = current; - mm = tsk->mm; - -+ /* -+ * From here on, we know this must be a fault in userspace. -+ */ -+ - /* kprobes don't want to hook the spurious faults: */ - if (unlikely(kprobe_page_fault(regs, X86_TRAP_PF))) - return; - -+ /* -+ * DTrace doesn't want to either. -+ */ -+ if (unlikely(dtrace_no_pf(regs))) -+ return; -+ - /* - * Reserved bits are never expected to be set on - * entries in the user portion of the page tables. -diff --git a/fs/exec.c b/fs/exec.c -index ca89e0e3ef10f19ee0ba7243c52fa7ff130900cf..4340b28030047552a40dfa962e08d994d3f33278 100644 ---- a/fs/exec.c -+++ b/fs/exec.c -@@ -64,6 +64,7 @@ - #include <linux/compat.h> - #include <linux/vmalloc.h> - #include <linux/io_uring.h> - #include <linux/random.h> -+#include <linux/dtrace_os.h> - - #include <linux/uaccess.h> - #include <asm/mmu_context.h> -@@ -1822,6 +1823,10 @@ static int bprm_execve(struct linux_binprm *bprm, - goto out; - - /* execve succeeded */ -+ -+ /* Update DTrace per-task data. */ -+ dtrace_task_exec(current); -+ - current->fs->in_exec = 0; - current->in_execve = 0; - rseq_execve(current); -diff --git a/include/asm-generic/qrwlock.h b/include/asm-generic/qrwlock.h -index 3aefde23dceab8b87d54f8c7e4493dc1a2b54eeb..addbb3c7d953ead4e88a98c609cebc4c6a245bc2 100644 ---- a/include/asm-generic/qrwlock.h -+++ b/include/asm-generic/qrwlock.h -@@ -30,6 +30,26 @@ - extern void queued_read_lock_slowpath(struct qrwlock *lock); - extern void queued_write_lock_slowpath(struct qrwlock *lock); - -+#ifdef CONFIG_DTRACE -+/** -+ * queued_peek_read_can_lock -- would read_trylock() be likely to succeed? -+ * @lock: Pointer to queue rwlock structure -+ */ -+static inline int queued_peek_read_can_lock(struct qrwlock *lock) -+{ -+ return !(atomic_read(&lock->cnts) & _QW_WMASK); -+} -+ -+/** -+ * queued_peek_write_can_lock -- would write_trylock() be likely to succeed? -+ * @lock: Pointer to queue rwlock structure -+ */ -+static inline int queued_peek_write_can_lock(struct qrwlock *lock) -+{ -+ return !atomic_read(&lock->cnts); -+} -+#endif /* CONFIG_DTRACE */ -+ - /** - * queued_read_trylock - try to acquire read lock of a queue rwlock - * @lock : Pointer to queue rwlock structure -@@ -120,6 +140,10 @@ static inline void queued_write_unlock(struct qrwlock *lock) - * Remapping rwlock architecture specific functions to the corresponding - * queue rwlock functions. - */ -+#ifdef CONFIG_DTRACE -+#define arch_peek_read_can_lock(l) queued_peek_read_can_lock(l) -+#define arch_peek_write_can_lock(l) queued_peek_write_can_lock(l) -+#endif /* CONFIG_DTRACE */ - #define arch_read_lock(l) queued_read_lock(l) - #define arch_write_lock(l) queued_write_lock(l) - #define arch_read_trylock(l) queued_read_trylock(l) -diff --git a/include/dtrace/dtrace_impl.h b/include/dtrace/dtrace_impl.h -new file mode 100644 -index 0000000000000000000000000000000000000000..2420103c765cefec965a7dac2b03e50ac8b37f02 ---- /dev/null -+++ b/include/dtrace/dtrace_impl.h -@@ -0,0 +1,1236 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Dynamic Tracing for Linux - Implementation -+ * -+ * Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_IMPL_H -+#define _LINUX_DTRACE_IMPL_H -+ -+#include <linux/cyclic.h> -+#include <linux/idr.h> -+ -+#include <linux/dtrace/universal.h> -+#include <linux/dtrace/dif.h> -+#include <linux/dtrace/difo_defines.h> -+#include <linux/dtrace/metadesc.h> -+#include <linux/dtrace/stability.h> -+#include <linux/dtrace/helpers.h> -+#include <dtrace/types.h> -+#include <dtrace/provider.h> -+#include <dtrace/dtrace_impl_defines.h> -+ -+struct dtrace_provider { -+ struct dtrace_pattr dtpv_attr; -+ struct dtrace_ppriv dtpv_priv; -+ struct dtrace_pops dtpv_pops; -+ char *dtpv_name; -+ void *dtpv_arg; -+ uint_t dtpv_defunct; -+ struct dtrace_provider *dtpv_next; -+}; -+ -+struct dtrace_predicate { -+ struct dtrace_difo *dtp_difo; -+ dtrace_cacheid_t dtp_cacheid; -+ int dtp_refcnt; -+}; -+ -+struct dtrace_statvar { -+ uint64_t dtsv_data; -+ size_t dtsv_size; -+ int dtsv_refcnt; -+ struct dtrace_difv dtsv_var; -+}; -+ -+struct dtrace_action { -+ dtrace_actkind_t dta_kind; -+ uint16_t dta_intuple; -+ uint32_t dta_refcnt; -+ struct dtrace_difo *dta_difo; -+ struct dtrace_recdesc dta_rec; -+ struct dtrace_action *dta_prev; -+ struct dtrace_action *dta_next; -+}; -+ -+struct dtrace_ecb; -+ -+struct dtrace_probe { -+ dtrace_id_t dtpr_id; -+ struct dtrace_ecb *dtpr_ecb; -+ struct dtrace_ecb *dtpr_ecb_last; -+ void *dtpr_arg; -+ dtrace_cacheid_t dtpr_predcache; -+ int dtpr_aframes; -+ struct dtrace_provider *dtpr_provider; -+ char *dtpr_mod; -+ char *dtpr_func; -+ char *dtpr_name; -+ struct dtrace_probe *dtpr_nextmod; -+ struct dtrace_probe *dtpr_prevmod; -+ struct dtrace_probe *dtpr_nextfunc; -+ struct dtrace_probe *dtpr_prevfunc; -+ struct dtrace_probe *dtpr_nextname; -+ struct dtrace_probe *dtpr_prevname; -+ dtrace_genid_t dtpr_gen; -+}; -+ -+struct dtrace_state; -+ -+struct dtrace_ecb { -+ dtrace_epid_t dte_epid; -+ uint32_t dte_alignment; -+ size_t dte_needed; -+ size_t dte_size; -+ struct dtrace_predicate *dte_predicate; -+ struct dtrace_action *dte_action; -+ struct dtrace_ecb *dte_next; -+ struct dtrace_state *dte_state; -+ uint32_t dte_cond; -+ struct dtrace_probe *dte_probe; -+ struct dtrace_action *dte_action_last; -+ uint64_t dte_uarg; -+}; -+ -+struct dtrace_key { -+ uint64_t dttk_value; -+ uint64_t dttk_size; -+}; -+ -+struct dtrace_tuple { -+ uint32_t dtt_nkeys; -+ uint32_t dtt_pad; -+ struct dtrace_key dtt_key[1]; -+}; -+ -+struct dtrace_dynvar { -+ uint64_t dtdv_hashval; -+ struct dtrace_dynvar *dtdv_next; -+ void *dtdv_data; -+ struct dtrace_tuple dtdv_tuple; -+}; -+ -+struct dtrace_dstate_percpu { -+ struct dtrace_dynvar *dtdsc_free; -+ struct dtrace_dynvar *dtdsc_dirty; -+ struct dtrace_dynvar *dtdsc_rinsing; -+ struct dtrace_dynvar *dtdsc_clean; -+ uint64_t dtdsc_drops; -+ uint64_t dtdsc_dirty_drops; -+ uint64_t dtdsc_rinsing_drops; -+#ifdef CONFIG_64BIT -+ uint64_t dtdsc_pad; -+#else -+ uint64_t dtdsc_pad[2]; -+#endif -+}; -+ -+struct dtrace_dynhash { -+ struct dtrace_dynvar *dtdh_chain; -+ uintptr_t dtdh_lock; -+#ifdef CONFIG_64BIT -+ uintptr_t dtdh_pad[6]; -+#else -+ uintptr_t dtdh_pad[14]; -+#endif -+}; -+ -+struct dtrace_dstate { -+ void *dtds_base; -+ size_t dtds_size; -+ size_t dtds_hashsize; -+ size_t dtds_chunksize; -+ struct dtrace_dynhash *dtds_hash; -+ enum dtrace_dstate_state dtds_state; -+ struct dtrace_dstate_percpu *dtds_percpu; -+}; -+ -+struct dtrace_vstate { -+ struct dtrace_state *dtvs_state; -+ struct dtrace_statvar **dtvs_globals; -+ int dtvs_nglobals; -+ struct dtrace_difv *dtvs_tlocals; -+ int dtvs_ntlocals; -+ struct dtrace_statvar **dtvs_locals; -+ int dtvs_nlocals; -+ struct dtrace_dstate dtvs_dynvars; -+}; -+ -+/* -+ * DTrace Machine State -+ * -+ * In the process of processing a fired probe, DTrace needs to track and/or -+ * cache some per-CPU state associated with that particular firing. This is -+ * state that is always discarded after the probe firing has completed, and -+ * much of it is not specific to any DTrace consumer, remaining valid across -+ * all ECBs. This state is tracked in the dtrace_mstate structure. -+ */ -+ -+struct dtrace_mstate { -+ uintptr_t dtms_scratch_base; -+ uintptr_t dtms_scratch_ptr; -+ size_t dtms_scratch_size; -+ uint32_t dtms_present; -+ uint64_t dtms_arg[7]; -+ dtrace_epid_t dtms_epid; -+ ktime_t dtms_timestamp; -+ int dtms_stackdepth; -+ int dtms_ustackdepth; -+ struct dtrace_probe *dtms_probe; -+ uintptr_t dtms_caller; -+ uint64_t dtms_ucaller; -+ int dtms_ipl; -+ int dtms_fltoffs; -+ uintptr_t dtms_strtok; -+ uint32_t dtms_access; -+ struct dtrace_difo *dtms_difo; -+}; -+ -+struct dtrace_buffer { -+ uint64_t dtb_offset; -+ uint64_t dtb_size; -+ uint32_t dtb_flags; -+ uint32_t dtb_drops; -+ caddr_t dtb_tomax; -+ caddr_t dtb_xamot; -+ uint32_t dtb_xamot_flags; -+ uint32_t dtb_xamot_drops; -+ uint64_t dtb_xamot_offset; -+ uint32_t dtb_errors; -+ uint32_t dtb_xamot_errors; -+#ifndef CONFIG_64BIT -+ uint64_t dtb_pad1; -+#endif -+}; -+ -+struct dtrace_speculation { -+ enum dtrace_speculation_state dtsp_state; -+ int dtsp_cleaning; -+ struct dtrace_buffer *dtsp_buffer; -+}; -+ -+struct dtrace_aggregation { -+ struct dtrace_action dtag_action; -+ dtrace_aggid_t dtag_id; -+ struct dtrace_ecb *dtag_ecb; -+ struct dtrace_action *dtag_first; -+ uint32_t dtag_base; -+ uint8_t dtag_hasarg; -+ uint64_t dtag_initial; -+ void (*dtag_aggregate)(uint64_t *, uint64_t, uint64_t); -+}; -+ -+struct dtrace_cred { -+ const struct cred *dcr_cred; -+ uint8_t dcr_destructive; -+ uint8_t dcr_visible; -+ uint16_t dcr_action; -+}; -+ -+struct dtrace_state { -+ dev_t dts_dev; -+ int dts_necbs; -+ struct dtrace_ecb **dts_ecbs; -+ dtrace_epid_t dts_epid; -+ size_t dts_needed; -+ struct dtrace_state *dts_anon; -+ enum dtrace_activity dts_activity; -+ struct dtrace_vstate dts_vstate; -+ struct dtrace_buffer *dts_buffer; -+ struct dtrace_buffer *dts_aggbuffer; -+ struct dtrace_speculation *dts_speculations; -+ int dts_nspeculations; -+ struct idr dts_agg_idr; -+ int dts_naggs; -+ uint64_t dts_errors; -+ uint32_t dts_speculations_busy; -+ uint32_t dts_speculations_unavail; -+ uint32_t dts_stkstroverflows; -+ uint32_t dts_dblerrors; -+ uint32_t dts_reserve; -+ cyclic_id_t dts_cleaner; -+ cyclic_id_t dts_deadman; -+ ktime_t dts_laststatus; -+ ktime_t dts_alive; -+ char dts_speculates; -+ char dts_destructive; -+ int dts_nformats; -+ char **dts_formats; -+ dtrace_optval_t dts_options[DTRACEOPT_MAX]; -+ struct dtrace_cred dts_cred; -+ size_t dts_nretained; -+}; -+ -+struct dtrace_enabling { -+ struct dtrace_ecbdesc **dten_desc; -+ int dten_ndesc; -+ int dten_maxdesc; -+ struct dtrace_vstate *dten_vstate; -+ dtrace_genid_t dten_probegen; -+ struct dtrace_ecbdesc *dten_current; -+ int dten_error; -+ int dten_primed; -+ struct dtrace_enabling *dten_prev; -+ struct dtrace_enabling *dten_next; -+}; -+ -+typedef int dtrace_probekey_f(const char *, const char *, int); -+ -+struct dtrace_probekey { -+ const char *dtpk_prov; -+ dtrace_probekey_f *dtpk_pmatch; -+ const char *dtpk_mod; -+ dtrace_probekey_f *dtpk_mmatch; -+ const char *dtpk_func; -+ dtrace_probekey_f *dtpk_fmatch; -+ const char *dtpk_name; -+ dtrace_probekey_f *dtpk_nmatch; -+ dtrace_id_t dtpk_id; -+}; -+ -+struct dtrace_hashbucket { -+ struct dtrace_hashbucket *dthb_next; -+ struct dtrace_probe *dthb_chain; -+ int dthb_len; -+}; -+ -+struct dtrace_hash { -+ struct dtrace_hashbucket **dth_tab; -+ int dth_size; -+ int dth_mask; -+ int dth_nbuckets; -+ uintptr_t dth_nextoffs; -+ uintptr_t dth_prevoffs; -+ uintptr_t dth_stroffs; -+}; -+ -+/* -+ * DTrace supports safe loads from probe context; if the address turns out to -+ * be invalid, a bit will be set by the kernel indicating that DTrace -+ * encountered a memory error, and DTrace will propagate the error to the user -+ * accordingly. However, there may exist some regions of memory in which an -+ * arbitrary load can change system state, and from which it is impossible to -+ * recover from such a load after it has been attempted. Examples of this may -+ * include memory in which programmable I/O registers are mapped (for which a -+ * read may have some implications for the device) or (in the specific case of -+ * UltraSPARC-I and -II) the virtual address hole. The platform is required -+ * to make DTrace aware of these toxic ranges; DTrace will then check that -+ * target addresses are not in a toxic range before attempting to issue a -+ * safe load. -+ */ -+struct dtrace_toxrange { -+ uintptr_t dtt_base; -+ uintptr_t dtt_limit; -+}; -+ -+/* -+ * DTrace Helper Implementation -+ * -+ * A description of the helper architecture may be found in <linux/dtrace.h>. -+ * Each process contains a pointer to its helpers in its dtrace_helpers -+ * member. This is a pointer to a dtrace_helpers structure, which contains an -+ * array of pointers to dtrace_helper structures, helper variable state (shared -+ * among a process's helpers) and a generation count. (The generation count is -+ * used to provide an identifier when a helper is added so that it may be -+ * subsequently removed.) The dtrace_helper structure is self-explanatory, -+ * containing pointers to the objects needed to execute the helper. Note that -+ * helpers are _duplicated_ across fork(2), and destroyed on exec(2). No more -+ * than dtrace_helpers_max are allowed per-process. -+ */ -+struct dtrace_helper_action { -+ int dtha_generation; /* helper action generation */ -+ int dtha_nactions; /* number of actions */ -+ struct dtrace_difo *dtha_predicate; /* helper action predicate */ -+ struct dtrace_difo **dtha_actions; /* array of actions */ -+ struct dtrace_helper_action *dtha_next; /* next helper action */ -+}; -+ -+struct dtrace_helper_provider { -+ int dthp_generation; /* helper provider generation */ -+ uint32_t dthp_ref; /* reference count */ -+ struct dof_helper dthp_prov; /* DOF w/ provider and probes */ -+}; -+ -+struct dtrace_helpers { -+ struct dtrace_helper_action **dthps_actions; /* helper actions array */ -+ struct dtrace_vstate dthps_vstate; /* helper action var. state */ -+ struct dtrace_helper_provider **dthps_provs; /* providers array */ -+ uint_t dthps_nprovs; /* count of providers */ -+ uint_t dthps_maxprovs; /* provider array size */ -+ int dthps_generation; /* current generation */ -+ pid_t dthps_pid; /* pid of associated proc */ -+ int dthps_deferred; /* helper in deferred list */ -+ struct dtrace_helpers *dthps_next; /* next pointer */ -+ struct dtrace_helpers *dthps_prev; /* prev pointer */ -+}; -+ -+/* -+ * DTrace Helper Action Tracing -+ * -+ * Debugging helper actions can be arduous. To ease the development and -+ * debugging of helpers, DTrace contains a tracing-framework-within-a-tracing- -+ * framework: helper tracing. If dtrace_helptrace_enabled is non-zero (which -+ * it is by default on DEBUG kernels), all helper activity will be traced to a -+ * global, in-kernel ring buffer. Each entry includes a pointer to the specific -+ * helper, the location within the helper, and a trace of all local variables. -+ * The ring buffer may be displayed in a human-readable format with the -+ * ::dtrace_helptrace mdb(1) dcmd. -+ */ -+struct dtrace_helptrace { -+ struct dtrace_helper_action *dtht_helper; /* helper action */ -+ int dtht_where; /* where in helper action */ -+ int dtht_nlocals; /* number of locals */ -+ int dtht_fault; /* type of fault (if any) */ -+ int dtht_fltoffs; /* DIF offset */ -+ uint64_t dtht_illval; /* faulting value */ -+ uint64_t dtht_locals[1]; /* local variables */ -+}; -+ -+extern struct mutex dtrace_lock; -+extern struct mutex dtrace_provider_lock; -+extern struct mutex dtrace_meta_lock; -+ -+extern dtrace_genid_t dtrace_probegen; -+extern struct kmem_cache *dtrace_probe_cachep; -+ -+extern struct dtrace_pops dtrace_provider_ops; -+ -+extern int dtrace_opens; -+extern int dtrace_err_verbose; -+ -+extern struct dtrace_toxrange *dtrace_toxrange; -+extern int dtrace_toxranges; -+ -+extern void dtrace_nullop(void); -+extern int dtrace_enable_nullop(void); -+extern int dtrace_istoxic(uintptr_t, size_t); -+ -+/* -+ * DTrace Probe Context Functions -+ */ -+ -+extern void dtrace_panic(const char *, ...); -+extern int dtrace_assfail(const char *, const char *, int); -+extern void dtrace_aggregate_min(uint64_t *, uint64_t, uint64_t); -+extern void dtrace_aggregate_max(uint64_t *, uint64_t, uint64_t); -+extern void dtrace_aggregate_quantize(uint64_t *, uint64_t, uint64_t); -+extern void dtrace_aggregate_lquantize(uint64_t *, uint64_t, uint64_t); -+extern void dtrace_aggregate_llquantize(uint64_t *, uint64_t, uint64_t); -+extern void dtrace_aggregate_avg(uint64_t *, uint64_t, uint64_t); -+extern void dtrace_aggregate_stddev(uint64_t *, uint64_t, uint64_t); -+extern void dtrace_aggregate_count(uint64_t *, uint64_t, uint64_t); -+extern void dtrace_aggregate_sum(uint64_t *, uint64_t, uint64_t); -+extern void dtrace_aggregate(struct dtrace_aggregation *, -+ struct dtrace_buffer *, -+ intptr_t, struct dtrace_buffer *, uint64_t, -+ uint64_t); -+ -+/* -+ * DTrace Probe Hashing Functions -+ */ -+ -+extern struct dtrace_hash *dtrace_hash_create(uintptr_t, uintptr_t, uintptr_t); -+extern void dtrace_hash_destroy(struct dtrace_hash *); -+extern int dtrace_hash_add(struct dtrace_hash *, struct dtrace_probe *); -+extern struct dtrace_probe *dtrace_hash_lookup(struct dtrace_hash *, -+ struct dtrace_probe *); -+extern int dtrace_hash_collisions(struct dtrace_hash *, struct dtrace_probe *); -+extern void dtrace_hash_remove(struct dtrace_hash *, struct dtrace_probe *); -+ -+/* -+ * DTrace Speculation Functions -+ */ -+extern int dtrace_speculation(struct dtrace_state *); -+extern void dtrace_speculation_commit(struct dtrace_state *, processorid_t, -+ dtrace_specid_t); -+extern void dtrace_speculation_discard(struct dtrace_state *, processorid_t, -+ dtrace_specid_t); -+extern void dtrace_speculation_clean(struct dtrace_state *); -+extern struct dtrace_buffer *dtrace_speculation_buffer(struct dtrace_state *, -+ processorid_t, -+ dtrace_specid_t); -+ -+/* -+ * DTrace Non-Probe Context Utility Functions -+ */ -+ -+/* -+ * DTrace Matching Functions -+ */ -+extern struct dtrace_hash *dtrace_bymod; -+extern struct dtrace_hash *dtrace_byfunc; -+extern struct dtrace_hash *dtrace_byname; -+ -+extern int dtrace_match_priv(const struct dtrace_probe *, uint32_t, kuid_t); -+extern int dtrace_match_probe(const struct dtrace_probe *, -+ const struct dtrace_probekey *, uint32_t, -+ kuid_t); -+extern int dtrace_match_glob(const char *, const char *, int); -+extern int dtrace_match_string(const char *, const char *, int); -+extern int dtrace_match_nul(const char *, const char *, int); -+extern int dtrace_match_nonzero(const char *, const char *, int); -+extern int dtrace_match(const struct dtrace_probekey *, uint32_t, kuid_t, -+ int (*matched)(struct dtrace_probe *, void *), void *); -+extern void dtrace_probekey(const struct dtrace_probedesc *, -+ struct dtrace_probekey *); -+ -+/* -+ * DTrace Provider-to-Framework API Functions -+ */ -+ -+extern struct dtrace_provider *dtrace_provider; -+extern struct dtrace_meta *dtrace_meta_pid; -+extern struct dtrace_helpers *dtrace_deferred_pid; -+ -+/* -+ * DTrace Privilege Check Functions -+ */ -+extern int dtrace_priv_proc_destructive(struct dtrace_state *); -+extern int dtrace_priv_proc_control(struct dtrace_state *); -+extern int dtrace_priv_proc(struct dtrace_state *); -+extern int dtrace_priv_kernel(struct dtrace_state *); -+ -+/* -+ * DTrace Probe Management Functions -+ */ -+ -+extern int dtrace_probe_enable(const struct dtrace_probedesc *, -+ struct dtrace_enabling *); -+extern void dtrace_probe_description(const struct dtrace_probe *, -+ struct dtrace_probedesc *); -+extern void dtrace_probe_provide(struct dtrace_probedesc *, -+ struct dtrace_provider *); -+extern int dtrace_probe_init(void); -+extern void dtrace_probe_exit(void); -+extern void dtrace_probe_remove_id(dtrace_id_t); -+extern struct dtrace_probe *dtrace_probe_lookup_id(dtrace_id_t); -+extern struct dtrace_probe *dtrace_probe_get_next(dtrace_id_t *); -+extern int dtrace_probe_for_each(int (*)(int, void *, void *), void *); -+ -+/* -+ * DTrace Kernel Hooks -+ */ -+extern void (*dtrace_modload)(struct module *); -+extern void (*dtrace_modunload)(struct module *); -+ -+extern uint8_t dtrace_load8(uintptr_t); -+extern uint16_t dtrace_load16(uintptr_t); -+extern uint32_t dtrace_load32(uintptr_t); -+extern uint64_t dtrace_load64(uintptr_t); -+#ifdef CONFIG_64BIT -+#define dtrace_loadptr dtrace_load64 -+#else -+#define dtrace_loadptr dtrace_load32 -+#endif -+ -+ -+extern void dtrace_bzero(void *, size_t); -+ -+extern int dtrace_vcanload(void *, struct dtrace_diftype *, -+ struct dtrace_mstate *, -+ struct dtrace_vstate *); -+extern int dtrace_canload(uintptr_t, size_t, struct dtrace_mstate *, -+ struct dtrace_vstate *); -+ -+extern int dtrace_difo_validate(struct dtrace_difo *, struct dtrace_vstate *, -+ uint_t, const struct cred *); -+extern int dtrace_difo_validate_helper(struct dtrace_difo *); -+extern int dtrace_difo_cacheable(struct dtrace_difo *); -+extern void dtrace_difo_hold(struct dtrace_difo *); -+extern void dtrace_difo_init(struct dtrace_difo *, struct dtrace_vstate *); -+extern struct dtrace_difo *dtrace_difo_duplicate(struct dtrace_difo *, -+ struct dtrace_vstate *); -+extern void dtrace_difo_release(struct dtrace_difo *, struct dtrace_vstate *); -+ -+extern uint64_t dtrace_vtime_references; -+ -+extern uint64_t dtrace_dif_emulate(struct dtrace_difo *, -+ struct dtrace_mstate *, -+ struct dtrace_vstate *, -+ struct dtrace_state *); -+ -+/* -+ * DTrace Format Functions -+ */ -+extern uint16_t dtrace_format_add(struct dtrace_state *, char *); -+extern void dtrace_format_remove(struct dtrace_state *, uint16_t); -+extern void dtrace_format_destroy(struct dtrace_state *); -+ -+/* -+ * DTrace Predicate Functions -+ */ -+extern struct dtrace_predicate *dtrace_predicate_create(struct dtrace_difo *); -+extern void dtrace_predicate_hold(struct dtrace_predicate *); -+extern void dtrace_predicate_release(struct dtrace_predicate *, -+ struct dtrace_vstate *); -+ -+/* -+ * DTrace Action Description Functions -+ */ -+extern struct dtrace_actdesc *dtrace_actdesc_create(dtrace_actkind_t, uint32_t, -+ uint64_t, uint64_t); -+extern void dtrace_actdesc_hold(struct dtrace_actdesc *); -+extern void dtrace_actdesc_release(struct dtrace_actdesc *, -+ struct dtrace_vstate *); -+ -+/* -+ * DTrace Helper Functions -+ */ -+extern void dtrace_helpers_destroy(struct task_struct *); -+extern void dtrace_helpers_duplicate(struct task_struct *, -+ struct task_struct *); -+extern uint64_t dtrace_helper(int, struct dtrace_mstate *, -+ struct dtrace_state *, -+ uint64_t, uint64_t); -+ -+/* -+ * DTrace ECB Functions -+ */ -+extern struct dtrace_ecb *dtrace_ecb_create_cache; -+ -+extern int dtrace_ecb_create_enable(struct dtrace_probe *, void *); -+extern void dtrace_ecb_disable(struct dtrace_ecb *); -+extern void dtrace_ecb_destroy(struct dtrace_ecb *); -+extern void dtrace_ecb_resize(struct dtrace_ecb *); -+extern int dtrace_ecb_enable(struct dtrace_ecb *); -+extern struct dtrace_ecb *dtrace_epid2ecb(struct dtrace_state *, -+ dtrace_epid_t); -+extern struct dtrace_aggregation *dtrace_aggid2agg(struct dtrace_state *, -+ dtrace_aggid_t); -+ -+/* -+ * DTrace Buffer Functions -+ * -+ * DTrace Buffers -+ * -+ * Principal buffers, aggregation buffers, and speculative buffers are all -+ * managed with the dtrace_buffer structure. By default, this structure -+ * includes twin data buffers -- dtb_tomax and dtb_xamot -- that serve as the -+ * active and passive buffers, respectively. For speculative buffers, -+ * dtb_xamot will be NULL; for "ring" and "fill" buffers, dtb_xamot will point -+ * to a scratch buffer. For all buffer types, the dtrace_buffer structure is -+ * always allocated on a per-CPU basis; a single dtrace_buffer structure is -+ * never shared among CPUs. (That is, there is never true sharing of the -+ * dtrace_buffer structure; to prevent false sharing of the structure, it must -+ * always be aligned to the coherence granularity -- generally 64 bytes.) -+ * -+ * One of the critical design decisions of DTrace is that a given ECB always -+ * stores the same quantity and type of data. This is done to assure that the -+ * only metadata required for an ECB's traced data is the EPID. That is, from -+ * the EPID, the consumer can determine the data layout. (The data buffer -+ * layout is shown schematically below.) By assuring that one can determine -+ * data layout from the EPID, the metadata stream can be separated from the -+ * data stream -- simplifying the data stream enormously. -+ * -+ * base of data buffer ---> +------+--------------------+------+ -+ * | EPID | data | EPID | -+ * +------+--------+------+----+------+ -+ * | data | EPID | data | -+ * +---------------+------+-----------+ -+ * | data, cont. | -+ * +------+--------------------+------+ -+ * | EPID | data | | -+ * +------+--------------------+ | -+ * | || | -+ * | || | -+ * | \/ | -+ * : : -+ * . . -+ * . . -+ * . . -+ * : : -+ * | | -+ * limit of data buffer ---> +----------------------------------+ -+ * -+ * When evaluating an ECB, dtrace_probe() determines if the ECB's needs of the -+ * principal buffer (both scratch and payload) exceed the available space. If -+ * the ECB's needs exceed available space (and if the principal buffer policy -+ * is the default "switch" policy), the ECB is dropped, the buffer's drop count -+ * is incremented, and processing advances to the next ECB. If the ECB's needs -+ * can be met with the available space, the ECB is processed, but the offset in -+ * the principal buffer is only advanced if the ECB completes processing -+ * without error. -+ * -+ * When a buffer is to be switched (either because the buffer is the principal -+ * buffer with a "switch" policy or because it is an aggregation buffer), a -+ * cross call is issued to the CPU associated with the buffer. In the cross -+ * call context, interrupts are disabled, and the active and the inactive -+ * buffers are atomically switched. This involves switching the data pointers, -+ * copying the various state fields (offset, drops, errors, etc.) into their -+ * inactive equivalents, and clearing the state fields. Because interrupts are -+ * disabled during this procedure, the switch is guaranteed to appear atomic to -+ * dtrace_probe(). -+ * -+ * DTrace Ring Buffering -+ * -+ * To process a ring buffer correctly, one must know the oldest valid record. -+ * Processing starts at the oldest record in the buffer and continues until -+ * the end of the buffer is reached. Processing then resumes starting with -+ * the record stored at offset 0 in the buffer, and continues until the -+ * youngest record is processed. If trace records are of a fixed-length, -+ * determining the oldest record is trivial: -+ * -+ * - If the ring buffer has not wrapped, the oldest record is the record -+ * stored at offset 0. -+ * -+ * - If the ring buffer has wrapped, the oldest record is the record stored -+ * at the current offset. -+ * -+ * With variable length records, however, just knowing the current offset -+ * doesn't suffice for determining the oldest valid record: assuming that one -+ * allows for arbitrary data, one has no way of searching forward from the -+ * current offset to find the oldest valid record. (That is, one has no way -+ * of separating data from metadata.) It would be possible to simply refuse to -+ * process any data in the ring buffer between the current offset and the -+ * limit, but this leaves (potentially) an enormous amount of otherwise valid -+ * data unprocessed. -+ * -+ * To effect ring buffering, we track two offsets in the buffer: the current -+ * offset and the _wrapped_ offset. If a request is made to reserve some -+ * amount of data, and the buffer has wrapped, the wrapped offset is -+ * incremented until the wrapped offset minus the current offset is greater -+ * than or equal to the reserve request. This is done by repeatedly looking -+ * up the ECB corresponding to the EPID at the current wrapped offset, and -+ * incrementing the wrapped offset by the size of the data payload -+ * corresponding to that ECB. If this offset is greater than or equal to the -+ * limit of the data buffer, the wrapped offset is set to 0. Thus, the -+ * current offset effectively "chases" the wrapped offset around the buffer. -+ * Schematically: -+ * -+ * base of data buffer ---> +------+--------------------+------+ -+ * | EPID | data | EPID | -+ * +------+--------+------+----+------+ -+ * | data | EPID | data | -+ * +---------------+------+-----------+ -+ * | data, cont. | -+ * +------+---------------------------+ -+ * | EPID | data | -+ * current offset ---> +------+---------------------------+ -+ * | invalid data | -+ * wrapped offset ---> +------+--------------------+------+ -+ * | EPID | data | EPID | -+ * +------+--------+------+----+------+ -+ * | data | EPID | data | -+ * +---------------+------+-----------+ -+ * : : -+ * . . -+ * . ... valid data ... . -+ * . . -+ * : : -+ * +------+-------------+------+------+ -+ * | EPID | data | EPID | data | -+ * +------+------------++------+------+ -+ * | data, cont. | leftover | -+ * limit of data buffer ---> +-------------------+--------------+ -+ * -+ * If the amount of requested buffer space exceeds the amount of space -+ * available between the current offset and the end of the buffer: -+ * -+ * (1) all words in the data buffer between the current offset and the limit -+ * of the data buffer (marked "leftover", above) are set to -+ * DTRACE_EPIDNONE -+ * -+ * (2) the wrapped offset is set to zero -+ * -+ * (3) the iteration process described above occurs until the wrapped offset -+ * is greater than the amount of desired space. -+ * -+ * The wrapped offset is implemented by (re-)using the inactive offset. -+ * In a "switch" buffer policy, the inactive offset stores the offset in -+ * the inactive buffer; in a "ring" buffer policy, it stores the wrapped -+ * offset. -+ * -+ * DTrace Scratch Buffering -+ * -+ * Some ECBs may wish to allocate dynamically-sized temporary scratch memory. -+ * To accommodate such requests easily, scratch memory may be allocated in -+ * the buffer beyond the current offset plus the needed memory of the current -+ * ECB. If there isn't sufficient room in the buffer for the requested amount -+ * of scratch space, the allocation fails and an error is generated. Scratch -+ * memory is tracked in the dtrace_mstate_t and is automatically freed when -+ * the ECB ceases processing. Note that ring buffers cannot allocate their -+ * scratch from the principal buffer -- lest they needlessly overwrite older, -+ * valid data. Ring buffers therefore have their own dedicated scratch buffer -+ * from which scratch is allocated. -+ */ -+ -+extern void dtrace_buffer_switch(struct dtrace_buffer *); -+extern void dtrace_buffer_activate(struct dtrace_state *); -+extern int dtrace_buffer_alloc(struct dtrace_buffer *, size_t, int, -+ processorid_t); -+extern void dtrace_buffer_drop(struct dtrace_buffer *); -+extern intptr_t dtrace_buffer_reserve(struct dtrace_buffer *, size_t, size_t, -+ struct dtrace_state *, -+ struct dtrace_mstate *); -+extern void dtrace_buffer_polish(struct dtrace_buffer *); -+extern void dtrace_buffer_free(struct dtrace_buffer *); -+ -+/* -+ * DTrace framework/probe data synchronization -+ * ------------------------------------------- -+ * -+ * The dtrace_sync() facility is used to synchronize global DTrace framework -+ * data with DTrace probe context. The framework updates data and then calls -+ * dtrace_sync(). dtrace_sync() loops until it observes all CPUs have been out -+ * of probe context at least once. This ensures all consumers are using the -+ * updated data. -+ * -+ * DTrace probes have several requirements. First DTrace probe context cannot -+ * block. DTrace probes execute with interrupts disabled. Locks cannot be -+ * acquired in DTrace probe context. A second requirement is that DTrace -+ * probes need to be as high performance as possible to minimize the effect of -+ * enabled probes. -+ * -+ * DTrace framework data changes have their own requirements. DTrace data -+ * changes/syncs are extremely infrequent compared to DTrace probe firings. -+ * Probes can be in commonly executed code. A good trade-off is to favor -+ * DTrace probe context performance over DTrace sync performance. -+ * -+ * To meet the above requirements, the DTrace data synchronization algorithm -+ * is lock-less. The DTrace probe path is wait-free. The DTrace probe path -+ * is memory-barrier-free in the common case to minimize probe effect. -+ * dtrace_probe has been made membar free in the common case by adding a read -+ * in dtrace_probe and adding an additional write and membar to dtrace_sync(). -+ * -+ * A simple algorithm is to have dtrace_probe set a flag for its CPU when -+ * entering DTrace probe context and clear the flag when it exits DTrace probe -+ * context. A producer of DTrace framework data checks the flag to detect and -+ * synchronize with probe context. Unfortunately memory ordering issues -+ * complicate the implementation. Memory barriers are required in probe -+ * context for this simple approach to work. -+ * -+ * A simple implementation to sync with one CPU that works with any memory -+ * ordering model is: -+ * -+ * DTrace probe: -+ * 1. CPU->in_probe_context = B_TRUE; -+ * 2. dtrace_membar_enter()// membar #StoreLoad|#StoreStore -+ * 3. access framework shared data// critical section -+ * 4. dtrace_membar_exit()// membar #LoadStore|#StoreStore -+ * 5. CPU->in_probe_context = B_FALSE; -+ * -+ * DTrace framework dtrace_sync: -+ * 0. update framework shared data -+ * 1. dtrace_membar_enter()// membar #StoreLoad|#StoreStore -+ * 2. while (CPU->in_probe_context == B_TRUE) -+ * 3. spin -+ * 4. dtrace_membar_exit()// membar #LoadStore|#StoreStore -+ * 5. produce shared dtrace data -+ * -+ * A note on memory ordering -+ * ------------------------- -+ * -+ * dtrace_membar_enter() guarantees later loads cannot complete before earlier -+ * stores, and it guarantees later stores cannot complete before earlier stores. -+ * dtrace_membar_enter() is, in SPARC parlance, a membar #StoreLoad|#StoreStore. -+ * -+ * dtrace_membar_exit() guarantees later stores cannot complete before earlier -+ * loads, and it guarantees later stores cannot complete before earlier stores. -+ * dtrace_membar_exit() is, in SPARC parlance, a membar #LoadStore|#StoreStore. -+ * -+ * Please see the SPARC and Intel processor guides on memory ordering. -+ * All sun4v and Fujitsu processors are TSO (Total Store Order). Modern -+ * supported Intel and AMD processors have similar load and store ordering -+ * to SPARC. All processors currently supported by Solaris have these memory -+ * ordering properties: -+ * 1) Loads are ordered with respect to earlier loads. -+ * 2) Stores are ordered with respect to earlier stores. -+ * 3a) SPARC Atomic load-store behaves as if it were followed by a -+ * MEMBAR #LoadLoad, #LoadStore, and #StoreStore. -+ * 3b) X86 Atomic operations serialize load and store. -+ * 4) Stores cannot bypass earlier loads. -+ * -+ * The above implementation details allow the membars to be simplified thus: -+ * A) dtrace_membar_enter() can be reduced to "membar #StoreLoad" on sparc. -+ * See property number 4 above. -+ * Since dtrace_membar_enter() is an atomic operation on x86, it cannot be -+ * reduced further. -+ * B) dtrace_membar_exit() becomes a NOP on both SPARC and x86. -+ * See properties 2 and 4. -+ * -+ * -+ * Elimination of membar #StoreLoad from dtrace probe context -+ * ---------------------------------------------------------- -+ * -+ * Furthermore it is possible to eliminate all memory barriers from the common -+ * dtrace_probe() entry case. The only membar needed in dtrace_probe is there -+ * to prevent Loads of global DTrace framework data from passing the Store to -+ * the "in_probe_context" flag (i.e. the dtrace_membar_enter()). -+ * A Load at the beginning of the algorithm is also ordered with these later -+ * Loads and Stores: the membar #StoreLoad can be replaced with a early Load of -+ * a "sync_request" flag and a conditional branch on the flag value. -+ * -+ * dtrace_sync() first Stores to the "sync_request" flag, and dtrace_probe() -+ * starts by Loading the flag. This Load in dtrace_probe() of "sync_request" -+ * is ordered with its later Store to the "in_probe_context" flag and -+ * dtrace_probe's later Loads of DTrace framework data. dtrace_probe() only -+ * needs a membar #StoreLoad iff the "sync_request" flag is set. -+ * -+ * Optimized Synchronization Algorithm -+ * ----------------------------------- -+ * -+ * DTrace probe: -+ * + 1a. request_flag = CPU->sync_request // Load -+ * 1b. CPU->in_probe_context = B_TRUE // Store -+ * + 2. if request_flag > 0 -+ * dtrace_membar_enter() // membar #StoreLoad -+ * 3. access framework shared data // critical section -+ * - -+ * 5. CPU->in_probe_context = B_FALSE // Store -+ * -+ * DTrace framework dtrace_sync: -+ * + 1a. atomically add 1 to CPU->sync_request // Store and -+ * 1b. dtrace_membar_enter() // membar #StoreLoad -+ * 2. while (CPU->in_probe_context == B_TRUE) // Load -+ * 3. spin -+ * + 4a. atomically subtract 1 from CPU->sync_request // Load + Store -+ * - -+ * 5. produce shared dtrace data -+ * -+ * This algorithm has been proven correct by analysis of all interleaving -+ * scenarios of the above operations with the hardware memory ordering -+ * described above. -+ * -+ * The Load and store of the flag pair is very inexpensive. The cacheline with -+ * the flag pair is never accessed by a different CPU except by dtrace_sync. -+ * dtrace_sync is very uncommon compared to typical probe firings. The removal -+ * of membars from DTrace probe context at the expense of a Load and Store and -+ * a conditional branch is a good performance win. -+ * -+ * As implemented there is one pair of flags per CPU. The flags are in one -+ * cacheline; they could be split into two cachelines if dtrace_sync was more -+ * common. dtrace_sync loops over all NCPU sets of flags. dtrace_sync lazily -+ * only does one dtrace_membar_enter() (step 1b) after setting all NCPU -+ * sync_request flags. -+ * -+ * Sample aliasing could cause dtrace_sync() to always sample a CPU's -+ * in_probe_context flag when the CPU is in probe context even if the CPU -+ * left and returned to probe context one or more times since the last sample. -+ * cpuc_in_probe_ctxt is implemented as an even/odd counter instead of a -+ * boolean flag. cpuc_in_probe_ctxt is odd when in probe context and even -+ * when not in probe context. Probe context increments cpuc_in_probe_ctxt when -+ * entering and exiting. dtrace_probe() handles re-entry by not increment the -+ * counter for re-enterant entry and exit. -+ */ -+ -+/* -+ * dtrace_membar_exit() is a NOP on current SPARC and X86 hardware. -+ * It is defined as an inline asm statement to prevent the C optimizer from -+ * moving C statements around the membar. -+ */ -+#define dtrace_membar_exit() \ -+ __asm__ __volatile__("" ::: "memory") -+ -+/* -+ * dtrace_membar_enter() does not need an explicit membar #StoreStore because -+ * modern SPARC hardware is TSO: stores are ordered with other stores. -+ */ -+#define dtrace_membar_enter() \ -+ mb() -+ -+#define dtrace_safe_smt_pause() \ -+ cpu_relax() -+ -+/* -+ * Used by dtrace_probe() to flag entry to the the critical section. -+ * dtrace_probe() context may be consuming DTrace framework data. -+ * -+ * cpuc_in_probe_ctxt is odd when in probe context and even when not in -+ * probe context. The flag must not be incremented when re-entering from -+ * probe context. -+ */ -+#define DTRACE_SYNC_ENTER_CRITICAL(cookie, re_entry) \ -+{ \ -+ uint64_t requests; \ -+ uint64_t count; \ -+ \ -+ preempt_disable(); \ -+ local_irq_save(cookie); \ -+ \ -+ requests = atomic64_read(&this_cpu_core->cpuc_sync_requests); \ -+ \ -+ /* Increment flag iff it is even */ \ -+ count = atomic64_read(&this_cpu_core->cpuc_in_probe_ctx); \ -+ re_entry = count & 0x1; \ -+ atomic64_set(&this_cpu_core->cpuc_in_probe_ctx, count | 0x1); \ -+ ASSERT(DTRACE_SYNC_IN_CRITICAL(smp_processor_id())); \ -+ \ -+ /* \ -+ * Later Loads are ordered with respect to the Load of \ -+ * cpuc_sync_requests. The Load is also guaranteed to complete \ -+ * before the store to cpuc_in_probe_ctxt. Thus a member_enter \ -+ * is only needed when requests is not 0. This is very \ -+ * uncommon. \ -+ */ \ -+ if (requests > 0) { \ -+ dtrace_membar_enter(); \ -+ } \ -+} -+ -+/* -+ * Used by dtrace_probe() to flag exit from the critical section. -+ * dtrace_probe context is no longer using DTrace framework data. -+ */ -+#define DTRACE_SYNC_EXIT_CRITICAL(cookie, re_entry) \ -+{ \ -+ dtrace_membar_exit(); \ -+ ASSERT((re_entry | 0x1) == 0x1); \ -+ \ -+ /* \ -+ * flag must not be incremented when returning to probe context.\ -+ */ \ -+ atomic64_add(~re_entry & 0x1, &this_cpu_core->cpuc_in_probe_ctx); \ -+ ASSERT(re_entry == \ -+ (atomic64_read(&this_cpu_core->cpuc_in_probe_ctx) & 0x1)); \ -+ local_irq_restore(cookie); \ -+ preempt_enable(); \ -+} -+ -+/* -+ * Used by dtrace_sync to inform dtrace_probe it needs to synchronize with -+ * dtrace_sync. dtrace_probe consumes the cpuc_sync_requests flag to determine -+ * if it needs a membar_enter. Not called from probe context. -+ * -+ * cpuc_sync_requests must be updated atomically by dtrace_sync because there -+ * may be multiple dtrace_sync operations executing at the same time. -+ * cpuc_sync_requests is a simple count of the number of concurrent -+ * dtrace_sync requests. -+ */ -+#define DTRACE_SYNC_START(cpuid) \ -+{ \ -+ atomic64_add(1, &(per_cpu_core(cpuid))->cpuc_sync_requests); \ -+ ASSERT(atomic64_read(&per_cpu_core(cpuid)->cpuc_sync_requests) > 0); \ -+} -+ -+/* -+ * Used by dtrace_sync to flag dtrace_probe that it no longer needs to -+ * synchronize with dtrace_sync. Not called from probe context. -+ */ -+#define DTRACE_SYNC_END(cpuid) \ -+{ \ -+ atomic64_add(-1, &(per_cpu_core(cpuid))->cpuc_sync_requests); \ -+ ASSERT(atomic64_read(&per_cpu_core(cpuid)->cpuc_sync_requests) >= 0); \ -+} -+ -+/* -+ * The next two macros are used by dtrace_sync to check if the target CPU is in -+ * DTrace probe context. cpuc_in_probe_ctxt is a monotonically increasing -+ * count which dtrace_probe() increments when entering and exiting probe -+ * context. The flag is odd when in probe context, and even when not in probe -+ * context. -+ */ -+#define DTRACE_SYNC_IN_CRITICAL(cpuid) \ -+ (atomic64_read(&per_cpu_core(cpuid)->cpuc_in_probe_ctx) & 0x1) -+ -+/* -+ * Used to check if the target CPU left and then entered probe context again. -+ */ -+#define DTRACE_SYNC_CRITICAL_COUNT(cpuid) \ -+ (atomic64_read(&per_cpu_core(cpuid)->cpuc_in_probe_ctx)) -+ -+/* -+ * The next three macros are bitmap operations used by dtrace_sync to keep track -+ * of which CPUs it still needs to synchronize with. -+ */ -+#define DTRACE_SYNC_OUTSTANDING(cpuid, bitmap) \ -+ (cpumask_test_cpu(cpuid, bitmap) == 1) -+ -+#define DTRACE_SYNC_NEEDED(cpuid, bitmap) \ -+ cpumask_set_cpu(cpuid, bitmap) -+ -+#define DTRACE_SYNC_DONE(cpuid, bitmap) \ -+ cpumask_clear_cpu(cpuid, bitmap) -+ -+extern uint64_t dtrace_sync_sample_count; -+extern void dtrace_sync(void); -+ -+/* -+ * DTrace Enabling Functions -+ */ -+extern struct dtrace_enabling *dtrace_retained; -+extern dtrace_genid_t dtrace_retained_gen; -+ -+extern struct dtrace_enabling *dtrace_enabling_create(struct dtrace_vstate *); -+extern void dtrace_enabling_add(struct dtrace_enabling *, -+ struct dtrace_ecbdesc *); -+extern void dtrace_enabling_dump(struct dtrace_enabling *); -+extern void dtrace_enabling_destroy(struct dtrace_enabling *); -+extern int dtrace_enabling_retain(struct dtrace_enabling *); -+extern int dtrace_enabling_replicate(struct dtrace_state *, -+ struct dtrace_probedesc *, -+ struct dtrace_probedesc *); -+extern void dtrace_enabling_retract(struct dtrace_state *); -+extern int dtrace_enabling_match(struct dtrace_enabling *, int *); -+extern void dtrace_enabling_matchall(void); -+extern void dtrace_enabling_prime(struct dtrace_state *); -+extern void dtrace_enabling_provide(struct dtrace_provider *); -+ -+/* -+ * DOF functions -+ */ -+extern void dtrace_dof_error(struct dof_hdr *, const char *); -+extern struct dof_hdr *dtrace_dof_create(struct dtrace_state *); -+extern struct dof_hdr *dtrace_dof_copyin(void __user *, int *); -+extern struct dof_hdr *dtrace_dof_property(const char *); -+extern void dtrace_dof_destroy(struct dof_hdr *); -+extern int dtrace_dof_slurp(struct dof_hdr *, struct dtrace_vstate *, -+ const struct cred *, struct dtrace_enabling **, -+ uint64_t, int); -+extern int dtrace_dof_options(struct dof_hdr *, struct dtrace_state *); -+extern void dtrace_helper_provide(struct dof_helper *dhp, pid_t pid); -+extern int dtrace_helper_slurp(struct dof_hdr *, struct dof_helper *); -+extern int dtrace_helper_destroygen(int); -+ -+/* -+ * DTrace Anonymous Enabling Functions -+ */ -+struct dtrace_anon { -+ struct dtrace_state *dta_state; -+ struct dtrace_enabling *dta_enabling; -+ processorid_t dta_beganon; -+}; -+ -+extern struct dtrace_anon dtrace_anon; -+ -+extern struct dtrace_state *dtrace_anon_grab(void); -+extern void dtrace_anon_property(void); -+ -+/* -+ * DTrace Consumer State Functions -+ */ -+extern struct kmem_cache *dtrace_state_cachep; -+extern size_t dtrace_strsize_default; -+ -+extern ktime_t dtrace_deadman_timeout; -+extern int dtrace_destructive_disallow; -+ -+extern dtrace_id_t dtrace_probeid_begin; -+extern dtrace_id_t dtrace_probeid_end; -+extern dtrace_id_t dtrace_probeid_error; -+ -+extern struct dtrace_dynvar dtrace_dynhash_sink; -+ -+extern struct user_namespace *init_user_namespace; -+ -+extern int dtrace_dstate_init(struct dtrace_dstate *, size_t); -+extern void dtrace_dstate_fini(struct dtrace_dstate *); -+extern void dtrace_vstate_fini(struct dtrace_vstate *); -+extern struct dtrace_state *dtrace_state_create(struct file *); -+extern int dtrace_state_go(struct dtrace_state *, processorid_t *); -+extern int dtrace_state_stop(struct dtrace_state *, processorid_t *); -+extern int dtrace_state_option(struct dtrace_state *, dtrace_optid_t, -+ dtrace_optval_t); -+extern void dtrace_state_destroy(struct dtrace_state *); -+ -+/* -+ * DTrace Utility Functions -+ */ -+extern int dtrace_isglob(const char *); -+extern int dtrace_gmatch(const char *, const char *); -+extern void *dtrace_vzalloc(unsigned long); -+extern void *dtrace_vzalloc_try(unsigned long); -+extern char *dtrace_strdup(const char *); -+extern int dtrace_strncmp(char *, char *, size_t); -+extern size_t dtrace_strlen(const char *, size_t); -+extern int dtrace_badattr(const struct dtrace_attribute *); -+extern int dtrace_badname(const char *); -+extern void dtrace_cred2priv(const struct cred *, uint32_t *, kuid_t *); -+ -+extern void ctf_forceload(void); -+ -+#define dtrace_membar_producer() smp_wmb() -+#define dtrace_membar_consumer() smp_rmb() -+ -+typedef unsigned long dtrace_icookie_t; -+ -+extern struct mutex cpu_lock; -+ -+extern void dtrace_toxic_ranges(void (*)(uintptr_t, uintptr_t)); -+extern void dtrace_vpanic(const char *, va_list); -+extern int dtrace_getipl(void); -+ -+extern dtrace_icookie_t dtrace_interrupt_disable(void); -+extern void dtrace_interrupt_enable(dtrace_icookie_t); -+ -+typedef void (*dtrace_xcall_t)(void *); -+ -+extern void dtrace_xcall(processorid_t, dtrace_xcall_t, void *); -+ -+extern uintptr_t dtrace_fulword(void *); -+extern uint8_t dtrace_fuword8(void *); -+extern uint16_t dtrace_fuword16(void *); -+extern uint32_t dtrace_fuword32(void *); -+extern uint64_t dtrace_fuword64(void *); -+ -+extern void dtrace_probe_error(struct dtrace_state *, dtrace_epid_t, int, int, -+ int, uintptr_t); -+ -+extern void dtrace_getpcstack(uint64_t *, int, int, uint32_t *); -+extern void dtrace_getupcstack(uint64_t *, int); -+extern unsigned long dtrace_getufpstack(uint64_t *, uint64_t *, int); -+extern uintptr_t dtrace_getfp(void); -+extern uint64_t dtrace_getarg(int, int); -+extern int dtrace_getstackdepth(struct dtrace_mstate *, int); -+extern int dtrace_getustackdepth(void); -+extern ulong_t dtrace_getreg(struct task_struct *, uint_t); -+extern void dtrace_copyin(uintptr_t, uintptr_t, size_t, -+ volatile uint16_t *); -+extern void dtrace_copyout(uintptr_t, uintptr_t, size_t, -+ volatile uint16_t *); -+extern void dtrace_copyinstr(uintptr_t, uintptr_t, size_t, -+ volatile uint16_t *); -+extern void dtrace_copyoutstr(uintptr_t, uintptr_t, size_t, -+ volatile uint16_t *); -+ -+/* -+ * Plaforms that support a fast path to obtain the caller implement the -+ * dtrace_caller() function. -+ * -+ * The first argument is the number of frames that should be skipped when -+ * looking for a caller address. The 2nd argument is a dummy argument that -+ * is necessary for SPARC. -+ * -+ * On x86 this is effectively a NOP. -+ * -+ * On SPARC it is possible to retrieve the caller address from the register -+ * windows without flushing them to the stack. This involves performing -+ * explicit rotation of the register windows. Modification of the windowing -+ * mechanism state alters all %i, %o, and %l registers so we are can only use -+ * %g registers to store temporary data. -+ * -+ * On Linux a lot of %g registers are already allocated for specific purposes. -+ * Saving temporaries to the stack would be a violation of the fast path code -+ * logic. Therefore, the function prototype declares a 2nd argument that serves -+ * as a temporary value. A compiler will not expect that the value in %o1 -+ * will survive the call and therefore dtrace_caller() can use %o1 as a -+ * temporary register. -+ */ -+extern uintptr_t dtrace_caller(int, int); -+ -+extern void dtrace_copyin_arch(uintptr_t, uintptr_t, size_t, -+ volatile uint16_t *); -+extern void dtrace_copyinstr_arch(uintptr_t, uintptr_t, size_t, -+ volatile uint16_t *); -+ -+extern void pdata_init(struct dtrace_module *, struct module *); -+extern void pdata_cleanup(struct dtrace_module *, struct module *); -+ -+extern void debug_enter(char *); -+ -+#endif /* _LINUX_DTRACE_IMPL_H */ -diff --git a/include/dtrace/dtrace_impl_defines.h b/include/dtrace/dtrace_impl_defines.h -new file mode 100644 -index 0000000000000000000000000000000000000000..19b57f6188a0515cb63765bae20d9cf376dc4a21 ---- /dev/null -+++ b/include/dtrace/dtrace_impl_defines.h -@@ -0,0 +1,173 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Dynamic Tracing for Linux - Implementation Defines -+ * -+ * Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_IMPL_DEFINES_H -+#define _LINUX_DTRACE_IMPL_DEFINES_H -+ -+#include <linux/dtrace/universal.h> -+#include <linux/preempt.h> -+#include <asm/ptrace.h> -+ -+typedef typeof(instruction_pointer((struct pt_regs *)0)) pc_t; -+ -+enum dtrace_activity { -+ DTRACE_ACTIVITY_INACTIVE = 0, -+ DTRACE_ACTIVITY_WARMUP, -+ DTRACE_ACTIVITY_ACTIVE, -+ DTRACE_ACTIVITY_DRAINING, -+ DTRACE_ACTIVITY_COOLDOWN, -+ DTRACE_ACTIVITY_STOPPED, -+ DTRACE_ACTIVITY_KILLED -+}; -+ -+enum dtrace_dstate_state { -+ DTRACE_DSTATE_CLEAN = 0, -+ DTRACE_DSTATE_EMPTY, -+ DTRACE_DSTATE_DIRTY, -+ DTRACE_DSTATE_RINSING -+}; -+ -+enum dtrace_dynvar_op { -+ DTRACE_DYNVAR_ALLOC, -+ DTRACE_DYNVAR_NOALLOC, -+ DTRACE_DYNVAR_DEALLOC -+}; -+ -+#define DTRACE_MSTATE_ARGS 0x00000001 -+#define DTRACE_MSTATE_PROBE 0x00000002 -+#define DTRACE_MSTATE_EPID 0x00000004 -+#define DTRACE_MSTATE_TIMESTAMP 0x00000008 -+#define DTRACE_MSTATE_STACKDEPTH 0x00000010 -+#define DTRACE_MSTATE_CALLER 0x00000020 -+#define DTRACE_MSTATE_IPL 0x00000040 -+#define DTRACE_MSTATE_FLTOFFS 0x00000080 -+#define DTRACE_MSTATE_USTACKDEPTH 0x00000100 -+#define DTRACE_MSTATE_UCALLER 0x00000200 -+ -+#define DTRACE_PROBEKEY_MAXDEPTH 8 -+ -+enum dtrace_speculation_state { -+ DTRACESPEC_INACTIVE = 0, -+ DTRACESPEC_ACTIVE, -+ DTRACESPEC_ACTIVEONE, -+ DTRACESPEC_ACTIVEMANY, -+ DTRACESPEC_COMMITTING, -+ DTRACESPEC_COMMITTINGMANY, -+ DTRACESPEC_DISCARDING -+}; -+ -+#define DTRACE_HELPER_ACTION_USTACK 0 -+#define DTRACE_NHELPER_ACTIONS 1 -+ -+#define DTRACE_HELPTRACE_NEXT (-1) -+#define DTRACE_HELPTRACE_DONE (-2) -+#define DTRACE_HELPTRACE_ERR (-3) -+ -+#undef ASSERT -+#ifdef CONFIG_DT_DEBUG -+# define ASSERT(x) ((void)((x) || dtrace_assfail(#x, __FILE__, __LINE__))) -+#else -+# define ASSERT(x) ((void)0) -+#endif -+ -+/* -+ * DTrace Probe Hashing -+ */ -+ -+#define DTRACE_HASHNEXT(hash, probe) \ -+ (struct dtrace_probe **)((uintptr_t)(probe) + (hash)->dth_nextoffs) -+#define DTRACE_HASHPREV(hash, probe) \ -+ (struct dtrace_probe **)((uintptr_t)(probe) + (hash)->dth_prevoffs) -+ -+/* -+ * DTrace Probe Management -+ */ -+#define DTRACE_ANCHORED(probe) ((probe)->dtpr_func[0] != '\0') -+#define DTRACE_FLAGS2FLT(flags) \ -+ (((flags) & CPU_DTRACE_BADADDR) ? DTRACEFLT_BADADDR : \ -+ ((flags) & CPU_DTRACE_ILLOP) ? DTRACEFLT_ILLOP : \ -+ ((flags) & CPU_DTRACE_DIVZERO) ? DTRACEFLT_DIVZERO : \ -+ ((flags) & CPU_DTRACE_KPRIV) ? DTRACEFLT_KPRIV : \ -+ ((flags) & CPU_DTRACE_UPRIV) ? DTRACEFLT_UPRIV : \ -+ ((flags) & CPU_DTRACE_TUPOFLOW) ? DTRACEFLT_TUPOFLOW : \ -+ ((flags) & CPU_DTRACE_BADALIGN) ? DTRACEFLT_BADALIGN : \ -+ ((flags) & CPU_DTRACE_NOSCRATCH) ? DTRACEFLT_NOSCRATCH : \ -+ ((flags) & CPU_DTRACE_BADSTACK) ? DTRACEFLT_BADSTACK : \ -+ DTRACEFLT_UNKNOWN) -+ -+/* -+ * Test whether alloc_sz bytes will fit in the scratch region. We isolate -+ * alloc_sz on the righthand side of the comparison in order to avoid overflow -+ * or underflow in the comparison with it. This is simpler than the INRANGE -+ * check above, because we know that the dtms_scratch_ptr is valid in the -+ * range. Allocations of size zero are allowed. -+ */ -+#define DTRACE_INSCRATCH(mstate, alloc_sz) \ -+ ((mstate)->dtms_scratch_base + (mstate)->dtms_scratch_size - \ -+ (mstate)->dtms_scratch_ptr >= (alloc_sz)) -+ -+/* -+ * Buffering. -+ */ -+ -+#define DTRACEBUF_RING 0x0001 /* bufpolicy set to "ring" */ -+#define DTRACEBUF_FILL 0x0002 /* bufpolicy set to "fill" */ -+#define DTRACEBUF_NOSWITCH 0x0004 /* do not switch buffer */ -+#define DTRACEBUF_WRAPPED 0x0008 /* ring buffer has wrapped */ -+#define DTRACEBUF_DROPPED 0x0010 /* drops occurred */ -+#define DTRACEBUF_ERROR 0x0020 /* errors occurred */ -+#define DTRACEBUF_FULL 0x0040 /* "fill" buffer is full */ -+#define DTRACEBUF_CONSUMED 0x0080 /* buffer has been consumed */ -+#define DTRACEBUF_INACTIVE 0x0100 /* buffer is not yet active */ -+ -+#define DTRACE_STORE(type, tomax, offset, what) \ -+ do { \ -+ *((type *)((uintptr_t)(tomax) + (uintptr_t)(offset))) = (type)(what); \ -+ } while (0) -+ -+#define KERNELBASE (uintptr_t)_text -+ -+#ifdef CONFIG_DT_DEBUG_MUTEX -+# define real_mutex_lock(x) mutex_lock(x) -+# define real_mutex_unlock(x) mutex_unlock(x) -+ -+# define mutex_lock(x) do { \ -+ pr_debug("mutex_lock(%s) at %s::%d for %p (PID %d)\n", \ -+ __stringify(x), \ -+ __FILE__, __LINE__, current, \ -+ current ? current->pid : -1); \ -+ real_mutex_lock(x); \ -+ } while (0) -+# define mutex_unlock(x) do { \ -+ pr_debug("mutex_unlock(%s) at %s::%d for %p (PID %d)\n", \ -+ __stringify(x), \ -+ __FILE__, __LINE__, current, \ -+ current ? current->pid : -1); \ -+ real_mutex_unlock(x); \ -+ } while (0) -+#endif -+ -+#define MUTEX_HELD(lock) mutex_owned(lock) -+ -+#define PDATA(mp) ((struct dtrace_module *)mp->pdata) -+ -+#endif /* _LINUX_DTRACE_IMPL_DEFINES_H */ -diff --git a/include/dtrace/provider.h b/include/dtrace/provider.h -new file mode 100644 -index 0000000000000000000000000000000000000000..9eeb147f03639207768d212cd1ef8e8b00325105 ---- /dev/null -+++ b/include/dtrace/provider.h -@@ -0,0 +1,971 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Dynamic Tracing for Linux - Provider API -+ * -+ * Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _DTRACE_PROVIDER_H -+#define _DTRACE_PROVIDER_H -+ -+/* -+ * The following functions are implemented by the DTrace framework and are -+ * used to implement separate in-kernel DTrace providers. -+ * -+ * The provider API has two halves: the API that the providers consume from -+ * DTrace, and the API that providers make available to DTrace. -+ * -+ * 1 Framework-to-Provider API -+ * -+ * 1.1 Overview -+ * -+ * The Framework-to-Provider API is represented by the dtrace_pops structure -+ * that the provider passes to the framework when registering itself. This -+ * structure consists of the following members: -+ * -+ * dtps_provide() <-- Provide all probes, all modules -+ * dtps_provide_module() <-- Provide all probes in specified module -+ * dtps_enable() <-- Enable specified probe -+ * dtps_disable() <-- Disable specified probe -+ * dtps_suspend() <-- Suspend specified probe -+ * dtps_resume() <-- Resume specified probe -+ * dtps_getargdesc() <-- Get the argument description for args[X] -+ * dtps_getargval() <-- Get the value for an argX or args[X] variable -+ * dtps_usermode() <-- Find out if the probe was fired in user mode -+ * dtps_destroy() <-- Destroy all state associated with this probe -+ * dtps_destroy_module() <-- Destroy per-module data -+ * -+ * 1.2 void dtps_provide(void *arg, const struct dtrace_probedesc *spec) -+ * -+ * 1.2.1 Overview -+ * -+ * Called to indicate that the provider should provide all probes. If the -+ * specified description is non-NULL, dtps_provide() is being called because -+ * no probe matched a specified probe -- if the provider has the ability to -+ * create custom probes, it may wish to create a probe that matches the -+ * specified description. -+ * -+ * 1.2.2 Arguments and notes -+ * -+ * The first argument is the cookie as passed to dtrace_register(). The -+ * second argument is a pointer to a probe description that the provider may -+ * wish to consider when creating custom probes. The provider is expected to -+ * call back into the DTrace framework via dtrace_probe_create() to create -+ * any necessary probes. dtps_provide() may be called even if the provider -+ * has made available all probes; the provider should check the return value -+ * of dtrace_probe_create() to handle this case. Note that the provider need -+ * not implement both dtps_provide() and dtps_provide_module(); see -+ * "Arguments and Notes" for dtrace_register(), below. -+ * -+ * 1.2.3 Return value -+ * -+ * None. -+ * -+ * 1.2.4 Caller's context -+ * -+ * dtps_provide() is typically called from open() or ioctl() context, but may -+ * be called from other contexts as well. The DTrace framework is locked in -+ * such a way that providers may not register or unregister. This means that -+ * the provider may not call any DTrace API that affects its registration with -+ * the framework, including dtrace_register(), dtrace_unregister(), -+ * dtrace_invalidate(), and dtrace_condense(). However, the context is such -+ * that the provider may (and indeed, is expected to) call probe-related -+ * DTrace routines, including dtrace_probe_create(), dtrace_probe_lookup(), -+ * and dtrace_probe_arg(). -+ * -+ * 1.3 void dtps_provide_module(void *arg, struct modctl *mp) -+ * -+ * 1.3.1 Overview -+ * -+ * Called to indicate that the provider should provide all probes in the -+ * specified module. -+ * -+ * 1.3.2 Arguments and notes -+ * -+ * The first argument is the cookie as passed to dtrace_register(). The -+ * second argument is a pointer to a modctl structure that indicates the -+ * module for which probes should be created. -+ * -+ * 1.3.3 Return value -+ * -+ * None. -+ * -+ * 1.3.4 Caller's context -+ * -+ * dtps_provide_module() may be called from open() or ioctl() context, but -+ * may also be called from a module loading context. mod_lock is held, and -+ * the DTrace framework is locked in such a way that providers may not -+ * register or unregister. This means that the provider may not call any -+ * DTrace API that affects its registration with the framework, including -+ * dtrace_register(), dtrace_unregister(), dtrace_invalidate(), and -+ * dtrace_condense(). However, the context is such that the provider may (and -+ * indeed, is expected to) call probe-related DTrace routines, including -+ * dtrace_probe_create(), dtrace_probe_lookup(), and dtrace_probe_arg(). Note -+ * that the provider need not implement both dtps_provide() and -+ * dtps_provide_module(); see "Arguments and Notes" for dtrace_register(), -+ * below. -+ * -+ * 1.4 int dtps_enable(void *arg, dtrace_id_t id, void *parg) -+ * -+ * 1.4.1 Overview -+ * -+ * Called to enable the specified probe. -+ * -+ * 1.4.2 Arguments and notes -+ * -+ * The first argument is the cookie as passed to dtrace_register(). The -+ * second argument is the identifier of the probe to be enabled. The third -+ * argument is the probe argument as passed to dtrace_probe_create(). -+ * dtps_enable() will be called when a probe transitions from not being -+ * enabled at all to having one or more ECB. The number of ECBs associated -+ * with the probe may change without subsequent calls into the provider. -+ * When the number of ECBs drops to zero, the provider will be explicitly -+ * told to disable the probe via dtps_disable(). dtrace_probe() should never -+ * be called for a probe identifier that hasn't been explicitly enabled via -+ * dtps_enable(). -+ * -+ * 1.4.3 Return value -+ * -+ * On success, dtps_enable() should return 0. On failure, -1 should be -+ * returned. -+ * -+ * 1.4.4 Caller's context -+ * -+ * The DTrace framework is locked in such a way that it may not be called -+ * back into at all. cpu_lock is held. mod_lock is not held and may not -+ * be acquired. -+ * -+ * 1.5 void dtps_disable(void *arg, dtrace_id_t id, void *parg) -+ * -+ * 1.5.1 Overview -+ * -+ * Called to disable the specified probe. -+ * -+ * 1.5.2 Arguments and notes -+ * -+ * The first argument is the cookie as passed to dtrace_register(). The -+ * second argument is the identifier of the probe to be disabled. The third -+ * argument is the probe argument as passed to dtrace_probe_create(). -+ * dtps_disable() will be called when a probe transitions from being enabled -+ * to having zero ECBs. dtrace_probe() should never be called for a probe -+ * identifier that has been explicitly enabled via dtps_disable(). -+ * -+ * 1.5.3 Return value -+ * -+ * None. -+ * -+ * 1.5.4 Caller's context -+ * -+ * The DTrace framework is locked in such a way that it may not be called -+ * back into at all. cpu_lock is held. mod_lock is not held and may not -+ * be acquired. -+ * -+ * 1.6 void dtps_suspend(void *arg, dtrace_id_t id, void *parg) -+ * -+ * 1.6.1 Overview -+ * -+ * Called to suspend the specified enabled probe. This entry point is for -+ * providers that may need to suspend some or all of their probes when CPUs -+ * are being powered on or when the boot monitor is being entered for a -+ * prolonged period of time. -+ * -+ * 1.6.2 Arguments and notes -+ * -+ * The first argument is the cookie as passed to dtrace_register(). The -+ * second argument is the identifier of the probe to be suspended. The -+ * third argument is the probe argument as passed to dtrace_probe_create(). -+ * dtps_suspend will only be called on an enabled probe. Providers that -+ * provide a dtps_suspend entry point will want to take roughly the action -+ * that it takes for dtps_disable. -+ * -+ * 1.6.3 Return value -+ * -+ * None. -+ * -+ * 1.6.4 Caller's context -+ * -+ * Interrupts are disabled. The DTrace framework is in a state such that the -+ * specified probe cannot be disabled or destroyed for the duration of -+ * dtps_suspend(). As interrupts are disabled, the provider is afforded -+ * little latitude; the provider is expected to do no more than a store to -+ * memory. -+ * -+ * 1.7 void dtps_resume(void *arg, dtrace_id_t id, void *parg) -+ * -+ * 1.7.1 Overview -+ * -+ * Called to resume the specified enabled probe. This entry point is for -+ * providers that may need to resume some or all of their probes after the -+ * completion of an event that induced a call to dtps_suspend(). -+ * -+ * 1.7.2 Arguments and notes -+ * -+ * The first argument is the cookie as passed to dtrace_register(). The -+ * second argument is the identifier of the probe to be resumed. The -+ * third argument is the probe argument as passed to dtrace_probe_create(). -+ * dtps_resume will only be called on an enabled probe. Providers that -+ * provide a dtps_resume entry point will want to take roughly the action -+ * that it takes for dtps_enable. -+ * -+ * 1.7.3 Return value -+ * -+ * None. -+ * -+ * 1.7.4 Caller's context -+ * -+ * Interrupts are disabled. The DTrace framework is in a state such that the -+ * specified probe cannot be disabled or destroyed for the duration of -+ * dtps_resume(). As interrupts are disabled, the provider is afforded -+ * little latitude; the provider is expected to do no more than a store to -+ * memory. -+ * -+ * 1.8 void dtps_getargdesc(void *arg, dtrace_id_t id, void *parg, -+ * struct dtrace_argdesc *desc) -+ * -+ * 1.8.1 Overview -+ * -+ * Called to retrieve the argument description for an args[X] variable. -+ * -+ * 1.8.2 Arguments and notes -+ * -+ * The first argument is the cookie as passed to dtrace_register(). The -+ * second argument is the identifier of the current probe. The third -+ * argument is the probe argument as passed to dtrace_probe_create(). The -+ * fourth argument is a pointer to the argument description. This -+ * description is both an input and output parameter: it contains the -+ * index of the desired argument in the dtargd_ndx field, and expects -+ * the other fields to be filled in upon return. If there is no argument -+ * corresponding to the specified index, the dtargd_ndx field should be set -+ * to DTRACE_ARGNONE. -+ * -+ * 1.8.3 Return value -+ * -+ * None. The dtargd_ndx, dtargd_native, dtargd_xlate and dtargd_mapping -+ * members of the dtrace_argdesc structure are all output values. -+ * -+ * 1.8.4 Caller's context -+ * -+ * dtps_getargdesc() is called from ioctl() context. mod_lock is held, and -+ * the DTrace framework is locked in such a way that providers may not -+ * register or unregister. This means that the provider may not call any -+ * DTrace API that affects its registration with the framework, including -+ * dtrace_register(), dtrace_unregister(), dtrace_invalidate(), and -+ * dtrace_condense(). -+ * -+ * 1.9 uint64_t dtps_getargval(void *arg, dtrace_id_t id, void *parg, -+ * int argno, int aframes) -+ * -+ * 1.9.1 Overview -+ * -+ * Called to retrieve a value for an argX or args[X] variable. -+ * -+ * 1.9.2 Arguments and notes -+ * -+ * The first argument is the cookie as passed to dtrace_register(). The -+ * second argument is the identifier of the current probe. The third -+ * argument is the probe argument as passed to dtrace_probe_create(). The -+ * fourth argument is the number of the argument (the X in the example in -+ * 1.9.1). The fifth argument is the number of stack frames that were used -+ * to get from the actual place in the code that fired the probe to -+ * dtrace_probe() itself, the so-called artificial frames. This argument may -+ * be used to descend an appropriate number of frames to find the correct -+ * values. If this entry point is left NULL, the dtrace_getarg() built-in -+ * function is used. -+ * -+ * 1.9.3 Return value -+ * -+ * The value of the argument. -+ * -+ * 1.9.4 Caller's context -+ * -+ * This is called from within dtrace_probe() meaning that interrupts -+ * are disabled. No locks should be taken within this entry point. -+ * -+ * 1.10 int dtps_usermode(void *arg, dtrace_id_t id, void *parg) -+ * -+ * 1.10.1 Overview -+ * -+ * Called to determine if the probe was fired in a user context. -+ * -+ * 1.10.2 Arguments and notes -+ * -+ * The first argument is the cookie as passed to dtrace_register(). The -+ * second argument is the identifier of the current probe. The third -+ * argument is the probe argument as passed to dtrace_probe_create(). This -+ * entry point must not be left NULL for providers whose probes allow for -+ * mixed mode tracing, that is to say those probes that can fire during -+ * kernel- _or_ user-mode execution -+ * -+ * 1.10.3 Return value -+ * -+ * A boolean value. -+ * -+ * 1.10.4 Caller's context -+ * -+ * This is called from within dtrace_probe() meaning that interrupts -+ * are disabled. No locks should be taken within this entry point. -+ * -+ * 1.11 void dtps_destroy(void *arg, dtrace_id_t id, void *parg) -+ * -+ * 1.11.1 Overview -+ * -+ * Called to destroy the specified probe. -+ * -+ * 1.11.2 Arguments and notes -+ * -+ * The first argument is the cookie as passed to dtrace_register(). The -+ * second argument is the identifier of the probe to be destroyed. The third -+ * argument is the probe argument as passed to dtrace_probe_create(). The -+ * provider should free all state associated with the probe. The framework -+ * guarantees that dtps_destroy() is only called for probes that have either -+ * been disabled via dtps_disable() or were never enabled via dtps_enable(). -+ * Once dtps_disable() has been called for a probe, no further call will be -+ * made specifying the probe. -+ * -+ * 1.11.3 Return value -+ * -+ * None. -+ * -+ * 1.11.4 Caller's context -+ * -+ * The DTrace framework is locked in such a way that it may not be called -+ * back into at all. mod_lock is held. cpu_lock is not held, and may not be -+ * acquired. -+ * -+ * 1.12 void dtps_destroy_module(void *arg, struct modctl *mp) -+ * -+ * 1.12.1 Overview -+ * -+ * Called to notify provider that it can remove any per-module data. -+ * -+ * 1.12.2 Arguments and notes -+ * -+ * The first argument is the cookie as passed to dtrace_register(). The -+ * second argument is a pointer to a struct module structure that points to -+ * the module for which data may be cleared. -+ * -+ * 1.12.3 Return value -+ * -+ * None. -+ * -+ * -+ * 2 Provider-to-Framework API -+ * -+ * 2.1 Overview -+ * -+ * The Provider-to-Framework API provides the mechanism for the provider to -+ * register itself with the DTrace framework, to create probes, to lookup -+ * probes and (most importantly) to fire probes. The Provider-to-Framework -+ * consists of: -+ * -+ * dtrace_register() <-- Register a provider with the DTrace framework -+ * dtrace_unregister() <-- Remove a provider's DTrace registration -+ * dtrace_meta_register() <-- Register a metaprovider with the DTrace framework -+ * dtrace_meta_unregister()<-- Remove a metaprovider's DTrace registration -+ * dtrace_invalidate() <-- Invalidate the specified provider -+ * dtrace_condense() <-- Remove a provider's unenabled probes -+ * dtrace_attached() <-- Indicates whether or not DTrace has attached -+ * dtrace_probe_create() <-- Create a DTrace probe -+ * dtrace_probe_lookup() <-- Lookup a DTrace probe based on its name -+ * dtrace_probe_arg() <-- Return the probe argument for a specific probe -+ * dtrace_probe() <-- Fire the specified probe -+ * -+ * 2.2 int dtrace_register(const char *name, const struct dtrace_pattr *pap, -+ * uint32_t priv, struct cred *cr, const struct dtrace_pops *pops, -+ * void *arg, dtrace_provider_id_t *idp) -+ * -+ * 2.2.1 Overview -+ * -+ * dtrace_register() registers the calling provider with the DTrace -+ * framework. It should generally be called by DTrace providers in their -+ * attach(9E) entry point. -+ * -+ * 2.2.2 Arguments and Notes -+ * -+ * The first argument is the name of the provider. The second argument is a -+ * pointer to the stability attributes for the provider. The third argument -+ * is the privilege flags for the provider, and must be some combination of: -+ * -+ * DTRACE_PRIV_NONE <= All users may enable probes from this provider -+ * -+ * DTRACE_PRIV_PROC <= Any user with privilege of PRIV_DTRACE_PROC may -+ * enable probes from this provider -+ * -+ * DTRACE_PRIV_USER <= Any user with privilege of PRIV_DTRACE_USER may -+ * enable probes from this provider -+ * -+ * DTRACE_PRIV_KERNEL <= Any user with privilege of PRIV_DTRACE_KERNEL -+ * may enable probes from this provider -+ * -+ * DTRACE_PRIV_OWNER <= This flag places an additional constraint on -+ * the privilege requirements above. These probes -+ * require either (a) a user ID matching the user -+ * ID of the cred passed in the fourth argument -+ * or (b) the PRIV_PROC_OWNER privilege. -+ * -+ * Note that these flags designate the _visibility_ of the probes, not -+ * the conditions under which they may or may not fire. -+ * -+ * The fourth argument is the credential that is associated with the provider. -+ * This argument should be NULL if the privilege flags don't include -+ * DTRACE_PRIV_OWNER. If non-NULL, the framework stashes the uid represented -+ * by this credential for use at probe-time, in implicit predicates. These -+ * limit visibility of the probes to users which have sufficient privilege to -+ * access them. -+ * -+ * The fifth argument is a DTrace provider operations vector, which provides -+ * the implementation for the Framework-to-Provider API. (See Section 1, -+ * above.) This must be non-NULL, and each member must be non-NULL. The -+ * exceptions to this are (1) the dtps_provide() and dtps_provide_module() -+ * members (if the provider so desires, _one_ of these members may be left -+ * NULL -- denoting that the provider only implements the other) and (2) -+ * the dtps_suspend() and dtps_resume() members, which must either both be -+ * NULL or both be non-NULL. -+ * -+ * The sixth argument is a cookie to be specified as the first argument for -+ * each function in the Framework-to-Provider API. This argument may have -+ * any value. -+ * -+ * The final argument is a pointer to dtrace_provider_id_t. If -+ * dtrace_register() successfully completes, the provider identifier will be -+ * stored in the memory pointed to be this argument. This argument must be -+ * non-NULL. -+ * -+ * 2.2.3 Return value -+ * -+ * On success, dtrace_register() returns 0 and stores the new provider's -+ * identifier into the memory pointed to by the idp argument. On failure, -+ * dtrace_register() returns an errno: -+ * -+ * EINVAL The arguments passed to dtrace_register() were somehow invalid. -+ * This may because a parameter that must be non-NULL was NULL, -+ * because the name was invalid (either empty or an illegal -+ * provider name) or because the attributes were invalid. -+ * -+ * No other failure code is returned. -+ * -+ * 2.2.4 Caller's context -+ * -+ * dtrace_register() may induce calls to dtrace_provide(); the provider must -+ * hold no locks across dtrace_register() that may also be acquired by -+ * dtrace_provide(). cpu_lock and mod_lock must not be held. -+ * -+ * 2.3 int dtrace_unregister(dtrace_provider_id_t id) -+ * -+ * 2.3.1 Overview -+ * -+ * Unregisters the specified provider from the DTrace framework. It should -+ * generally be called by DTrace providers in their detach(9E) entry point. -+ * -+ * 2.3.2 Arguments and Notes -+ * -+ * The only argument is the provider identifier, as returned from a -+ * successful call to dtrace_register(). As a result of calling -+ * dtrace_unregister(), the DTrace framework will call back into the provider -+ * via the dtps_destroy() entry point. Once dtrace_unregister() successfully -+ * completes, however, the DTrace framework will no longer make calls through -+ * the Framework-to-Provider API. -+ * -+ * 2.3.3 Return value -+ * -+ * On success, dtrace_unregister returns 0. On failure, dtrace_unregister() -+ * returns an errno: -+ * -+ * EBUSY There are currently processes that have the DTrace pseudodevice -+ * open, or there exists an anonymous enabling that hasn't yet -+ * been claimed. -+ * -+ * No other failure code is returned. -+ * -+ * 2.3.4 Caller's context -+ * -+ * Because a call to dtrace_unregister() may induce calls through the -+ * Framework-to-Provider API, the caller may not hold any lock across -+ * dtrace_register() that is also acquired in any of the Framework-to- -+ * Provider API functions. Additionally, mod_lock may not be held. -+ * -+ * 2.4 void dtrace_invalidate(dtrace_provider_id_t id) -+ * -+ * 2.4.1 Overview -+ * -+ * Invalidates the specified provider. All subsequent probe lookups for the -+ * specified provider will fail, but its probes will not be removed. -+ * -+ * 2.4.2 Arguments and note -+ * -+ * The only argument is the provider identifier, as returned from a -+ * successful call to dtrace_register(). In general, a provider's probes -+ * always remain valid; dtrace_invalidate() is a mechanism for invalidating -+ * an entire provider, regardless of whether or not probes are enabled or -+ * not. Note that dtrace_invalidate() will _not_ prevent already enabled -+ * probes from firing -- it will merely prevent any new enablings of the -+ * provider's probes. -+ * -+ * 2.5 int dtrace_condense(dtrace_provider_id_t id) -+ * -+ * 2.5.1 Overview -+ * -+ * Removes all the unenabled probes for the given provider. This function is -+ * not unlike dtrace_unregister(), except that it doesn't remove the -+ * provider just as many of its associated probes as it can. -+ * -+ * 2.5.2 Arguments and Notes -+ * -+ * As with dtrace_unregister(), the sole argument is the provider identifier -+ * as returned from a successful call to dtrace_register(). As a result of -+ * calling dtrace_condense(), the DTrace framework will call back into the -+ * given provider's dtps_destroy() entry point for each of the provider's -+ * unenabled probes. -+ * -+ * 2.5.3 Return value -+ * -+ * Currently, dtrace_condense() always returns 0. However, consumers of this -+ * function should check the return value as appropriate; its behavior may -+ * change in the future. -+ * -+ * 2.5.4 Caller's context -+ * -+ * As with dtrace_unregister(), the caller may not hold any lock across -+ * dtrace_condense() that is also acquired in the provider's entry points. -+ * Also, mod_lock may not be held. -+ * -+ * 2.6 int dtrace_attached() -+ * -+ * 2.6.1 Overview -+ * -+ * Indicates whether or not DTrace has attached. -+ * -+ * 2.6.2 Arguments and Notes -+ * -+ * For most providers, DTrace makes initial contact beyond registration. -+ * That is, once a provider has registered with DTrace, it waits to hear -+ * from DTrace to create probes. However, some providers may wish to -+ * proactively create probes without first being told by DTrace to do so. -+ * If providers wish to do this, they must first call dtrace_attached() to -+ * determine if DTrace itself has attached. If dtrace_attached() returns 0, -+ * the provider must not make any other Provider-to-Framework API call. -+ * -+ * 2.6.3 Return value -+ * -+ * dtrace_attached() returns 1 if DTrace has attached, 0 otherwise. -+ * -+ * 2.7 int dtrace_probe_create(dtrace_provider_id_t id, const char *mod, -+ * const char *func, const char *name, int aframes, void *arg) -+ * -+ * 2.7.1 Overview -+ * -+ * Creates a probe with specified module name, function name, and name. -+ * -+ * 2.7.2 Arguments and Notes -+ * -+ * The first argument is the provider identifier, as returned from a -+ * successful call to dtrace_register(). The second, third, and fourth -+ * arguments are the module name, function name, and probe name, -+ * respectively. Of these, module name and function name may both be NULL -+ * (in which case the probe is considered to be unanchored), or they may both -+ * be non-NULL. The name must be non-NULL, and must point to a non-empty -+ * string. -+ * -+ * The fifth argument is the number of artificial stack frames that will be -+ * found on the stack when dtrace_probe() is called for the new probe. These -+ * artificial frames will be automatically be pruned should the stack() or -+ * stackdepth() functions be called as part of one of the probe's ECBs. If -+ * the parameter doesn't add an artificial frame, this parameter should be -+ * zero. -+ * -+ * The final argument is a probe argument that will be passed back to the -+ * provider when a probe-specific operation is called. (e.g., via -+ * dtps_enable(), dtps_disable(), etc.) -+ * -+ * Note that it is up to the provider to be sure that the probe that it -+ * creates does not already exist -- if the provider is unsure of the probe's -+ * existence, it should assure its absence with dtrace_probe_lookup() before -+ * calling dtrace_probe_create(). -+ * -+ * 2.7.3 Return value -+ * -+ * dtrace_probe_create() always succeeds, and always returns the identifier -+ * of the newly-created probe. -+ * -+ * 2.7.4 Caller's context -+ * -+ * While dtrace_probe_create() is generally expected to be called from -+ * dtps_provide() and/or dtps_provide_module(), it may be called from other -+ * non-DTrace contexts. Neither cpu_lock nor mod_lock may be held. -+ * -+ * 2.8 dtrace_id_t dtrace_probe_lookup(dtrace_provider_id_t id, -+ * const char *mod, const char *func, const char *name) -+ * -+ * 2.8.1 Overview -+ * -+ * Looks up a probe based on provdider and one or more of module name, -+ * function name and probe name. -+ * -+ * 2.8.2 Arguments and Notes -+ * -+ * The first argument is the provider identifier, as returned from a -+ * successful call to dtrace_register(). The second, third, and fourth -+ * arguments are the module name, function name, and probe name, -+ * respectively. Any of these may be NULL; dtrace_probe_lookup() will return -+ * the identifier of the first probe that is provided by the specified -+ * provider and matches all of the non-NULL matching criteria. -+ * dtrace_probe_lookup() is generally used by a provider to be check the -+ * existence of a probe before creating it with dtrace_probe_create(). -+ * -+ * 2.8.3 Return value -+ * -+ * If the probe exists, returns its identifier. If the probe does not exist, -+ * return DTRACE_IDNONE. -+ * -+ * 2.8.4 Caller's context -+ * -+ * While dtrace_probe_lookup() is generally expected to be called from -+ * dtps_provide() and/or dtps_provide_module(), it may also be called from -+ * other non-DTrace contexts. Neither cpu_lock nor mod_lock may be held. -+ * -+ * 2.9 void *dtrace_probe_arg(dtrace_provider_id_t id, dtrace_id_t probe) -+ * -+ * 2.9.1 Overview -+ * -+ * Returns the probe argument associated with the specified probe. -+ * -+ * 2.9.2 Arguments and Notes -+ * -+ * The first argument is the provider identifier, as returned from a -+ * successful call to dtrace_register(). The second argument is a probe -+ * identifier, as returned from dtrace_probe_lookup() or -+ * dtrace_probe_create(). This is useful if a probe has multiple -+ * provider-specific components to it: the provider can create the probe -+ * once with provider-specific state, and then add to the state by looking -+ * up the probe based on probe identifier. -+ * -+ * 2.9.3 Return value -+ * -+ * Returns the argument associated with the specified probe. If the -+ * specified probe does not exist, or if the specified probe is not provided -+ * by the specified provider, NULL is returned. -+ * -+ * 2.9.4 Caller's context -+ * -+ * While dtrace_probe_arg() is generally expected to be called from -+ * dtps_provide() and/or dtps_provide_module(), it may also be called from -+ * other non-DTrace contexts. Neither cpu_lock nor mod_lock may be held. -+ * -+ * 2.10 void dtrace_probe(dtrace_id_t probe, uintptr_t arg0, uintptr_t arg1, -+ * uintptr_t arg2, uintptr_t arg3, uintptr_t arg4) -+ * -+ * 2.10.1 Overview -+ * -+ * The epicenter of DTrace: fires the specified probes with the specified -+ * arguments. -+ * -+ * 2.10.2 Arguments and Notes -+ * -+ * The first argument is a probe identifier as returned by -+ * dtrace_probe_create() or dtrace_probe_lookup(). The second through sixth -+ * arguments are the values to which the D variables "arg0" through "arg4" -+ * will be mapped. -+ * -+ * dtrace_probe() should be called whenever the specified probe has fired -- -+ * however the provider defines it. -+ * -+ * 2.10.3 Return value -+ * -+ * None. -+ * -+ * 2.10.4 Caller's context -+ * -+ * dtrace_probe() may be called in virtually any context: kernel, user, -+ * interrupt, high-level interrupt, with arbitrary adaptive locks held, with -+ * dispatcher locks held, with interrupts disabled, etc. The only latitude -+ * that must be afforded to DTrace is the ability to make calls within -+ * itself (and to its in-kernel subroutines) and the ability to access -+ * arbitrary (but mapped) memory. On some platforms, this constrains -+ * context. For example, on UltraSPARC, dtrace_probe() cannot be called -+ * from any context in which TL is greater than zero. dtrace_probe() may -+ * also not be called from any routine which may be called by dtrace_probe() -+ * -- which includes functions in the DTrace framework and some in-kernel -+ * DTrace subroutines. All such functions "dtrace_"; providers that -+ * instrument the kernel arbitrarily should be sure to not instrument these -+ * routines. -+ */ -+ -+#include <dtrace/types.h> -+#include <linux/cred.h> -+#include <linux/module.h> -+#include <linux/dtrace/enabling_defines.h> -+#include <linux/dtrace/arg_defines.h> -+#include <dtrace/provider_defines.h> -+#include <linux/dtrace/stability.h> -+ -+struct dtrace_pops { -+ void (*dtps_provide)(void *, const struct dtrace_probedesc *); -+ void (*dtps_provide_module)(void *, struct module *); -+ int (*dtps_enable)(void *, dtrace_id_t, void *); -+ void (*dtps_disable)(void *, dtrace_id_t, void *); -+ void (*dtps_suspend)(void *, dtrace_id_t, void *); -+ void (*dtps_resume)(void *, dtrace_id_t, void *); -+ void (*dtps_getargdesc)(void *, dtrace_id_t, void *, -+ struct dtrace_argdesc *); -+ uint64_t (*dtps_getargval)(void *, dtrace_id_t, void *, int, int); -+ int (*dtps_usermode)(void *, dtrace_id_t, void *); -+ void (*dtps_destroy)(void *, dtrace_id_t, void *); -+ void (*dtps_destroy_module)(void *, struct module *); -+}; -+ -+struct dtrace_helper_probedesc { -+ char *dthpb_mod; -+ char *dthpb_func; -+ char *dthpb_name; -+ uint64_t dthpb_base; -+ uint32_t *dthpb_offs; -+ uint32_t *dthpb_enoffs; -+ uint32_t dthpb_noffs; -+ uint32_t dthpb_nenoffs; -+ uint8_t *dthpb_args; -+ uint8_t dthpb_xargc; -+ uint8_t dthpb_nargc; -+ char *dthpb_xtypes; -+ char *dthpb_ntypes; -+}; -+ -+struct dtrace_helper_provdesc { -+ char *dthpv_provname; -+ struct dtrace_pattr dthpv_pattr; -+}; -+ -+struct dtrace_mops { -+ void (*dtms_create_probe)(void *, void *, -+ struct dtrace_helper_probedesc *); -+ void *(*dtms_provide_pid)(void *, struct dtrace_helper_provdesc *, -+ pid_t); -+ void (*dtms_remove_pid)(void *, struct dtrace_helper_provdesc *, -+ pid_t); -+}; -+ -+/* -+ * DTrace Provider-to-Framework API Functions -+ */ -+ -+struct dtrace_meta { -+ struct dtrace_mops dtm_mops; -+ char *dtm_name; -+ void *dtm_arg; -+ uint64_t dtm_count; -+}; -+ -+struct dtrace_mprovider { -+ char *dtmp_name; -+ char *dtmp_pref; -+ struct dtrace_pattr *dtmp_attr; -+ uint32_t dtmp_priv; -+ struct dtrace_pops *dtmp_pops; -+ dtrace_provider_id_t dtmp_id; -+}; -+ -+struct dtrace_pmod { -+ struct module *mod; -+ struct list_head list; -+}; -+ -+extern int dtrace_register(const char *, const struct dtrace_pattr *, -+ uint32_t, const struct cred *, -+ const struct dtrace_pops *, void *, -+ dtrace_provider_id_t *); -+extern int dtrace_unregister(dtrace_provider_id_t); -+extern void dtrace_invalidate(dtrace_provider_id_t); -+extern int dtrace_condense(dtrace_provider_id_t); -+extern int dtrace_attached(void); -+ -+extern int dtrace_meta_register(const char *, const struct dtrace_mops *, -+ void *, dtrace_meta_provider_id_t *); -+extern int dtrace_meta_unregister(dtrace_meta_provider_id_t); -+ -+extern dtrace_id_t dtrace_probe_create(dtrace_provider_id_t, const char *, -+ const char *, const char *, int, -+ void *); -+extern void *dtrace_probe_arg(dtrace_provider_id_t, dtrace_id_t); -+extern dtrace_id_t dtrace_probe_lookup(dtrace_provider_id_t, const char *, -+ const char *, const char *); -+extern void dtrace_probe(dtrace_id_t, uintptr_t, uintptr_t, uintptr_t, -+ uintptr_t, uintptr_t, uintptr_t, uintptr_t); -+ -+/* -+ * Provider creation. -+ */ -+#ifdef DTRACE_HAVE_PROV_EXIT -+# define DT_PROV_EXIT(name) \ -+ extern int name##_prov_exit(void); -+#else -+# define DT_PROV_EXIT(name) \ -+ static int name##_prov_exit(void) \ -+ { \ -+ return (dtrace_unregister(name##_id) == 0); \ -+ } -+#endif -+ -+#define DT_PROVIDER_MODULE(name, priv) \ -+ dtrace_provider_id_t name##_id = DTRACE_PROVNONE; \ -+ \ -+ DT_PROV_EXIT(name) \ -+ \ -+ static int __init name##_init(void) \ -+ { \ -+ int ret = -ENOMEM; \ -+ struct dtrace_module *pdata = THIS_MODULE->pdata; \ -+ \ -+ if (pdata == NULL) \ -+ goto failed; \ -+ \ -+ ret = name##_dev_init(); \ -+ if (ret) \ -+ goto failed; \ -+ \ -+ ret = dtrace_register(__stringify(name), &name##_attr, priv, \ -+ NULL, &name##_pops, NULL, &name##_id); \ -+ if (ret) \ -+ goto failed; \ -+ \ -+ pdata->prov_exit = name##_prov_exit; \ -+ \ -+ return 0; \ -+ \ -+ failed: \ -+ return ret; \ -+ } \ -+ \ -+ static void __exit name##_exit(void) \ -+ { \ -+ name##_dev_exit(); \ -+ } \ -+ \ -+ module_init(name##_init); \ -+ module_exit(name##_exit); -+ -+#ifdef DTRACE_HAVE_PROV_EXIT -+# define DT_META_PROV_EXIT(name) \ -+ extern int name##_prov_exit(void); -+#else -+# define DT_META_PROV_EXIT(name) \ -+ static int name##_prov_exit(void) \ -+ { \ -+ return (dtrace_meta_unregister(name##_id) == 0); \ -+ } -+#endif -+ -+#define DT_META_PROVIDER_MODULE(name) \ -+ dtrace_meta_provider_id_t name##_id = DTRACE_METAPROVNONE; \ -+ \ -+ DT_META_PROV_EXIT(name) \ -+ \ -+ static int __init name##_init(void) \ -+ { \ -+ int ret = -ENOMEM; \ -+ struct dtrace_module *pdata = THIS_MODULE->pdata; \ -+ \ -+ if (pdata == NULL) \ -+ goto failed; \ -+ \ -+ ret = name##_dev_init(); \ -+ if (ret) \ -+ goto failed; \ -+ \ -+ ret = dtrace_meta_register(__stringify(name), &name##_mops, \ -+ NULL, &name##_id); \ -+ if (ret) \ -+ goto failed; \ -+ \ -+ pdata->prov_exit = name##_prov_exit; \ -+ \ -+ return 0; \ -+ \ -+ failed: \ -+ return ret; \ -+ } \ -+ \ -+ static void __exit name##_exit(void) \ -+ { \ -+ name##_dev_exit(); \ -+ } \ -+ \ -+ module_init(name##_init); \ -+ module_exit(name##_exit); -+ -+#define DT_MULTI_PROVIDER_MODULE(name, plist) \ -+ static int name##_prov_exit(void) \ -+ { \ -+ int ret = 0; \ -+ struct dtrace_mprovider *prov; \ -+ \ -+ for (prov = plist; prov->dtmp_name != NULL; prov++) { \ -+ if (prov->dtmp_id != DTRACE_PROVNONE) { \ -+ ret = dtrace_unregister(prov->dtmp_id); \ -+ if (ret != 0) { \ -+ pr_warn("Failed to unregister " \ -+ "provider %s: %d", \ -+ prov->dtmp_name, ret); \ -+ break; \ -+ } \ -+ \ -+ prov->dtmp_id = DTRACE_PROVNONE; \ -+ } \ -+ } \ -+ \ -+ return (ret == 0); \ -+ } \ -+ \ -+ static int __init name##_init(void) \ -+ { \ -+ int ret = -ENOMEM; \ -+ struct dtrace_mprovider *prov; \ -+ struct dtrace_module *pdata = THIS_MODULE->pdata; \ -+ \ -+ if (pdata == NULL) \ -+ goto failed; \ -+ \ -+ ret = name##_dev_init(); \ -+ if (ret) \ -+ goto failed; \ -+ \ -+ for (prov = plist; prov->dtmp_name != NULL; prov++) { \ -+ if (dtrace_register(prov->dtmp_name, prov->dtmp_attr, \ -+ prov->dtmp_priv, NULL, \ -+ prov->dtmp_pops, prov, \ -+ &prov->dtmp_id) != 0) \ -+ pr_warn("Failed to register provider %s", \ -+ prov->dtmp_name); \ -+ } \ -+ \ -+ pdata->prov_exit = name##_prov_exit; \ -+ \ -+ return 0; \ -+ \ -+ failed: \ -+ return ret; \ -+ } \ -+ \ -+ static void __exit name##_exit(void) \ -+ { \ -+ name##_dev_exit(); \ -+ } \ -+ \ -+ module_init(name##_init); \ -+ module_exit(name##_exit); -+ -+ -+#endif /* _DTRACE_PROVIDER_H */ -diff --git a/include/dtrace/provider_defines.h b/include/dtrace/provider_defines.h -new file mode 100644 -index 0000000000000000000000000000000000000000..104514e1261be3e7803e84f6276b01d42186b67f ---- /dev/null -+++ b/include/dtrace/provider_defines.h -@@ -0,0 +1,41 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Dynamic Tracing for Linux - Provider defines -+ * -+ * Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _DTRACE_PROVIDER_DEFINES_H -+#define _DTRACE_PROVIDER_DEFINES_H -+ -+#include <linux/dtrace/universal.h> -+#include <linux/in6.h> -+ -+typedef uintptr_t dtrace_provider_id_t; -+typedef uintptr_t dtrace_meta_provider_id_t; -+typedef __be32 ipaddr_t; -+typedef ipaddr_t *ipaddr_t_p; -+typedef struct in6_addr in6_addr_t; -+ -+struct dtrace_pops; -+struct dtrace_helper_probedesc; -+struct dtrace_helper_provdesc; -+struct dtrace_mops; -+struct dtrace_meta; -+ -+#endif /* _DTRACE_PROVIDER_DEFINES_H */ -diff --git a/include/dtrace/types.h b/include/dtrace/types.h -new file mode 100644 -index 0000000000000000000000000000000000000000..7f8d0d7efcc7b9552d75935233572c4de8fe0532 ---- /dev/null -+++ b/include/dtrace/types.h -@@ -0,0 +1,131 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Dynamic Tracing for Linux - Kernel Types -+ * -+ * Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _DTRACE_TYPES_H -+#define _DTRACE_TYPES_H -+ -+/* -+ * This file contains types needed to parse the DTrace shared userspace/ kernel -+ * headers, and a few others (it has not been gardened to remove constants used -+ * only by the DTrace core). Userspace has its own version of these types -+ * (mostly from <unistd.h>). -+ * -+ * This file is compiled both in a normal kernel environment and in a peculiar -+ * halfway-house environment used for headers_checking of <ioctl.h>, in which -+ * among other things, no config.h symbols are available. As a result, you -+ * should be careful about #including kernel headers here: many will break -+ * headers_check if added. So far, it has always been sufficient to add them to -+ * dtrace/dtrace.h instead; if this turns out to be insufficient later (perhaps -+ * because DTrace core files cease to #include all of <dtrace.h>), the -+ * HEADERS_CHECK #define may prove useful to disable kernel-only portions of -+ * this file. -+ */ -+ -+#include <asm/bitsperlong.h> -+#include <linux/dtrace_os.h> -+ -+typedef unsigned char uchar_t; -+typedef unsigned int uint_t; -+typedef unsigned long ulong_t; -+ -+typedef long intptr_t; -+ -+#define UINT8_MAX (0xff) -+#define UINT8_MIN 0 -+#define UINT16_MAX (0xffff) -+#define UINT16_MIN 0 -+#define UINT32_MAX (0xffffffff) -+#define UINT32_MIN 0 -+#define UINT64_MAX (~0ULL) -+#define UINT64_MIN (0) -+#define INT64_MAX ((long long)(~0ULL>>1)) -+#define INT64_MIN (-INT64_MAX - 1LL) -+ -+#define NBBY (__BITS_PER_LONG / sizeof(long)) -+ -+/* -+ * This is a bit unusual, but OpenSolaris seems to like it. Basically, the -+ * values below are the number of time units (sec, milli, micro, nano) that -+ * comprise 1 second. As such, it is the value of the respective multiplier. -+ */ -+#define SEC 1 -+#define MILLISEC 1000 -+#define MICROSEC 1000000 -+#define NANOSEC 1000000000 -+ -+typedef enum { -+ TRUE = -1, -+ FALSE = 0 -+} boolean_t; -+ -+ -+#define DTRACE_ACCESS_KERNEL 0x1 -+ -+#define DTRACE_CRA_PROC 0x0001 -+#define DTRACE_CRA_PROC_CONTROL 0x0002 -+#define DTRACE_CRA_PROC_DESTRUCTIVE_ALLUSER 0x0004 -+#define DTRACE_CRA_PROC_DESTRUCTIVE_CREDCHG 0x0010 -+#define DTRACE_CRA_KERNEL 0x0020 -+#define DTRACE_CRA_KERNEL_DESTRUCTIVE 0x0040 -+ -+#define DTRACE_CRA_ALL (DTRACE_CRA_PROC | \ -+ DTRACE_CRA_PROC_CONTROL | \ -+ DTRACE_CRA_PROC_DESTRUCTIVE_ALLUSER | \ -+ DTRACE_CRA_PROC_DESTRUCTIVE_CREDCHG | \ -+ DTRACE_CRA_KERNEL | \ -+ DTRACE_CRA_KERNEL_DESTRUCTIVE) -+ -+#define DTRACE_CRV_ALLPROC 0x01 -+#define DTRACE_CRV_KERNEL 0x02 -+#define DTRACE_CRV_ALL (DTRACE_CRV_ALLPROC | DTRACE_CRV_KERNEL) -+ -+#define DTRACE_MATCH_FAIL -1 -+#define DTRACE_MATCH_NEXT 0 -+#define DTRACE_MATCH_DONE 1 -+ -+#define DTRACE_COND_OWNER 0x01 -+#define DTRACE_COND_USERMODE 0x02 -+ -+#define P2ROUNDUP(x, a) (-(-(x) & -(a))) -+ -+#if (BITS_PER_LONG == 64) || defined(CONFIG_KTIME_SCALAR) -+#define KTIME_INIT(s, ns) ((s64)(s) * NSEC_PER_SEC + (s64)(ns)) -+#else -+# define KTIME_INIT(n, ns) { .sec = (s), .nsec = (ns) } -+#endif -+#define ktime_lt(t0, t1) (t0 < t1) -+#define ktime_le(t0, t1) (t0 <= t1) -+#define ktime_ge(t0, t1) (t0 >= t1) -+#define ktime_gt(t0, t1) (t0 > t1) -+#define ktime_cp(t0, t1) (t0 = t1) -+ -+/* -+ * Translate between kernel config options and userspace-compatible definitions. -+ */ -+#ifdef CONFIG_64BIT -+#define _LP64 1 -+#endif -+#ifdef __LITTLE_ENDIAN -+#define _LITTLE_ENDIAN 1 -+#endif -+ -+#endif /* _DTRACE_TYPES_H */ -diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h -index bc56287a1ed1395059df7236e6bacdcb2af5d72c..25e7b8778b714ab95962bbe2b5e8b76ecae6bcbc 100644 ---- a/include/linux/cpuhotplug.h -+++ b/include/linux/cpuhotplug.h -@@ -107,6 +107,7 @@ enum cpuhp_state { - CPUHP_AP_IRQ_SIFIVE_PLIC_STARTING, - CPUHP_AP_ARM_MVEBU_COHERENCY, - CPUHP_AP_MICROCODE_LOADER, -+ CPUHP_AP_CYCLIC_STARTING, - CPUHP_AP_PERF_X86_AMD_UNCORE_STARTING, - CPUHP_AP_PERF_X86_STARTING, - CPUHP_AP_PERF_X86_AMD_IBS_STARTING, -diff --git a/include/linux/cyclic.h b/include/linux/cyclic.h -new file mode 100644 -index 0000000000000000000000000000000000000000..12ab85dc185b556ba71f0993937bcb00413dcbfe ---- /dev/null -+++ b/include/linux/cyclic.h -@@ -0,0 +1,49 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+#ifndef _CYCLIC_H_ -+#define _CYCLIC_H_ -+ -+#include <linux/ktime.h> -+#include <linux/types.h> -+ -+#define CY_LOW_LEVEL 0 -+#define CY_LOCK_LEVEL 1 -+#define CY_HIGH_LEVEL 2 -+#define CY_SOFT_LEVELS 2 -+#define CY_LEVELS 3 -+ -+typedef uintptr_t cyclic_id_t; -+typedef uint16_t cyc_level_t; -+typedef void (*cyc_func_t)(uintptr_t); -+ -+#define CYCLIC_NONE ((cyclic_id_t)0) -+ -+struct cyc_handler { -+ cyc_func_t cyh_func; -+ uintptr_t cyh_arg; -+ cyc_level_t cyh_level; -+}; -+ -+#define CY_INTERVAL_INF (-1) -+ -+struct cyc_time { -+ ktime_t cyt_when; -+ ktime_t cyt_interval; -+}; -+ -+struct cyc_omni_handler { -+ void (*cyo_online)(void *, uint32_t, struct cyc_handler *, -+ struct cyc_time *); -+ void (*cyo_offline)(void *, uint32_t, void *); -+ void *cyo_arg; -+}; -+ -+extern cyclic_id_t cyclic_add(struct cyc_handler *, struct cyc_time *); -+extern cyclic_id_t cyclic_add_omni(struct cyc_omni_handler *); -+extern void cyclic_remove(cyclic_id_t); -+extern void cyclic_reprogram(cyclic_id_t, ktime_t); -+ -+#endif /* _CYCLIC_H_ */ -diff --git a/include/linux/dtrace/cpu_defines.h b/include/linux/dtrace/cpu_defines.h -new file mode 100644 -index 0000000000000000000000000000000000000000..c8719378da80dd9293e92abe4713ab395b3b6db1 ---- /dev/null -+++ b/include/linux/dtrace/cpu_defines.h -@@ -0,0 +1,61 @@ -+/* Copyright (C) 2011-2014 Oracle, Inc. */ -+ -+#ifndef _LINUX_DTRACE_CPU_DEFINES_H_ -+#define _LINUX_DTRACE_CPU_DEFINES_H_ -+ -+#include <linux/percpu.h> -+ -+#define CPUC_SIZE (sizeof (uint16_t) + sizeof(uint8_t) + \ -+ sizeof(uintptr_t) + sizeof(struct mutex)) -+#define CPUC_PADSIZE (192 - CPUC_SIZE) -+ -+#define per_cpu_core(cpu) (&per_cpu(dtrace_cpu_core, (cpu))) -+#if 0 -+# define this_cpu_core (this_cpu_ptr(&dtrace_cpu_core)) -+#else -+# define this_cpu_core (per_cpu_core(smp_processor_id())) -+#endif -+ -+#define DTRACE_CPUFLAG_ISSET(flag) \ -+ (this_cpu_core->cpuc_dtrace_flags & (flag)) -+ -+#define DTRACE_CPUFLAG_SET(flag) \ -+ (this_cpu_core->cpuc_dtrace_flags |= (flag)) -+ -+#define DTRACE_CPUFLAG_CLEAR(flag) \ -+ (this_cpu_core->cpuc_dtrace_flags &= ~(flag)) -+ -+#define CPU_DTRACE_NOFAULT 0x0001 -+#define CPU_DTRACE_DROP 0x0002 -+#define CPU_DTRACE_BADADDR 0x0004 -+#define CPU_DTRACE_BADALIGN 0x0008 -+#define CPU_DTRACE_DIVZERO 0x0010 -+#define CPU_DTRACE_ILLOP 0x0020 -+#define CPU_DTRACE_NOSCRATCH 0x0040 -+#define CPU_DTRACE_KPRIV 0x0080 -+#define CPU_DTRACE_UPRIV 0x0100 -+#define CPU_DTRACE_TUPOFLOW 0x0200 -+#define CPU_DTRACE_ENTRY 0x0800 -+#define CPU_DTRACE_BADSTACK 0x1000 -+#define CPU_DTRACE_NOPF 0x2000 -+#define CPU_DTRACE_PF_TRAPPED 0x4000 -+ -+#define CPU_DTRACE_FAULT (CPU_DTRACE_BADADDR | CPU_DTRACE_BADALIGN | \ -+ CPU_DTRACE_DIVZERO | CPU_DTRACE_ILLOP | \ -+ CPU_DTRACE_NOSCRATCH | CPU_DTRACE_KPRIV | \ -+ CPU_DTRACE_UPRIV | CPU_DTRACE_TUPOFLOW | \ -+ CPU_DTRACE_BADSTACK | CPU_DTRACE_PF_TRAPPED) -+#define CPU_DTRACE_ERROR (CPU_DTRACE_FAULT | CPU_DTRACE_DROP) -+ -+typedef uint32_t processorid_t; -+typedef uint32_t psetid_t; -+typedef uint32_t chipid_t; -+typedef uint32_t lgrp_id_t; -+ -+struct cpu_core; -+struct cpuinfo; -+ -+#define per_cpu_info(cpu) (&per_cpu(dtrace_cpu_info, (cpu))) -+#define this_cpu_info (this_cpu_ptr(&dtrace_cpu_info)) -+ -+#endif /* _LINUX_DTRACE_CPU_DEFINES_H_ */ -diff --git a/include/linux/dtrace_cpu.h b/include/linux/dtrace_cpu.h -new file mode 100644 -index 0000000000000000000000000000000000000000..6b3dc7219f49d3bbadcb16a6939c1a98d520ecf2 ---- /dev/null -+++ b/include/linux/dtrace_cpu.h -@@ -0,0 +1,53 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+#ifndef _LINUX_DTRACE_CPU_H_ -+#define _LINUX_DTRACE_CPU_H_ -+ -+#ifdef CONFIG_DTRACE -+ -+#include <linux/ktime.h> -+#include <linux/mutex.h> -+#include <linux/spinlock.h> -+#include <linux/dtrace_types.h> -+#include <linux/dtrace_cpu_defines.h> -+#include <asm/dtrace_cpuinfo.h> -+ -+struct cpu_core { -+ uint16_t cpuc_dtrace_flags; -+ uint8_t cpuc_dcpc_intr_state; -+ uint8_t cpuc_pad[CPUC_PADSIZE]; -+ uintptr_t cpuc_dtrace_illval; -+ struct mutex cpuc_pid_lock; -+ -+ uintptr_t cpu_dtrace_caller; -+ struct pt_regs *cpu_dtrace_regs; -+ ktime_t cpu_dtrace_chillmark; -+ ktime_t cpu_dtrace_chilled; -+ rwlock_t cpu_ft_lock; -+ atomic64_t cpuc_sync_requests; -+ atomic64_t cpuc_in_probe_ctx; -+ dtrace_id_t cpuc_current_probe; -+}; -+ -+DECLARE_PER_CPU_SHARED_ALIGNED(struct cpu_core, dtrace_cpu_core); -+ -+struct cpuinfo { -+ processorid_t cpu_id; -+ psetid_t cpu_pset; -+ chipid_t cpu_chip; -+ lgrp_id_t cpu_lgrp; -+ cpuinfo_arch_t *cpu_info; -+}; -+ -+DECLARE_PER_CPU_SHARED_ALIGNED(struct cpuinfo, dtrace_cpu_info); -+ -+/* ABI requirement: type names compiled into DTrace userspace. */ -+typedef struct cpuinfo cpuinfo_t; -+ -+extern void dtrace_cpu_init(void); -+ -+#endif /* CONFIG_DTRACE */ -+#endif /* _LINUX_DTRACE_CPU_H_ */ -diff --git a/include/linux/dtrace_cpu_defines.h b/include/linux/dtrace_cpu_defines.h -new file mode 100644 -index 0000000000000000000000000000000000000000..f5866a6e95b8e4a0e39efb926aa4357842112b0e ---- /dev/null -+++ b/include/linux/dtrace_cpu_defines.h -@@ -0,0 +1,2 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+#include <linux/dtrace/cpu_defines.h> -diff --git a/include/linux/dtrace_os.h b/include/linux/dtrace_os.h -new file mode 100644 -index 0000000000000000000000000000000000000000..5bcd77e08a14e8502cbadb53004dbbeb711dc953 ---- /dev/null -+++ b/include/linux/dtrace_os.h -@@ -0,0 +1,120 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+#ifndef _LINUX_DTRACE_OS_H_ -+#define _LINUX_DTRACE_OS_H_ -+ -+#ifndef HEADERS_CHECK -+ -+#ifdef CONFIG_DTRACE -+ -+#include <linux/ktime.h> -+#include <linux/mm.h> -+#include <linux/notifier.h> -+#include <linux/timekeeper_internal.h> -+#include <asm/unistd.h> -+#include <linux/dtrace_cpu.h> -+#include <linux/dtrace_task.h> -+#include <linux/dtrace_psinfo.h> -+ -+extern struct module *dtrace_kmod; -+ -+extern void __init dtrace_os_init(void); -+extern void __init dtrace_psinfo_os_init(void); -+extern void __init dtrace_task_os_init(void); -+ -+extern void dtrace_mod_pdata_alloc(struct module *); -+extern void dtrace_mod_pdata_free(struct module *); -+extern int dtrace_destroy_prov(struct module *); -+ -+extern int dtrace_enable(void); -+extern void dtrace_disable(void); -+ -+extern ktime_t dtrace_gethrtime(void); -+extern ktime_t dtrace_getwalltime(void); -+ -+enum dtrace_vtime_state { -+ DTRACE_VTIME_INACTIVE = 0, -+ DTRACE_VTIME_ACTIVE -+}; -+ -+extern enum dtrace_vtime_state dtrace_vtime_active; -+ -+typedef void for_each_module_fn(void *, struct module *); -+extern void dtrace_for_each_module(for_each_module_fn *fn, void *arg); -+ -+extern void dtrace_update_time(struct timekeeper *); -+extern ktime_t dtrace_get_walltime(void); -+ -+extern void dtrace_vtime_enable(void); -+extern void dtrace_vtime_disable(void); -+extern void dtrace_vtime_switch(struct task_struct *, struct task_struct *); -+ -+#include <asm/dtrace_util.h> -+ -+extern int dtrace_instr_size(const asm_instr_t *); -+ -+extern int dtrace_die_notifier(struct notifier_block *, unsigned long, void *); -+ -+#define STACKTRACE_KERNEL 0x01 -+#define STACKTRACE_USER 0x02 -+#define STACKTRACE_TYPE 0x0f -+ -+struct stacktrace_state { -+ uint64_t *pcs; -+ uint64_t *fps; -+ int limit; -+ int depth; -+ int flags; -+}; -+ -+extern void dtrace_stacktrace(struct stacktrace_state *); -+extern void dtrace_user_stacktrace(struct stacktrace_state *); -+extern void dtrace_handle_badaddr(struct pt_regs *); -+extern void dtrace_mod_pdata_init(struct dtrace_module *pdata); -+extern void dtrace_mod_pdata_cleanup(struct dtrace_module *pdata); -+ -+/* -+ * This is only safe to call if we know this is a userspace fault -+ * or that the call happens after early boot. -+ */ -+static inline int dtrace_no_pf(struct pt_regs *regs) -+{ -+ if (unlikely(DTRACE_CPUFLAG_ISSET(CPU_DTRACE_NOFAULT))) { -+ dtrace_handle_badaddr(regs); -+ return 1; -+ } -+ -+ return 0; -+} -+ -+extern void (*dtrace_helpers_cleanup)(struct task_struct *); -+extern void (*dtrace_helpers_fork)(struct task_struct *, struct task_struct *); -+ -+#else -+ -+/* -+ * See arch/x86/mm/fault.c. -+ */ -+ -+#define dtrace_no_pf(ignore) 0 -+ -+/* -+ * See kernel/timekeeper.c -+ */ -+#define dtrace_update_time(ignore) -+ -+/* -+ * See kernel/dtrace/dtrace_os.c -+ */ -+#define dtrace_mod_pdata_alloc(ignore) -+#define dtrace_mod_pdata_free(ignore) -+#define dtrace_destroy_prov(ignore) 1 -+ -+#endif /* CONFIG_DTRACE */ -+ -+#endif /* !HEADERS_CHECK */ -+ -+#endif /* _LINUX_DTRACE_OS_H_ */ -diff --git a/include/linux/dtrace_psinfo.h b/include/linux/dtrace_psinfo.h -new file mode 100644 -index 0000000000000000000000000000000000000000..53a9c317a8a34f84927868b339904047cdf98ef1 ---- /dev/null -+++ b/include/linux/dtrace_psinfo.h -@@ -0,0 +1,59 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+#ifndef _LINUX_DTRACE_PSINFO_H_ -+#define _LINUX_DTRACE_PSINFO_H_ -+ -+#ifdef CONFIG_DTRACE -+ -+#define PR_PSARGS_SZ 80 -+#define PR_ARGV_SZ 512 -+#define PR_ENVP_SZ 512 -+ -+/* -+ * DTrace's per-process info (per-tgid). -+ * -+ * All threads in a process share the same structure instance. -+ */ -+struct dtrace_psinfo { -+ atomic_t dtps_usage; -+ unsigned long dtps_argc; -+ char **dtps_argv; -+ unsigned long dtps_envc; -+ char **dtps_envp; -+ char dtps_psargs[PR_PSARGS_SZ]; -+}; -+ -+/* -+ * DTrace psinfo API. Requires struct dtrace_task as its argument. -+ */ -+ -+extern void dtrace_psinfo_alloc(struct task_struct *); -+extern void dtrace_psinfo_free(struct dtrace_psinfo *); -+ -+static inline void dtrace_psinfo_get(struct dtrace_psinfo *psinfo) -+{ -+ if (likely(psinfo)) -+ atomic_inc(&(psinfo)->dtps_usage); -+} -+ -+static inline void dtrace_psinfo_put(struct dtrace_psinfo *psinfo) -+{ -+ if (likely((psinfo))) { -+ if (atomic_dec_and_test(&(psinfo)->dtps_usage)) -+ dtrace_psinfo_free(psinfo); -+ } -+} -+ -+#else /* CONFIG_DTRACE */ -+ -+#define dtrace_psinfo_alloc(ignore) -+#define dtrace_psinfo_free(ignore) -+#define dtrace_psinfo_get(ignore) -+#define dtrace_psinfo_put(ignore) -+ -+#endif /* CONFIG_DTRACE */ -+ -+#endif /* _LINUX_DTRACE_PSINFO_H_ */ -diff --git a/include/linux/dtrace_task.h b/include/linux/dtrace_task.h -new file mode 100644 -index 0000000000000000000000000000000000000000..ce7111223788a8b7d0c43e96a8da6ef042263b61 ---- /dev/null -+++ b/include/linux/dtrace_task.h -@@ -0,0 +1,38 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+#ifndef _LINUX_DTRACE_TASK_H_ -+#define _LINUX_DTRACE_TASK_H_ -+ -+#ifdef CONFIG_DTRACE -+ -+#include <linux/sched.h> -+ -+/* -+ * Opaque handle for per-task data. -+ */ -+struct dtrace_task; -+ -+/* -+ * DTrace's kernel API for per-task data manipulation. -+ */ -+ -+extern void dtrace_task_init(struct task_struct *); -+extern void dtrace_task_exec(struct task_struct *); -+extern void dtrace_task_copy(struct task_struct *, struct task_struct *); -+extern void dtrace_task_free(struct task_struct *); -+extern void dtrace_task_dup(struct task_struct *, struct task_struct *); -+ -+#else /* CONFIG_DTRACE */ -+ -+#define dtrace_task_init(ignore) -+#define dtrace_task_exec(ignore) -+#define dtrace_task_copy(ignore1, ignore2) -+#define dtrace_task_free(ignore) -+#define dtrace_task_dup(ignore1, ignore2) -+ -+#endif /* CONFIG_DTRACE */ -+ -+#endif /* _LINUX_DTRACE_TASK_H_ */ -diff --git a/include/linux/dtrace_task_impl.h b/include/linux/dtrace_task_impl.h -new file mode 100644 -index 0000000000000000000000000000000000000000..2f76b475c2f88822c5e5e69bab1f17364ae81a3e ---- /dev/null -+++ b/include/linux/dtrace_task_impl.h -@@ -0,0 +1,28 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. -+ */ -+#ifndef _LINUX_DTRACE_TASK_IMPL_H_ -+#define _LINUX_DTRACE_TASK_IMPL_H_ -+ -+#ifdef CONFIG_DTRACE -+ -+#include <linux/dtrace_task.h> -+#include <linux/dtrace_psinfo.h> -+ -+struct dtrace_task { -+ uint32_t dt_predcache; -+ ktime_t dt_vtime; -+ ktime_t dt_start; -+ uint8_t dt_stop; -+ uint8_t dt_sig; -+ struct dtrace_psinfo *dt_psinfo; -+ void *dt_helpers; -+ uint32_t dt_probes; -+ uint64_t dt_tp_count; -+ void *dt_ustack; -+}; -+ -+#endif /* CONFIG_DTRACE */ -+#endif /* _LINUX_DTRACE_TASK_IMPL_H_ */ -+ -diff --git a/include/linux/dtrace_types.h b/include/linux/dtrace_types.h -new file mode 100644 -index 0000000000000000000000000000000000000000..4484dc58e188c0c5ffe0495b8dc351405b3f945f ---- /dev/null -+++ b/include/linux/dtrace_types.h -@@ -0,0 +1,13 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+#ifndef _DTRACE_TYPES_H_ -+#define _DTRACE_TYPES_H_ -+ -+typedef uint32_t dtrace_id_t; -+ -+#define DTRACE_IDNONE 0 -+ -+#endif /* _DTRACE_TYPES_H_ */ -diff --git a/include/linux/ktime.h b/include/linux/ktime.h -index a12b5523cc18e699fea0f36ca49b65dbfdfeb015..ba226005fd2ad641b70163e2d5f49753b64760d0 100644 ---- a/include/linux/ktime.h -+++ b/include/linux/ktime.h -@@ -156,6 +156,14 @@ static inline s64 ktime_divns(const ktime_t kt, s64 div) - } - #endif - -+/* -+ * ktime_nz - Check whether a ktime_v variable is non-zero -+ */ -+static inline int ktime_nz(const ktime_t kt) -+{ -+ return kt != 0LL; -+} -+ - static inline s64 ktime_to_us(const ktime_t kt) - { - return ktime_divns(kt, NSEC_PER_USEC); -diff --git a/include/linux/module.h b/include/linux/module.h -index d44fe50d7c7fec29c95e8b07865201410216d9d3..44915ed85337f8ef9931afaee5b78f9961ac112e 100644 ---- a/include/linux/module.h -+++ b/include/linux/module.h -@@ -512,6 +512,9 @@ struct module { - struct klp_modinfo *klp_info; - #endif - -+#ifdef CONFIG_DTRACE -+ void *pdata; -+#endif - #ifdef CONFIG_MODULE_UNLOAD - /* What modules depend on me? */ - struct list_head source_list; -diff --git a/include/linux/mutex.h b/include/linux/mutex.h -index dcd185cbfe793b6f9d325dfabd6db87297d32383..bb18028db361585e6ed56b1b90853c006282e727 100644 ---- a/include/linux/mutex.h -+++ b/include/linux/mutex.h -@@ -20,6 +20,10 @@ - #include <linux/osq_lock.h> - #include <linux/debug_locks.h> - -+#ifdef CONFIG_SMP -+# include <asm/current.h> -+#endif -+ - struct ww_acquire_ctx; - - /* -@@ -224,4 +228,16 @@ enum mutex_trylock_recursive_enum { - extern /* __deprecated */ __must_check enum mutex_trylock_recursive_enum - mutex_trylock_recursive(struct mutex *lock); - -+#if defined(CONFIG_DEBUG_MUTEXES) || defined(CONFIG_SMP) -+static inline int mutex_owned(struct mutex *lock) -+{ -+ return mutex_is_locked(lock) && __mutex_owner(lock) == current; -+} -+#else -+static inline int mutex_owned(struct mutex *lock) -+{ -+ return mutex_is_locked(lock); -+} -+#endif -+ - #endif /* __LINUX_MUTEX_H */ -diff --git a/include/linux/rwlock.h b/include/linux/rwlock.h -index 3dcd617e65ae902316399b0717f0dc0e834b355c..a7e72774f17eb9040d7ba0ac26c8efcf10f69087 100644 ---- a/include/linux/rwlock.h -+++ b/include/linux/rwlock.h -@@ -59,6 +59,13 @@ do { \ - # define do_raw_write_unlock(rwlock) do {arch_write_unlock(&(rwlock)->raw_lock); __release(lock); } while (0) - #endif - -+#ifdef CONFIG_DTRACE -+#define peek_read_can_lock(rwlock) \ -+ arch_peek_read_can_lock(&(rwlock)->raw_lock) -+#define peek_write_can_lock(rwlock) \ -+ arch_peek_write_can_lock(&(rwlock)->raw_lock) -+#endif /* CONFIG_DTRACE */ -+ - /* - * Define the various rw_lock methods. Note we define these - * regardless of whether CONFIG_SMP or CONFIG_PREEMPT are set. The various -diff --git a/include/linux/sched.h b/include/linux/sched.h -index 76cd21fa55016e5e8ab7a09cec3d1516a18f5998..0be45d97998922eea294cb95dc269a761fda79fb 100644 ---- a/include/linux/sched.h -+++ b/include/linux/sched.h -@@ -34,6 +34,7 @@ - #include <linux/rseq.h> - #include <linux/seqlock.h> - #include <linux/kcsan.h> -+#include <linux/dtrace_task.h> - - /* task_struct member predeclarations (sorted alphabetically): */ - struct audit_context; -@@ -1304,6 +1305,9 @@ struct task_struct { - struct request_queue *throttle_queue; - #endif - -+#ifdef CONFIG_DTRACE -+ struct dtrace_task *dt_task; -+#endif - #ifdef CONFIG_UPROBES - struct uprobe_task *utask; - #endif -diff --git a/include/linux/spinlock_up.h b/include/linux/spinlock_up.h -index 0ac9112c1bbe3287658057098c37a67bc818c559..cfd00c13f2aa1bc08f6b7c8b79449edbdf0681b2 100644 ---- a/include/linux/spinlock_up.h -+++ b/include/linux/spinlock_up.h -@@ -69,4 +69,9 @@ static inline void arch_spin_unlock(arch_spinlock_t *lock) - - #define arch_spin_is_contended(lock) (((void)(lock), 0)) - -+#ifdef CONFIG_DTRACE -+#define arch_peek_read_can_lock(lock) (((void)(lock), 1)) -+#define arch_peek_write_can_lock(lock) (((void)(lock), 1)) -+#endif /* CONFIG_DTRACE */ -+ - #endif /* __LINUX_SPINLOCK_UP_H */ -diff --git a/include/uapi/linux/dtrace/Kbuild b/include/uapi/linux/dtrace/Kbuild -new file mode 100644 -index 0000000000000000000000000000000000000000..0cb5b941b72b292cd03a0df30844aa9e35c5d768 ---- /dev/null -+++ b/include/uapi/linux/dtrace/Kbuild -@@ -0,0 +1,35 @@ -+# UAPI Header export list -+header-y += actions_defines.h -+header-y += actions.h -+header-y += arg_defines.h -+header-y += arg.h -+header-y += buffer_defines.h -+header-y += buffer.h -+header-y += conf_defines.h -+header-y += conf.h -+header-y += cpu_defines.h -+header-y += dif_defines.h -+header-y += dif.h -+header-y += difo_defines.h -+header-y += difo.h -+header-y += dof_defines.h -+header-y += dof.h -+header-y += dtrace.h -+header-y += enabling_defines.h -+header-y += enabling.h -+header-y += fasttrap_defines.h -+header-y += fasttrap.h -+header-y += fasttrap_ioctl.h -+header-y += faults_defines.h -+header-y += faults.h -+header-y += helpers_defines.h -+header-y += helpers.h -+header-y += ioctl.h -+header-y += metadesc_defines.h -+header-y += metadesc.h -+header-y += options_defines.h -+header-y += options.h -+header-y += stability_defines.h -+header-y += stability.h -+header-y += status.h -+header-y += universal.h -diff --git a/include/uapi/linux/dtrace/actions.h b/include/uapi/linux/dtrace/actions.h -new file mode 100644 -index 0000000000000000000000000000000000000000..9b47343271babcf501645d2b3c86b130987f13a1 ---- /dev/null -+++ b/include/uapi/linux/dtrace/actions.h -@@ -0,0 +1,14 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+#ifndef _LINUX_DTRACE_ACTIONS_H -+#define _LINUX_DTRACE_ACTIONS_H -+ -+#include <linux/dtrace/actions_defines.h> -+ -+#endif /* _LINUX_DTRACE_ACTIONS_H */ -diff --git a/include/uapi/linux/dtrace/actions_defines.h b/include/uapi/linux/dtrace/actions_defines.h -new file mode 100644 -index 0000000000000000000000000000000000000000..4512c291f58a75d05fc97567137ead42092c8454 ---- /dev/null -+++ b/include/uapi/linux/dtrace/actions_defines.h -@@ -0,0 +1,181 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_ACTIONS_DEFINES_H -+#define _LINUX_DTRACE_ACTIONS_DEFINES_H -+ -+#include <linux/dtrace/universal.h> -+ -+/* -+ * The upper byte determines the class of the action; the low bytes determines -+ * the specific action within that class. The classes of actions are as -+ * follows: -+ * -+ * [ no class ] <= May record process- or kernel-related data -+ * DTRACEACT_PROC <= Only records process-related data -+ * DTRACEACT_PROC_DESTRUCTIVE <= Potentially destructive to processes -+ * DTRACEACT_KERNEL <= Only records kernel-related data -+ * DTRACEACT_KERNEL_DESTRUCTIVE <= Potentially destructive to the kernel -+ * DTRACEACT_SPECULATIVE <= Speculation-related action -+ * DTRACEACT_AGGREGATION <= Aggregating action -+ */ -+#define DTRACEACT_NONE 0 /* no action */ -+#define DTRACEACT_DIFEXPR 1 /* action is DIF expression */ -+#define DTRACEACT_EXIT 2 /* exit() action */ -+#define DTRACEACT_PRINTF 3 /* printf() action */ -+#define DTRACEACT_PRINTA 4 /* printa() action */ -+#define DTRACEACT_LIBACT 5 /* library-controlled action */ -+#define DTRACEACT_TRACEMEM 6 /* tracemem() action */ -+#define DTRACEACT_PCAP 7 /* pcap() action */ -+ -+#define DTRACEACT_PROC 0x0100 -+#define DTRACEACT_USTACK (DTRACEACT_PROC + 1) -+#define DTRACEACT_JSTACK (DTRACEACT_PROC + 2) -+#define DTRACEACT_USYM (DTRACEACT_PROC + 3) -+#define DTRACEACT_UMOD (DTRACEACT_PROC + 4) -+#define DTRACEACT_UADDR (DTRACEACT_PROC + 5) -+ -+#define DTRACEACT_PROC_DESTRUCTIVE 0x0200 -+#define DTRACEACT_STOP (DTRACEACT_PROC_DESTRUCTIVE + 1) -+#define DTRACEACT_RAISE (DTRACEACT_PROC_DESTRUCTIVE + 2) -+#define DTRACEACT_SYSTEM (DTRACEACT_PROC_DESTRUCTIVE + 3) -+#define DTRACEACT_FREOPEN (DTRACEACT_PROC_DESTRUCTIVE + 4) -+ -+#define DTRACEACT_PROC_CONTROL 0x0300 -+ -+#define DTRACEACT_KERNEL 0x0400 -+#define DTRACEACT_STACK (DTRACEACT_KERNEL + 1) -+#define DTRACEACT_SYM (DTRACEACT_KERNEL + 2) -+#define DTRACEACT_MOD (DTRACEACT_KERNEL + 3) -+ -+#define DTRACEACT_KERNEL_DESTRUCTIVE 0x0500 -+#define DTRACEACT_BREAKPOINT (DTRACEACT_KERNEL_DESTRUCTIVE + 1) -+#define DTRACEACT_PANIC (DTRACEACT_KERNEL_DESTRUCTIVE + 2) -+#define DTRACEACT_CHILL (DTRACEACT_KERNEL_DESTRUCTIVE + 3) -+ -+#define DTRACEACT_SPECULATIVE 0x0600 -+#define DTRACEACT_SPECULATE (DTRACEACT_SPECULATIVE + 1) -+#define DTRACEACT_COMMIT (DTRACEACT_SPECULATIVE + 2) -+#define DTRACEACT_DISCARD (DTRACEACT_SPECULATIVE + 3) -+ -+#define DTRACEACT_CLASS(x) ((x) & 0xff00) -+ -+#define DTRACEACT_ISAGG(x) \ -+ (DTRACEACT_CLASS(x) == DTRACEACT_AGGREGATION) -+ -+#define DTRACEACT_ISDESTRUCTIVE(x) \ -+ (DTRACEACT_CLASS(x) == DTRACEACT_PROC_DESTRUCTIVE || \ -+ DTRACEACT_CLASS(x) == DTRACEACT_KERNEL_DESTRUCTIVE) -+ -+#define DTRACEACT_ISSPECULATIVE(x) \ -+ (DTRACEACT_CLASS(x) == DTRACEACT_SPECULATIVE) -+ -+#define DTRACEACT_ISPRINTFLIKE(x) \ -+ ((x) == DTRACEACT_PRINTF || (x) == DTRACEACT_PRINTA || \ -+ (x) == DTRACEACT_SYSTEM || (x) == DTRACEACT_FREOPEN) -+ -+/* -+ * DTrace Aggregating Actions -+ * -+ * These are functions f(x) for which the following is true: -+ * -+ * f(f(x_0) U f(x_1) U ... U f(x_n)) = f(x_0 U x_1 U ... U x_n) -+ * -+ * where x_n is a set of arbitrary data. Aggregating actions are in their own -+ * DTrace action class, DTTRACEACT_AGGREGATION. The macros provided here allow -+ * for easier processing of the aggregation argument and data payload for a few -+ * aggregating actions (notably: quantize(), lquantize(), and ustack()). -+ */ -+ -+#define DTRACEACT_AGGREGATION 0x0700 -+#define DTRACEAGG_COUNT (DTRACEACT_AGGREGATION + 1) -+#define DTRACEAGG_MIN (DTRACEACT_AGGREGATION + 2) -+#define DTRACEAGG_MAX (DTRACEACT_AGGREGATION + 3) -+#define DTRACEAGG_AVG (DTRACEACT_AGGREGATION + 4) -+#define DTRACEAGG_SUM (DTRACEACT_AGGREGATION + 5) -+#define DTRACEAGG_STDDEV (DTRACEACT_AGGREGATION + 6) -+#define DTRACEAGG_QUANTIZE (DTRACEACT_AGGREGATION + 7) -+#define DTRACEAGG_LQUANTIZE (DTRACEACT_AGGREGATION + 8) -+#define DTRACEAGG_LLQUANTIZE (DTRACEACT_AGGREGATION + 9) -+ -+#define DTRACE_QUANTIZE_NBUCKETS \ -+ (((sizeof(uint64_t) * NBBY) - 1) * 2 + 1) -+ -+#define DTRACE_QUANTIZE_ZEROBUCKET ((sizeof(uint64_t) * NBBY) - 1) -+ -+#define DTRACE_QUANTIZE_BUCKETVAL(buck) \ -+ (int64_t)((buck) < DTRACE_QUANTIZE_ZEROBUCKET ? \ -+ -(1LL << (DTRACE_QUANTIZE_ZEROBUCKET - 1 - (buck))) : \ -+ (buck) == DTRACE_QUANTIZE_ZEROBUCKET ? 0 : \ -+ 1LL << ((buck) - DTRACE_QUANTIZE_ZEROBUCKET - 1)) -+ -+#define DTRACE_LQUANTIZE_STEPSHIFT 48 -+#define DTRACE_LQUANTIZE_STEPMASK ((uint64_t)UINT16_MAX << 48) -+#define DTRACE_LQUANTIZE_LEVELSHIFT 32 -+#define DTRACE_LQUANTIZE_LEVELMASK ((uint64_t)UINT16_MAX << 32) -+#define DTRACE_LQUANTIZE_BASESHIFT 0 -+#define DTRACE_LQUANTIZE_BASEMASK UINT32_MAX -+ -+#define DTRACE_LQUANTIZE_STEP(x) \ -+ (uint16_t)(((x) & DTRACE_LQUANTIZE_STEPMASK) >> \ -+ DTRACE_LQUANTIZE_STEPSHIFT) -+ -+#define DTRACE_LQUANTIZE_LEVELS(x) \ -+ (uint16_t)(((x) & DTRACE_LQUANTIZE_LEVELMASK) >> \ -+ DTRACE_LQUANTIZE_LEVELSHIFT) -+ -+#define DTRACE_LQUANTIZE_BASE(x) \ -+ (int32_t)(((x) & DTRACE_LQUANTIZE_BASEMASK) >> \ -+ DTRACE_LQUANTIZE_BASESHIFT) -+ -+#define DTRACE_LLQUANTIZE_STEPSSHIFT 48 -+#define DTRACE_LLQUANTIZE_STEPSMASK ((uint64_t)UINT16_MAX << 48) -+#define DTRACE_LLQUANTIZE_HMAGSHIFT 32 -+#define DTRACE_LLQUANTIZE_HMAGMASK ((uint64_t)UINT16_MAX << 32) -+#define DTRACE_LLQUANTIZE_LMAGSHIFT 16 -+#define DTRACE_LLQUANTIZE_LMAGMASK ((uint64_t)UINT16_MAX << 16) -+#define DTRACE_LLQUANTIZE_FACTORSHIFT 0 -+#define DTRACE_LLQUANTIZE_FACTORMASK UINT16_MAX -+ -+#define DTRACE_LLQUANTIZE_STEPS(x) \ -+ (uint16_t)(((x) & DTRACE_LLQUANTIZE_STEPSMASK) >> \ -+ DTRACE_LLQUANTIZE_STEPSSHIFT) -+ -+#define DTRACE_LLQUANTIZE_HMAG(x) \ -+ (uint16_t)(((x) & DTRACE_LLQUANTIZE_HMAGMASK) >> \ -+ DTRACE_LLQUANTIZE_HMAGSHIFT) -+ -+#define DTRACE_LLQUANTIZE_LMAG(x) \ -+ (uint16_t)(((x) & DTRACE_LLQUANTIZE_LMAGMASK) >> \ -+ DTRACE_LLQUANTIZE_LMAGSHIFT) -+ -+#define DTRACE_LLQUANTIZE_FACTOR(x) \ -+ (uint16_t)(((x) & DTRACE_LLQUANTIZE_FACTORMASK) >> \ -+ DTRACE_LLQUANTIZE_FACTORSHIFT) -+ -+#define DTRACE_USTACK_NFRAMES(x) (uint32_t)((x) & UINT32_MAX) -+#define DTRACE_USTACK_STRSIZE(x) (uint32_t)((x) >> 32) -+#define DTRACE_USTACK_ARG(x, y) \ -+ ((((uint64_t)(y)) << 32) | ((x) & UINT32_MAX)) -+ -+#ifndef _LP64 -+# ifndef _LITTLE_ENDIAN -+# define DTRACE_PTR(type, name) uint32_t name##pad; type *name -+# else -+# define DTRACE_PTR(type, name) type *name; uint32_t name##pad -+# endif -+#else -+# define DTRACE_PTR(type, name) type *name -+#endif -+ -+#endif /* _LINUX_DTRACE_ACTIONS_DEFINES_H */ -diff --git a/include/uapi/linux/dtrace/arg.h b/include/uapi/linux/dtrace/arg.h -new file mode 100644 -index 0000000000000000000000000000000000000000..4a9099a816e6d3576cd93eb5bccb4f2de98907c2 ---- /dev/null -+++ b/include/uapi/linux/dtrace/arg.h -@@ -0,0 +1,42 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_ARG_H -+#define _LINUX_DTRACE_ARG_H -+ -+#include <linux/dtrace/universal.h> -+#include <linux/dtrace/arg_defines.h> -+ -+/* -+ * Because it would waste both space and time, argument types do not reside -+ * with the probe. In order to determine argument types for args[X] -+ * variables, the D compiler queries for argument types on a probe-by-probe -+ * basis. (This optimizes for the common case that arguments are either not -+ * used or used in an untyped fashion.) Typed arguments are specified with a -+ * string of the type name in the dtragd_native member of the argument -+ * description structure. Typed arguments may be further translated to types -+ * of greater stability; the provider indicates such a translated argument by -+ * filling in the dtargd_xlate member with the string of the translated type. -+ * Finally, the provider may indicate which argument value a given argument -+ * maps to by setting the dtargd_mapping member -- allowing a single argument -+ * to map to multiple args[X] variables. -+ */ -+typedef struct dtrace_argdesc { -+ dtrace_id_t dtargd_id; -+ int dtargd_ndx; -+ int dtargd_mapping; -+ char dtargd_native[DTRACE_ARGTYPELEN]; -+ char dtargd_xlate[DTRACE_ARGTYPELEN]; -+} dtrace_argdesc_t; -+ -+#endif /* _LINUX_DTRACE_ARG_H */ -diff --git a/include/uapi/linux/dtrace/arg_defines.h b/include/uapi/linux/dtrace/arg_defines.h -new file mode 100644 -index 0000000000000000000000000000000000000000..72862cd1b8e6dccee6803955deb15f8d897187e4 ---- /dev/null -+++ b/include/uapi/linux/dtrace/arg_defines.h -@@ -0,0 +1,21 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_ARG_DEFINES_H -+#define _LINUX_DTRACE_ARG_DEFINES_H -+ -+#include <linux/dtrace/universal.h> -+ -+struct dtrace_argdesc; -+ -+#endif /* _LINUX_DTRACE_ARG_DEFINES_H */ -diff --git a/include/uapi/linux/dtrace/buffer.h b/include/uapi/linux/dtrace/buffer.h -new file mode 100644 -index 0000000000000000000000000000000000000000..9bbbc4f1f14bb3835e2fefbe432fd32e8f527090 ---- /dev/null -+++ b/include/uapi/linux/dtrace/buffer.h -@@ -0,0 +1,43 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_BUFFER_H -+#define _LINUX_DTRACE_BUFFER_H -+ -+#include <linux/dtrace/universal.h> -+#include <linux/dtrace/actions_defines.h> -+#include <linux/dtrace/buffer_defines.h> -+ -+/* -+ * In order to get a snapshot of the principal or aggregation buffer, -+ * user-level passes a buffer description to the kernel with the dtrace_bufdesc -+ * structure. This describes which CPU user-level is interested in, and -+ * where user-level wishes the kernel to snapshot the buffer to (the -+ * dtbd_data field). The kernel uses the same structure to pass back some -+ * information regarding the buffer: the size of data actually copied out, the -+ * number of drops, the number of errors, and the offset of the oldest record. -+ * If the buffer policy is a "switch" policy, taking a snapshot of the -+ * principal buffer has the additional effect of switching the active and -+ * inactive buffers. Taking a snapshot of the aggregation buffer _always_ has -+ * the additional effect of switching the active and inactive buffers. -+ */ -+typedef struct dtrace_bufdesc { -+ uint64_t dtbd_size; /* size of buffer */ -+ uint32_t dtbd_cpu; /* CPU or DTRACE_CPUALL */ -+ uint32_t dtbd_errors; /* number of errors */ -+ uint64_t dtbd_drops; /* number of drops */ -+ DTRACE_PTR(char, dtbd_data); /* data */ -+ uint64_t dtbd_oldest; /* offset of oldest record */ -+} dtrace_bufdesc_t; -+ -+#endif /* _LINUX_DTRACE_BUFFER_H */ -diff --git a/include/uapi/linux/dtrace/buffer_defines.h b/include/uapi/linux/dtrace/buffer_defines.h -new file mode 100644 -index 0000000000000000000000000000000000000000..16c3c193618ac9fd1bed0439244f2645761df388 ---- /dev/null -+++ b/include/uapi/linux/dtrace/buffer_defines.h -@@ -0,0 +1,21 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_BUFFER_DEFINES_H -+#define _LINUX_DTRACE_BUFFER_DEFINES_H -+ -+#include <linux/dtrace/universal.h> -+ -+struct dtrace_bufdesc; -+ -+#endif /* _LINUX_DTRACE_BUFFER_DEFINES_H */ -diff --git a/include/uapi/linux/dtrace/conf.h b/include/uapi/linux/dtrace/conf.h -new file mode 100644 -index 0000000000000000000000000000000000000000..95b201958f4c046fa3c03bc5a1a3776a366588d1 ---- /dev/null -+++ b/include/uapi/linux/dtrace/conf.h -@@ -0,0 +1,35 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_CONF_H -+#define _LINUX_DTRACE_CONF_H -+ -+#include <linux/dtrace/universal.h> -+#include <linux/dtrace/conf_defines.h> -+ -+/* -+ * User-level may need to understand some elements of the kernel DTrace -+ * configuration in order to generate correct DIF. This information is -+ * conveyed via the dtrace_conf structure. -+ */ -+typedef struct dtrace_conf { -+ uint_t dtc_difversion; /* supported DIF version */ -+ uint_t dtc_difintregs; /* # of DIF integer registers */ -+ uint_t dtc_diftupregs; /* # of DIF tuple registers */ -+ uint_t dtc_ctfmodel; /* CTF data model */ -+ /* Deviation from Solaris... Used to just be 8 padding entries. */ -+ uint_t dtc_maxbufs; /* max # of buffers */ -+ uint_t dtc_pad[7]; /* reserved for future use */ -+} dtrace_conf_t; -+ -+#endif /* _LINUX_DTRACE_CONF_H */ -diff --git a/include/uapi/linux/dtrace/conf_defines.h b/include/uapi/linux/dtrace/conf_defines.h -new file mode 100644 -index 0000000000000000000000000000000000000000..5c4a1cb5d37c944574b25f4f5f8a8eb5068d9bd5 ---- /dev/null -+++ b/include/uapi/linux/dtrace/conf_defines.h -@@ -0,0 +1,21 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_CONF_DEFINES_H -+#define _LINUX_DTRACE_CONF_DEFINES_H -+ -+#include <linux/dtrace/universal.h> -+ -+struct dtrace_conf; -+ -+#endif /* _LINUX_DTRACE_CONF_DEFINES_H */ -diff --git a/include/uapi/linux/dtrace/cpu_defines.h b/include/uapi/linux/dtrace/cpu_defines.h -new file mode 100644 -index 0000000000000000000000000000000000000000..a1cd3e410ccc24befea3becaf3049be8180b66b8 ---- /dev/null -+++ b/include/uapi/linux/dtrace/cpu_defines.h -@@ -0,0 +1,17 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+#ifndef _LINUX_DTRACE_CPU_DEFINES_H_ -+#define _LINUX_DTRACE_CPU_DEFINES_H_ -+ -+typedef uint32_t processorid_t; -+typedef uint32_t psetid_t; -+typedef uint32_t chipid_t; -+typedef uint32_t lgrp_id_t; -+ -+#endif /* _LINUX_DTRACE_CPU_DEFINES_H_ */ -diff --git a/include/uapi/linux/dtrace/dif.h b/include/uapi/linux/dtrace/dif.h -new file mode 100644 -index 0000000000000000000000000000000000000000..92daea17a1f149551b0495b31ee07a8525d50fb8 ---- /dev/null -+++ b/include/uapi/linux/dtrace/dif.h -@@ -0,0 +1,60 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_DIF_H -+#define _LINUX_DTRACE_DIF_H -+ -+#include <linux/dtrace/universal.h> -+#include <linux/dtrace/dif_defines.h> -+ -+/* -+ * The following definitions describe the DTrace Intermediate Format (DIF), a a -+ * RISC-like instruction set and program encoding used to represent predicates -+ * and actions that can be bound to DTrace probes. The constants below defining -+ * the number of available registers are suggested minimums; the compiler should -+ * use DTRACEIOC_CONF to dynamically obtain the number of registers provided by -+ * the current DTrace implementation. -+ */ -+ -+/* -+ * A DTrace Intermediate Format Type (DIF Type) is used to represent the types -+ * of variables, function and associative array arguments, and the return type -+ * for each DIF object (shown below). It contains a description of the type, -+ * its size in bytes, and a module identifier. -+ */ -+ -+typedef struct dtrace_diftype { -+ uint8_t dtdt_kind; -+ uint8_t dtdt_ckind; -+ uint8_t dtdt_flags; -+ uint8_t dtdt_pad; -+ uint32_t dtdt_size; -+} dtrace_diftype_t; -+ -+/* -+ * A DTrace Intermediate Format variable record is used to describe each of the -+ * variables referenced by a given DIF object. It contains an integer variable -+ * identifier along with variable scope and properties, as shown below. The -+ * size of this structure must be sizeof (int) aligned. -+ */ -+ -+typedef struct dtrace_difv { -+ uint32_t dtdv_name; -+ uint32_t dtdv_id; -+ uint8_t dtdv_kind; -+ uint8_t dtdv_scope; -+ uint16_t dtdv_flags; -+ struct dtrace_diftype dtdv_type; -+} dtrace_difv_t; -+ -+#endif /* _LINUX_DTRACE_DIF_H */ -diff --git a/include/uapi/linux/dtrace/dif_defines.h b/include/uapi/linux/dtrace/dif_defines.h -new file mode 100644 -index 0000000000000000000000000000000000000000..80b913f097a22ed174acd574a727ebee68be4fd4 ---- /dev/null -+++ b/include/uapi/linux/dtrace/dif_defines.h -@@ -0,0 +1,288 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_DIF_DEFINES_H -+#define _LINUX_DTRACE_DIF_DEFINES_H -+ -+#include <linux/dtrace/universal.h> -+ -+/* -+ * The following definitions describe the DTrace Intermediate Format (DIF), a a -+ * RISC-like instruction set and program encoding used to represent predicates -+ * and actions that can be bound to DTrace probes. The constants below defining -+ * the number of available registers are suggested minimums; the compiler should -+ * use DTRACEIOC_CONF to dynamically obtain the number of registers provided by -+ * the current DTrace implementation. -+ */ -+ -+#define DIF_VERSION_1 1 -+#define DIF_VERSION_2 2 -+#define DIF_VERSION DIF_VERSION_2 -+#define DIF_DIR_NREGS 8 /* number of DIF integer registers */ -+#define DIF_DTR_NREGS 8 /* number of DIF tuple registers */ -+ -+#define DIF_OP_OR 1 /* or r1, r2, rd */ -+#define DIF_OP_XOR 2 /* xor r1, r2, rd */ -+#define DIF_OP_AND 3 /* and r1, r2, rd */ -+#define DIF_OP_SLL 4 /* sll r1, r2, rd */ -+#define DIF_OP_SRL 5 /* srl r1, r2, rd */ -+#define DIF_OP_SUB 6 /* sub r1, r2, rd */ -+#define DIF_OP_ADD 7 /* add r1, r2, rd */ -+#define DIF_OP_MUL 8 /* mul r1, r2, rd */ -+#define DIF_OP_SDIV 9 /* sdiv r1, r2, rd */ -+#define DIF_OP_UDIV 10 /* udiv r1, r2, rd */ -+#define DIF_OP_SREM 11 /* srem r1, r2, rd */ -+#define DIF_OP_UREM 12 /* urem r1, r2, rd */ -+#define DIF_OP_NOT 13 /* not r1, rd */ -+#define DIF_OP_MOV 14 /* mov r1, rd */ -+#define DIF_OP_CMP 15 /* cmp r1, r2 */ -+#define DIF_OP_TST 16 /* tst r1 */ -+#define DIF_OP_BA 17 /* ba label */ -+#define DIF_OP_BE 18 /* be label */ -+#define DIF_OP_BNE 19 /* bne label */ -+#define DIF_OP_BG 20 /* bg label */ -+#define DIF_OP_BGU 21 /* bgu label */ -+#define DIF_OP_BGE 22 /* bge label */ -+#define DIF_OP_BGEU 23 /* bgeu label */ -+#define DIF_OP_BL 24 /* bl label */ -+#define DIF_OP_BLU 25 /* blu label */ -+#define DIF_OP_BLE 26 /* ble label */ -+#define DIF_OP_BLEU 27 /* bleu label */ -+#define DIF_OP_LDSB 28 /* ldsb [r1], rd */ -+#define DIF_OP_LDSH 29 /* ldsh [r1], rd */ -+#define DIF_OP_LDSW 30 /* ldsw [r1], rd */ -+#define DIF_OP_LDUB 31 /* ldub [r1], rd */ -+#define DIF_OP_LDUH 32 /* lduh [r1], rd */ -+#define DIF_OP_LDUW 33 /* lduw [r1], rd */ -+#define DIF_OP_LDX 34 /* ldx [r1], rd */ -+#define DIF_OP_RET 35 /* ret rd */ -+#define DIF_OP_NOP 36 /* nop */ -+#define DIF_OP_SETX 37 /* setx intindex, rd */ -+#define DIF_OP_SETS 38 /* sets strindex, rd */ -+#define DIF_OP_SCMP 39 /* scmp r1, r2 */ -+#define DIF_OP_LDGA 40 /* ldga var, ri, rd */ -+#define DIF_OP_LDGS 41 /* ldgs var, rd */ -+#define DIF_OP_STGS 42 /* stgs var, rs */ -+#define DIF_OP_LDTA 43 /* ldta var, ri, rd */ -+#define DIF_OP_LDTS 44 /* ldts var, rd */ -+#define DIF_OP_STTS 45 /* stts var, rs */ -+#define DIF_OP_SRA 46 /* sra r1, r2, rd */ -+#define DIF_OP_CALL 47 /* call subr, rd */ -+#define DIF_OP_PUSHTR 48 /* pushtr type, rs, rr */ -+#define DIF_OP_PUSHTV 49 /* pushtv type, rs, rv */ -+#define DIF_OP_POPTS 50 /* popts */ -+#define DIF_OP_FLUSHTS 51 /* flushts */ -+#define DIF_OP_LDGAA 52 /* ldgaa var, rd */ -+#define DIF_OP_LDTAA 53 /* ldtaa var, rd */ -+#define DIF_OP_STGAA 54 /* stgaa var, rs */ -+#define DIF_OP_STTAA 55 /* sttaa var, rs */ -+#define DIF_OP_LDLS 56 /* ldls var, rd */ -+#define DIF_OP_STLS 57 /* stls var, rs */ -+#define DIF_OP_ALLOCS 58 /* allocs r1, rd */ -+#define DIF_OP_COPYS 59 /* copys r1, r2, rd */ -+#define DIF_OP_STB 60 /* stb r1, [rd] */ -+#define DIF_OP_STH 61 /* sth r1, [rd] */ -+#define DIF_OP_STW 62 /* stw r1, [rd] */ -+#define DIF_OP_STX 63 /* stx r1, [rd] */ -+#define DIF_OP_ULDSB 64 /* uldsb [r1], rd */ -+#define DIF_OP_ULDSH 65 /* uldsh [r1], rd */ -+#define DIF_OP_ULDSW 66 /* uldsw [r1], rd */ -+#define DIF_OP_ULDUB 67 /* uldub [r1], rd */ -+#define DIF_OP_ULDUH 68 /* ulduh [r1], rd */ -+#define DIF_OP_ULDUW 69 /* ulduw [r1], rd */ -+#define DIF_OP_ULDX 70 /* uldx [r1], rd */ -+#define DIF_OP_RLDSB 71 /* rldsb [r1], rd */ -+#define DIF_OP_RLDSH 72 /* rldsh [r1], rd */ -+#define DIF_OP_RLDSW 73 /* rldsw [r1], rd */ -+#define DIF_OP_RLDUB 74 /* rldub [r1], rd */ -+#define DIF_OP_RLDUH 75 /* rlduh [r1], rd */ -+#define DIF_OP_RLDUW 76 /* rlduw [r1], rd */ -+#define DIF_OP_RLDX 77 /* rldx [r1], rd */ -+#define DIF_OP_XLATE 78 /* xlate xlrindex, rd */ -+#define DIF_OP_XLARG 79 /* xlarg xlrindex, rd */ -+ -+#define DIF_INTOFF_MAX 0xffff /* highest integer table offset */ -+#define DIF_STROFF_MAX 0xffff /* highest string table offset */ -+#define DIF_REGISTER_MAX 0xff /* highest register number */ -+#define DIF_VARIABLE_MAX 0xffff /* highest variable identifier */ -+#define DIF_SUBROUTINE_MAX 0xffff /* highest subroutine code */ -+ -+#define DIF_VAR_ARRAY_MIN 0x0000 /* lowest numbered array variable */ -+#define DIF_VAR_ARRAY_UBASE 0x0080 /* lowest user-defined array */ -+#define DIF_VAR_ARRAY_MAX 0x00ff /* highest numbered array variable */ -+ -+#define DIF_VAR_OTHER_MIN 0x0100 /* lowest numbered scalar or assc */ -+#define DIF_VAR_OTHER_UBASE 0x0500 /* lowest user-defined scalar or assc */ -+#define DIF_VAR_OTHER_MAX 0xffff /* highest numbered scalar or assc */ -+ -+#define DIF_VAR_ARGS 0x0000 -+#define DIF_VAR_REGS 0x0001 -+#define DIF_VAR_UREGS 0x0002 -+#define DIF_VAR_CURTHREAD 0x0100 -+#define DIF_VAR_TIMESTAMP 0x0101 -+#define DIF_VAR_VTIMESTAMP 0x0102 -+#define DIF_VAR_IPL 0x0103 -+#define DIF_VAR_EPID 0x0104 -+#define DIF_VAR_ID 0x0105 -+#define DIF_VAR_ARG0 0x0106 -+#define DIF_VAR_ARG1 0x0107 -+#define DIF_VAR_ARG2 0x0108 -+#define DIF_VAR_ARG3 0x0109 -+#define DIF_VAR_ARG4 0x010a -+#define DIF_VAR_ARG5 0x010b -+#define DIF_VAR_ARG6 0x010c -+#define DIF_VAR_ARG7 0x010d -+#define DIF_VAR_ARG8 0x010e -+#define DIF_VAR_ARG9 0x010f -+#define DIF_VAR_STACKDEPTH 0x0110 -+#define DIF_VAR_CALLER 0x0111 -+#define DIF_VAR_PROBEPROV 0x0112 -+#define DIF_VAR_PROBEMOD 0x0113 -+#define DIF_VAR_PROBEFUNC 0x0114 -+#define DIF_VAR_PROBENAME 0x0115 -+#define DIF_VAR_PID 0x0116 -+#define DIF_VAR_TID 0x0117 -+#define DIF_VAR_EXECNAME 0x0118 -+#define DIF_VAR_ZONENAME 0x0119 -+#define DIF_VAR_WALLTIMESTAMP 0x011a -+#define DIF_VAR_USTACKDEPTH 0x011b -+#define DIF_VAR_UCALLER 0x011c -+#define DIF_VAR_PPID 0x011d -+#define DIF_VAR_UID 0x011e -+#define DIF_VAR_GID 0x011f -+#define DIF_VAR_ERRNO 0x0120 -+#define DIF_VAR_CURCPU 0x0121 -+ -+#define DIF_SUBR_RAND 0 -+#define DIF_SUBR_MUTEX_OWNED 1 -+#define DIF_SUBR_MUTEX_OWNER 2 -+#define DIF_SUBR_MUTEX_TYPE_ADAPTIVE 3 -+#define DIF_SUBR_MUTEX_TYPE_SPIN 4 -+#define DIF_SUBR_RW_READ_HELD 5 -+#define DIF_SUBR_RW_WRITE_HELD 6 -+#define DIF_SUBR_RW_ISWRITER 7 -+#define DIF_SUBR_COPYIN 8 -+#define DIF_SUBR_COPYINSTR 9 -+#define DIF_SUBR_SPECULATION 10 -+#define DIF_SUBR_PROGENYOF 11 -+#define DIF_SUBR_STRLEN 12 -+#define DIF_SUBR_COPYOUT 13 -+#define DIF_SUBR_COPYOUTSTR 14 -+#define DIF_SUBR_ALLOCA 15 -+#define DIF_SUBR_BCOPY 16 -+#define DIF_SUBR_COPYINTO 17 -+#define DIF_SUBR_MSGDSIZE 18 -+#define DIF_SUBR_MSGSIZE 19 -+#define DIF_SUBR_GETMAJOR 20 -+#define DIF_SUBR_GETMINOR 21 -+#define DIF_SUBR_DDI_PATHNAME 22 -+#define DIF_SUBR_STRJOIN 23 -+#define DIF_SUBR_LLTOSTR 24 -+#define DIF_SUBR_BASENAME 25 -+#define DIF_SUBR_DIRNAME 26 -+#define DIF_SUBR_CLEANPATH 27 -+#define DIF_SUBR_STRCHR 28 -+#define DIF_SUBR_STRRCHR 29 -+#define DIF_SUBR_STRSTR 30 -+#define DIF_SUBR_STRTOK 31 -+#define DIF_SUBR_SUBSTR 32 -+#define DIF_SUBR_INDEX 33 -+#define DIF_SUBR_RINDEX 34 -+#define DIF_SUBR_HTONS 35 -+#define DIF_SUBR_HTONL 36 -+#define DIF_SUBR_HTONLL 37 -+#define DIF_SUBR_NTOHS 38 -+#define DIF_SUBR_NTOHL 39 -+#define DIF_SUBR_NTOHLL 40 -+#define DIF_SUBR_INET_NTOP 41 -+#define DIF_SUBR_INET_NTOA 42 -+#define DIF_SUBR_INET_NTOA6 43 -+#define DIF_SUBR_D_PATH 44 -+#define DIF_SUBR_LINK_NTOP 45 -+ -+#define DIF_SUBR_MAX 45 -+ -+typedef uint32_t dif_instr_t; -+ -+#define DIF_INSTR_OP(i) (((i) >> 24) & 0xff) -+#define DIF_INSTR_R1(i) (((i) >> 16) & 0xff) -+#define DIF_INSTR_R2(i) (((i) >> 8) & 0xff) -+#define DIF_INSTR_RD(i) ((i) & 0xff) -+#define DIF_INSTR_RS(i) ((i) & 0xff) -+#define DIF_INSTR_LABEL(i) ((i) & 0xffffff) -+#define DIF_INSTR_VAR(i) (((i) >> 8) & 0xffff) -+#define DIF_INSTR_INTEGER(i) (((i) >> 8) & 0xffff) -+#define DIF_INSTR_STRING(i) (((i) >> 8) & 0xffff) -+#define DIF_INSTR_SUBR(i) (((i) >> 8) & 0xffff) -+#define DIF_INSTR_TYPE(i) (((i) >> 16) & 0xff) -+#define DIF_INSTR_XLREF(i) (((i) >> 8) & 0xffff) -+#define DIF_INSTR_FMT(op, r1, r2, d) \ -+ (((op) << 24) | ((r1) << 16) | ((r2) << 8) | (d)) -+ -+#define DIF_INSTR_NOT(r1, d) (DIF_INSTR_FMT(DIF_OP_NOT, r1, 0, d)) -+#define DIF_INSTR_MOV(r1, d) (DIF_INSTR_FMT(DIF_OP_MOV, r1, 0, d)) -+#define DIF_INSTR_CMP(op, r1, r2) (DIF_INSTR_FMT(op, r1, r2, 0)) -+#define DIF_INSTR_TST(r1) (DIF_INSTR_FMT(DIF_OP_TST, r1, 0, 0)) -+#define DIF_INSTR_BRANCH(op, label) (((op) << 24) | (label)) -+#define DIF_INSTR_LOAD(op, r1, d) (DIF_INSTR_FMT(op, r1, 0, d)) -+#define DIF_INSTR_STORE(op, r1, d) (DIF_INSTR_FMT(op, r1, 0, d)) -+#define DIF_INSTR_SETX(i, d) ((DIF_OP_SETX << 24) | ((i) << 8) | (d)) -+#define DIF_INSTR_SETS(s, d) ((DIF_OP_SETS << 24) | ((s) << 8) | (d)) -+#define DIF_INSTR_RET(d) (DIF_INSTR_FMT(DIF_OP_RET, 0, 0, d)) -+#define DIF_INSTR_NOP (DIF_OP_NOP << 24) -+#define DIF_INSTR_LDA(op, v, r, d) (DIF_INSTR_FMT(op, v, r, d)) -+#define DIF_INSTR_LDV(op, v, d) (((op) << 24) | ((v) << 8) | (d)) -+#define DIF_INSTR_STV(op, v, rs) (((op) << 24) | ((v) << 8) | (rs)) -+#define DIF_INSTR_CALL(s, d) ((DIF_OP_CALL << 24) | ((s) << 8) | (d)) -+#define DIF_INSTR_PUSHTS(op, t, r2, rs) (DIF_INSTR_FMT(op, t, r2, rs)) -+#define DIF_INSTR_POPTS (DIF_OP_POPTS << 24) -+#define DIF_INSTR_FLUSHTS (DIF_OP_FLUSHTS << 24) -+#define DIF_INSTR_ALLOCS(r1, d) (DIF_INSTR_FMT(DIF_OP_ALLOCS, r1, 0, d)) -+#define DIF_INSTR_COPYS(r1, r2, d) (DIF_INSTR_FMT(DIF_OP_COPYS, r1, r2, d)) -+#define DIF_INSTR_XLATE(op, r, d) (((op) << 24) | ((r) << 8) | (d)) -+ -+#define DIF_REG_R0 0 -+ -+/* -+ * A DTrace Intermediate Format Type (DIF Type) is used to represent the types -+ * of variables, function and associative array arguments, and the return type -+ * for each DIF object (shown below). It contains a description of the type, -+ * its size in bytes, and a module identifier. -+ */ -+ -+#define DIF_TYPE_CTF 0 -+#define DIF_TYPE_STRING 1 -+ -+#define DIF_TF_BYREF 0x1 -+ -+/* -+ * A DTrace Intermediate Format variable record is used to describe each of the -+ * variables referenced by a given DIF object. It contains an integer variable -+ * identifier along with variable scope and properties, as shown below. The -+ * size of this structure must be sizeof (int) aligned. -+ */ -+ -+#define DIFV_KIND_ARRAY 0 -+#define DIFV_KIND_SCALAR 1 -+ -+#define DIFV_SCOPE_GLOBAL 0 -+#define DIFV_SCOPE_THREAD 1 -+#define DIFV_SCOPE_LOCAL 2 -+ -+#define DIFV_F_REF 0x1 -+#define DIFV_F_MOD 0x2 -+ -+struct dtrace_diftype; -+struct dtrace_difv; -+ -+#endif /* _LINUX_DTRACE_DIF_DEFINES_H */ -diff --git a/include/uapi/linux/dtrace/difo.h b/include/uapi/linux/dtrace/difo.h -new file mode 100644 -index 0000000000000000000000000000000000000000..6e9efd7f0a43047a7f5e1804c7192f888d9adef8 ---- /dev/null -+++ b/include/uapi/linux/dtrace/difo.h -@@ -0,0 +1,57 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_DIFO_H -+#define _LINUX_DTRACE_DIFO_H -+ -+#include <linux/dtrace/universal.h> -+#include <linux/dtrace/dif.h> -+#include <linux/dtrace/dof_defines.h> -+ -+/* -+ * A DIFO is used to store the compiled DIF for a D expression, its return -+ * type, and its string and variable tables. The string table is a single -+ * buffer of character data into which sets instructions and variable -+ * references can reference strings using a byte offset. The variable table -+ * is an array of dtrace_difv_t structures that describe the name and type of -+ * each variable and the id used in the DIF code. This structure is described -+ * above in the DIF section of this header file. The DIFO is used at both -+ * user-level (in the library) and in the kernel, but the structure is never -+ * passed between the two: the DOF structures form the only interface. As a -+ * result, the definition can change depending on the presence of _KERNEL. -+ */ -+ -+typedef struct dtrace_difo { -+ dif_instr_t *dtdo_buf; /* instruction buffer */ -+ uint64_t *dtdo_inttab; /* integer table (optional) */ -+ char *dtdo_strtab; /* string table (optional) */ -+ struct dtrace_difv *dtdo_vartab; /* variable table (optional) */ -+ uint_t dtdo_len; /* length of instruction buffer */ -+ uint_t dtdo_intlen; /* length of integer table */ -+ uint_t dtdo_strlen; /* length of string table */ -+ uint_t dtdo_varlen; /* length of variable table */ -+ struct dtrace_diftype dtdo_rtype; /* return type */ -+ uint_t dtdo_refcnt; /* owner reference count */ -+ uint_t dtdo_destructive; /* invokes destructive subroutines */ -+#ifndef _KERNEL -+ struct dtrace_diftype orig_dtdo_rtype; /* original return type */ -+ struct dof_relodesc *dtdo_kreltab; /* kernel relocations */ -+ struct dof_relodesc *dtdo_ureltab; /* user relocations */ -+ struct dt_node **dtdo_xlmtab; /* translator references */ -+ uint_t dtdo_krelen; /* length of krelo table */ -+ uint_t dtdo_urelen; /* length of urelo table */ -+ uint_t dtdo_xlmlen; /* length of translator table */ -+#endif -+} dtrace_difo_t; -+ -+#endif /* _LINUX_DTRACE_DIFO_H */ -diff --git a/include/uapi/linux/dtrace/difo_defines.h b/include/uapi/linux/dtrace/difo_defines.h -new file mode 100644 -index 0000000000000000000000000000000000000000..fdd25f2b76913c41a3306a19d600a7bdd9513099 ---- /dev/null -+++ b/include/uapi/linux/dtrace/difo_defines.h -@@ -0,0 +1,21 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_DIFO_DEFINES_H -+#define _LINUX_DTRACE_DIFO_DEFINES_H -+ -+#include <linux/dtrace/universal.h> -+ -+struct dtrace_difo; -+ -+#endif /* _LINUX_DTRACE_DIFO_DEFINES_H */ -diff --git a/include/uapi/linux/dtrace/dof.h b/include/uapi/linux/dtrace/dof.h -new file mode 100644 -index 0000000000000000000000000000000000000000..54c6ca71044368b77d0352c04f5dbe7b0aa4c8dd ---- /dev/null -+++ b/include/uapi/linux/dtrace/dof.h -@@ -0,0 +1,196 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_DOF_H -+#define _LINUX_DTRACE_DOF_H -+ -+#include <linux/dtrace/universal.h> -+#include <linux/dtrace/dif.h> -+#include <linux/dtrace/dof_defines.h> -+ -+/* -+ * DTrace programs can be persistently encoded in the DOF format so that they -+ * may be embedded in other programs (for example, in an ELF file) or in the -+ * dtrace driver configuration file for use in anonymous tracing. The DOF -+ * format is versioned and extensible so that it can be revised and so that -+ * internal data structures can be modified or extended compatibly. All DOF -+ * structures use fixed-size types, so the 32-bit and 64-bit representations -+ * are identical and consumers can use either data model transparently. -+ * -+ * The file layout is structured as follows: -+ * -+ * +---------------+-------------------+----- ... ----+---- ... ------+ -+ * | dof_hdr_t | dof_sec_t[ ... ] | loadable | non-loadable | -+ * | (file header) | (section headers) | section data | section data | -+ * +---------------+-------------------+----- ... ----+---- ... ------+ -+ * |<------------ dof_hdr.dofh_loadsz --------------->| | -+ * |<------------ dof_hdr.dofh_filesz ------------------------------->| -+ * -+ * The file header stores meta-data including a magic number, data model for -+ * the instrumentation, data encoding, and properties of the DIF code within. -+ * The header describes its own size and the size of the section headers. By -+ * convention, an array of section headers follows the file header, and then -+ * the data for all loadable sections and unloadable sections. This permits -+ * consumer code to easily download the headers and all loadable data into the -+ * DTrace driver in one contiguous chunk, omitting other extraneous sections. -+ * -+ * The section headers describe the size, offset, alignment, and section type -+ * for each section. Sections are described using a set of #defines that tell -+ * the consumer what kind of data is expected. Sections can contain links to -+ * other sections by storing a dof_secidx_t, an index into the section header -+ * array, inside of the section data structures. The section header includes -+ * an entry size so that sections with data arrays can grow their structures. -+ * -+ * The DOF data itself can contain many snippets of DIF (i.e. >1 DIFOs), which -+ * are represented themselves as a collection of related DOF sections. This -+ * permits us to change the set of sections associated with a DIFO over time, -+ * and also permits us to encode DIFOs that contain different sets of sections. -+ * When a DOF section wants to refer to a DIFO, it stores the dof_secidx_t of a -+ * section of type DOF_SECT_DIFOHDR. This section's data is then an array of -+ * dof_secidx_t's which in turn denote the sections associated with this DIFO. -+ * -+ * This loose coupling of the file structure (header and sections) to the -+ * structure of the DTrace program itself (ECB descriptions, action -+ * descriptions, and DIFOs) permits activities such as relocation processing -+ * to occur in a single pass without having to understand D program structure. -+ * -+ * Finally, strings are always stored in ELF-style string tables along with a -+ * string table section index and string table offset. Therefore strings in -+ * DOF are always arbitrary-length and not bound to the current implementation. -+ */ -+ -+typedef struct dof_hdr { -+ uint8_t dofh_ident[DOF_ID_SIZE];/* ident bytes (see defines) */ -+ uint32_t dofh_flags; /* file attribute flags (if any) */ -+ uint32_t dofh_hdrsize; /* size of file header in bytes */ -+ uint32_t dofh_secsize; /* size of section header in bytes */ -+ uint32_t dofh_secnum; /* number of section headers */ -+ uint64_t dofh_secoff; /* file offset of section headers */ -+ uint64_t dofh_loadsz; /* file size of loadable portion */ -+ uint64_t dofh_filesz; /* file size of entire DOF file */ -+ uint64_t dofh_pad; /* reserved for future use */ -+} dof_hdr_t; -+ -+typedef struct dof_sec { -+ uint32_t dofs_type; /* section type (see defines) */ -+ uint32_t dofs_align; /* section data memory alignment */ -+ uint32_t dofs_flags; /* section flags (if any) */ -+ uint32_t dofs_entsize; /* size of section entry (if table) */ -+ uint64_t dofs_offset; /* offset of section data within file */ -+ uint64_t dofs_size; /* size of section data in bytes */ -+} dof_sec_t; -+ -+ -+typedef struct dof_ecbdesc { -+ dof_secidx_t dofe_probes; /* link to DOF_SECT_PROBEDESC */ -+ dof_secidx_t dofe_pred; /* link to DOF_SECT_DIFOHDR */ -+ dof_secidx_t dofe_actions; /* link to DOF_SECT_ACTDESC */ -+ uint32_t dofe_pad; /* reserved for future use */ -+ uint64_t dofe_uarg; /* user-supplied library argument */ -+} dof_ecbdesc_t; -+ -+typedef struct dof_probedesc { -+ dof_secidx_t dofp_strtab; /* link to DOF_SECT_STRTAB section */ -+ dof_stridx_t dofp_provider; /* provider string */ -+ dof_stridx_t dofp_mod; /* module string */ -+ dof_stridx_t dofp_func; /* function string */ -+ dof_stridx_t dofp_name; /* name string */ -+ uint32_t dofp_id; /* probe identifier (or zero) */ -+} dof_probedesc_t; -+ -+typedef struct dof_actdesc { -+ dof_secidx_t dofa_difo; /* link to DOF_SECT_DIFOHDR */ -+ dof_secidx_t dofa_strtab; /* link to DOF_SECT_STRTAB section */ -+ uint32_t dofa_kind; /* action kind (DTRACEACT_* constant) */ -+ uint32_t dofa_ntuple; /* number of subsequent tuple actions */ -+ uint64_t dofa_arg; /* kind-specific argument */ -+ uint64_t dofa_uarg; /* user-supplied argument */ -+} dof_actdesc_t; -+ -+typedef struct dof_difohdr { -+ struct dtrace_diftype dofd_rtype; /* return type for this fragment */ -+ dof_secidx_t dofd_links[1]; /* variable length array of indices */ -+} dof_difohdr_t; -+ -+typedef struct dof_relohdr { -+ dof_secidx_t dofr_strtab; /* link to DOF_SECT_STRTAB for names */ -+ dof_secidx_t dofr_relsec; /* link to DOF_SECT_RELTAB for relos */ -+ dof_secidx_t dofr_tgtsec; /* link to section we are relocating */ -+} dof_relohdr_t; -+ -+typedef struct dof_relodesc { -+ dof_stridx_t dofr_name; /* string name of relocation symbol */ -+ uint32_t dofr_type; /* relo type (DOF_RELO_* constant) */ -+ uint64_t dofr_offset; /* byte offset for relocation */ -+ uint64_t dofr_data; /* additional type-specific data */ -+} dof_relodesc_t; -+ -+typedef struct dof_optdesc { -+ uint32_t dofo_option; /* option identifier */ -+ dof_secidx_t dofo_strtab; /* string table, if string option */ -+ uint64_t dofo_value; /* option value or string index */ -+} dof_optdesc_t; -+ -+typedef struct dof_provider { -+ dof_secidx_t dofpv_strtab; /* link to DOF_SECT_STRTAB section */ -+ dof_secidx_t dofpv_probes; /* link to DOF_SECT_PROBES section */ -+ dof_secidx_t dofpv_prargs; /* link to DOF_SECT_PRARGS section */ -+ dof_secidx_t dofpv_proffs; /* link to DOF_SECT_PROFFS section */ -+ dof_stridx_t dofpv_name; /* provider name string */ -+ dof_attr_t dofpv_provattr; /* provider attributes */ -+ dof_attr_t dofpv_modattr; /* module attributes */ -+ dof_attr_t dofpv_funcattr; /* function attributes */ -+ dof_attr_t dofpv_nameattr; /* name attributes */ -+ dof_attr_t dofpv_argsattr; /* args attributes */ -+ dof_secidx_t dofpv_prenoffs; /* link to DOF_SECT_PRENOFFS section */ -+} dof_provider_t; -+ -+typedef struct dof_probe { -+ uint64_t dofpr_addr; /* probe base address or offset */ -+ dof_stridx_t dofpr_func; /* probe function string */ -+ dof_stridx_t dofpr_name; /* probe name string */ -+ dof_stridx_t dofpr_nargv; /* native argument type strings */ -+ dof_stridx_t dofpr_xargv; /* translated argument type strings */ -+ uint32_t dofpr_argidx; /* index of first argument mapping */ -+ uint32_t dofpr_offidx; /* index of first offset entry */ -+ uint8_t dofpr_nargc; /* native argument count */ -+ uint8_t dofpr_xargc; /* translated argument count */ -+ uint16_t dofpr_noffs; /* number of offset entries for probe */ -+ uint32_t dofpr_enoffidx; /* index of first is-enabled offset */ -+ uint16_t dofpr_nenoffs; /* number of is-enabled offsets */ -+ uint16_t dofpr_pad1; /* reserved for future use */ -+ uint32_t dofpr_pad2; /* reserved for future use */ -+} dof_probe_t; -+ -+typedef struct dof_xlator { -+ dof_secidx_t dofxl_members; /* link to DOF_SECT_XLMEMBERS section */ -+ dof_secidx_t dofxl_strtab; /* link to DOF_SECT_STRTAB section */ -+ dof_stridx_t dofxl_argv; /* input parameter type strings */ -+ uint32_t dofxl_argc; /* input parameter list length */ -+ dof_stridx_t dofxl_type; /* output type string name */ -+ dof_attr_t dofxl_attr; /* output stability attributes */ -+} dof_xlator_t; -+ -+typedef struct dof_xlmember { -+ dof_secidx_t dofxm_difo; /* member link to DOF_SECT_DIFOHDR */ -+ dof_stridx_t dofxm_name; /* member name */ -+ struct dtrace_diftype dofxm_type; /* member type */ -+} dof_xlmember_t; -+ -+typedef struct dof_xlref { -+ dof_secidx_t dofxr_xlator; /* link to DOF_SECT_XLATORS section */ -+ uint32_t dofxr_member; /* index of referenced dof_xlmember */ -+ uint32_t dofxr_argn; /* index of argument for DIF_OP_XLARG */ -+} dof_xlref_t; -+ -+#endif /* _LINUX_DTRACE_DOF_H */ -diff --git a/include/uapi/linux/dtrace/dof_defines.h b/include/uapi/linux/dtrace/dof_defines.h -new file mode 100644 -index 0000000000000000000000000000000000000000..5357d5e099cc21a88ca60ccd7616f6e0a4764cc2 ---- /dev/null -+++ b/include/uapi/linux/dtrace/dof_defines.h -@@ -0,0 +1,192 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_DOF_DEFINES_H -+#define _LINUX_DTRACE_DOF_DEFINES_H -+ -+#include <linux/dtrace/universal.h> -+ -+/* -+ * DTrace programs can be persistently encoded in the DOF format so that they -+ * may be embedded in other programs (for example, in an ELF file) or in the -+ * dtrace driver configuration file for use in anonymous tracing. The DOF -+ * format is versioned and extensible so that it can be revised and so that -+ * internal data structures can be modified or extended compatibly. All DOF -+ * structures use fixed-size types, so the 32-bit and 64-bit representations -+ * are identical and consumers can use either data model transparently. -+ * -+ * The file layout is structured as follows: -+ * -+ * +---------------+-------------------+----- ... ----+---- ... ------+ -+ * | dof_hdr_t | dof_sec_t[ ... ] | loadable | non-loadable | -+ * | (file header) | (section headers) | section data | section data | -+ * +---------------+-------------------+----- ... ----+---- ... ------+ -+ * |<------------ dof_hdr.dofh_loadsz --------------->| | -+ * |<------------ dof_hdr.dofh_filesz ------------------------------->| -+ * -+ * The file header stores meta-data including a magic number, data model for -+ * the instrumentation, data encoding, and properties of the DIF code within. -+ * The header describes its own size and the size of the section headers. By -+ * convention, an array of section headers follows the file header, and then -+ * the data for all loadable sections and unloadable sections. This permits -+ * consumer code to easily download the headers and all loadable data into the -+ * DTrace driver in one contiguous chunk, omitting other extraneous sections. -+ * -+ * The section headers describe the size, offset, alignment, and section type -+ * for each section. Sections are described using a set of #defines that tell -+ * the consumer what kind of data is expected. Sections can contain links to -+ * other sections by storing a dof_secidx_t, an index into the section header -+ * array, inside of the section data structures. The section header includes -+ * an entry size so that sections with data arrays can grow their structures. -+ * -+ * The DOF data itself can contain many snippets of DIF (i.e. >1 DIFOs), which -+ * are represented themselves as a collection of related DOF sections. This -+ * permits us to change the set of sections associated with a DIFO over time, -+ * and also permits us to encode DIFOs that contain different sets of sections. -+ * When a DOF section wants to refer to a DIFO, it stores the dof_secidx_t of a -+ * section of type DOF_SECT_DIFOHDR. This section's data is then an array of -+ * dof_secidx_t's which in turn denote the sections associated with this DIFO. -+ * -+ * This loose coupling of the file structure (header and sections) to the -+ * structure of the DTrace program itself (ECB descriptions, action -+ * descriptions, and DIFOs) permits activities such as relocation processing -+ * to occur in a single pass without having to understand D program structure. -+ * -+ * Finally, strings are always stored in ELF-style string tables along with a -+ * string table section index and string table offset. Therefore strings in -+ * DOF are always arbitrary-length and not bound to the current implementation. -+ */ -+ -+#define DOF_ID_SIZE 16 /* total size of dofh_ident[] in bytes */ -+ -+#define DOF_ID_MAG0 0 -+#define DOF_ID_MAG1 1 -+#define DOF_ID_MAG2 2 -+#define DOF_ID_MAG3 3 -+#define DOF_ID_MODEL 4 -+#define DOF_ID_ENCODING 5 -+#define DOF_ID_VERSION 6 -+#define DOF_ID_DIFVERS 7 -+#define DOF_ID_DIFIREG 8 /* DIF integer registers used by compiler */ -+#define DOF_ID_DIFTREG 9 /* DIF tuple registers used by compiler */ -+#define DOF_ID_PAD 10 /* start of padding bytes (all zeroes) */ -+ -+#define DOF_MAG_MAG0 0x7F /* DOF_ID_MAG[0-3] */ -+#define DOF_MAG_MAG1 'D' -+#define DOF_MAG_MAG2 'O' -+#define DOF_MAG_MAG3 'F' -+ -+#define DOF_MAG_STRING "\177DOF" -+#define DOF_MAG_STRLEN 4 -+ -+#define DOF_MODEL_NONE 0 /* DOF_ID_MODEL */ -+#define DOF_MODEL_ILP32 1 -+#define DOF_MODEL_LP64 2 -+ -+#ifdef _LP64 -+#define DOF_MODEL_NATIVE DOF_MODEL_LP64 -+#else -+#define DOF_MODEL_NATIVE DOF_MODEL_ILP32 -+#endif -+ -+#define DOF_ENCODE_NONE 0 /* DOF_ID_ENCODING */ -+#define DOF_ENCODE_LSB 1 -+#define DOF_ENCODE_MSB 2 -+ -+#ifndef _LITTLE_ENDIAN -+#define DOF_ENCODE_NATIVE DOF_ENCODE_MSB -+#else -+#define DOF_ENCODE_NATIVE DOF_ENCODE_LSB -+#endif -+ -+#define DOF_VERSION_1 1 -+#define DOF_VERSION_2 2 -+#define DOF_VERSION DOF_VERSION_2 -+ -+#define DOF_FL_VALID 0 /* mask of all valid dofh_flags bits */ -+ -+typedef uint32_t dof_secidx_t; /* section header table index type */ -+typedef uint32_t dof_stridx_t; /* string table index type */ -+ -+#define DOF_SECIDX_NONE -1U /* null value for section indices */ -+#define DOF_STRIDX_NONE -1U /* null value for string indices */ -+ -+#define DOF_SECT_NONE 0 /* null section */ -+#define DOF_SECT_COMMENTS 1 /* compiler comments */ -+#define DOF_SECT_SOURCE 2 /* D program source code */ -+#define DOF_SECT_ECBDESC 3 /* dof_ecbdesc_t */ -+#define DOF_SECT_PROBEDESC 4 /* dof_probedesc_t */ -+#define DOF_SECT_ACTDESC 5 /* dof_actdesc_t array */ -+#define DOF_SECT_DIFOHDR 6 /* dof_difohdr_t (variable length) */ -+#define DOF_SECT_DIF 7 /* uint32_t array of byte code */ -+#define DOF_SECT_STRTAB 8 /* string table */ -+#define DOF_SECT_VARTAB 9 /* dtrace_difv_t array */ -+#define DOF_SECT_RELTAB 10 /* dof_relodesc_t array */ -+#define DOF_SECT_TYPTAB 11 /* dtrace_diftype_t array */ -+#define DOF_SECT_URELHDR 12 /* dof_relohdr_t (user relocations) */ -+#define DOF_SECT_KRELHDR 13 /* dof_relohdr_t (kernel relocations) */ -+#define DOF_SECT_OPTDESC 14 /* dof_optdesc_t array */ -+#define DOF_SECT_PROVIDER 15 /* dof_provider_t */ -+#define DOF_SECT_PROBES 16 /* dof_probe_t array */ -+#define DOF_SECT_PRARGS 17 /* uint8_t array (probe arg mappings) */ -+#define DOF_SECT_PROFFS 18 /* uint32_t array (probe arg offsets) */ -+#define DOF_SECT_INTTAB 19 /* uint64_t array */ -+#define DOF_SECT_UTSNAME 20 /* struct utsname */ -+#define DOF_SECT_XLTAB 21 /* dof_xlref_t array */ -+#define DOF_SECT_XLMEMBERS 22 /* dof_xlmember_t array */ -+#define DOF_SECT_XLIMPORT 23 /* dof_xlator_t */ -+#define DOF_SECT_XLEXPORT 24 /* dof_xlator_t */ -+#define DOF_SECT_PREXPORT 25 /* dof_secidx_t array (exported objs) */ -+#define DOF_SECT_PRENOFFS 26 /* uint32_t array (enabled offsets) */ -+ -+#define DOF_SECF_LOAD 1 /* section should be loaded */ -+ -+#define DOF_SEC_ISLOADABLE(x) \ -+ (((x) == DOF_SECT_ECBDESC) || ((x) == DOF_SECT_PROBEDESC) || \ -+ ((x) == DOF_SECT_ACTDESC) || ((x) == DOF_SECT_DIFOHDR) || \ -+ ((x) == DOF_SECT_DIF) || ((x) == DOF_SECT_STRTAB) || \ -+ ((x) == DOF_SECT_VARTAB) || ((x) == DOF_SECT_RELTAB) || \ -+ ((x) == DOF_SECT_TYPTAB) || ((x) == DOF_SECT_URELHDR) || \ -+ ((x) == DOF_SECT_KRELHDR) || ((x) == DOF_SECT_OPTDESC) || \ -+ ((x) == DOF_SECT_PROVIDER) || ((x) == DOF_SECT_PROBES) || \ -+ ((x) == DOF_SECT_PRARGS) || ((x) == DOF_SECT_PROFFS) || \ -+ ((x) == DOF_SECT_INTTAB) || ((x) == DOF_SECT_XLTAB) || \ -+ ((x) == DOF_SECT_XLMEMBERS) || ((x) == DOF_SECT_XLIMPORT) || \ -+ ((x) == DOF_SECT_XLIMPORT) || ((x) == DOF_SECT_XLEXPORT) || \ -+ ((x) == DOF_SECT_PREXPORT) || ((x) == DOF_SECT_PRENOFFS)) -+ -+#define DOF_RELO_NONE 0 /* empty relocation entry */ -+#define DOF_RELO_SETX 1 /* relocate setx value */ -+ -+typedef uint32_t dof_attr_t; /* encoded stability attributes */ -+ -+#define DOF_ATTR(n, d, c) (((n) << 24) | ((d) << 16) | ((c) << 8)) -+#define DOF_ATTR_NAME(a) (((a) >> 24) & 0xff) -+#define DOF_ATTR_DATA(a) (((a) >> 16) & 0xff) -+#define DOF_ATTR_CLASS(a) (((a) >> 8) & 0xff) -+ -+struct dof_hdr; -+struct dof_sec; -+struct dof_ecbdesc; -+struct dof_probedesc; -+struct dof_actdesc; -+struct dof_difohdr; -+struct dof_relohdr; -+struct dof_relodesc; -+struct dof_optdesc; -+struct dof_provider; -+struct dof_xlator; -+struct dof_xlmember; -+struct dof_xlref; -+ -+#endif /* _LINUX_DTRACE_DOF_DEFINES_H */ -diff --git a/include/uapi/linux/dtrace/dtrace.h b/include/uapi/linux/dtrace/dtrace.h -new file mode 100644 -index 0000000000000000000000000000000000000000..0ee9d35876ef5db0c5231c780735681434917e40 ---- /dev/null -+++ b/include/uapi/linux/dtrace/dtrace.h -@@ -0,0 +1,33 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_H_ -+#define _LINUX_DTRACE_H_ -+ -+#include <linux/dtrace/universal.h> -+#include <linux/dtrace/dif.h> -+#include <linux/dtrace/actions.h> -+#include <linux/dtrace/dof.h> -+#include <linux/dtrace/difo.h> -+#include <linux/dtrace/enabling.h> -+#include <linux/dtrace/metadesc.h> -+#include <linux/dtrace/options.h> -+#include <linux/dtrace/buffer.h> -+#include <linux/dtrace/status.h> -+#include <linux/dtrace/conf.h> -+#include <linux/dtrace/faults.h> -+#include <linux/dtrace/arg.h> -+#include <linux/dtrace/stability.h> -+#include <linux/dtrace/helpers.h> -+ -+#endif /* _LINUX_DTRACE_H_ */ -diff --git a/include/uapi/linux/dtrace/enabling.h b/include/uapi/linux/dtrace/enabling.h -new file mode 100644 -index 0000000000000000000000000000000000000000..8aac2ab9ea8daa3ddeae345584eb85b21b6418df ---- /dev/null -+++ b/include/uapi/linux/dtrace/enabling.h -@@ -0,0 +1,76 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_ENABLING_H -+#define _LINUX_DTRACE_ENABLING_H -+ -+#include <linux/dtrace/universal.h> -+#include <linux/dtrace/difo_defines.h> -+#include <linux/dtrace/enabling_defines.h> -+ -+/* -+ * When DTrace is tracking the description of a DTrace enabling entity (probe, -+ * predicate, action, ECB, record, etc.), it does so in a description -+ * structure. These structures all end in "desc", and are used at both -+ * user-level and in the kernel -- but (with the exception of -+ * dtrace_probedesc_t) they are never passed between them. Typically, -+ * user-level will use the description structures when assembling an enabling. -+ * It will then distill those description structures into a DOF object (see -+ * above), and send it into the kernel. The kernel will again use the -+ * description structures to create a description of the enabling as it reads -+ * the DOF. When the description is complete, the enabling will be actually -+ * created -- turning it into the structures that represent the enabling -+ * instead of merely describing it. Not surprisingly, the description -+ * structures bear a strong resemblance to the DOF structures that act as their -+ * conduit. -+ */ -+ -+struct dtrace_predicate; -+ -+typedef struct dtrace_probedesc { -+ dtrace_id_t dtpd_id; /* probe identifier */ -+ char dtpd_provider[DTRACE_PROVNAMELEN]; /* probe provider name */ -+ char dtpd_mod[DTRACE_MODNAMELEN]; /* probe module name */ -+ char dtpd_func[DTRACE_FUNCNAMELEN]; /* probe function name */ -+ char dtpd_name[DTRACE_NAMELEN]; /* probe name */ -+} dtrace_probedesc_t; -+ -+typedef struct dtrace_repldesc { -+ struct dtrace_probedesc dtrpd_match; /* probe descr. to match */ -+ struct dtrace_probedesc dtrpd_create; /* probe descr. to create */ -+} dtrace_repldesc_t; -+ -+typedef struct dtrace_preddesc { -+ struct dtrace_difo *dtpdd_difo; /* pointer to DIF object */ -+ struct dtrace_predicate *dtpdd_predicate; /* pointer to predicate */ -+} dtrace_preddesc_t; -+ -+typedef struct dtrace_actdesc { -+ struct dtrace_difo *dtad_difo; /* pointer to DIF object */ -+ struct dtrace_actdesc *dtad_next; /* next action */ -+ dtrace_actkind_t dtad_kind; /* kind of action */ -+ uint32_t dtad_ntuple; /* number in tuple */ -+ uint64_t dtad_arg; /* action argument */ -+ uint64_t dtad_uarg; /* user argument */ -+ int dtad_refcnt; /* reference count */ -+} dtrace_actdesc_t; -+ -+typedef struct dtrace_ecbdesc { -+ struct dtrace_actdesc *dted_action; /* action description(s) */ -+ struct dtrace_preddesc dted_pred; /* predicate description */ -+ struct dtrace_probedesc dted_probe; /* probe description */ -+ uint64_t dted_uarg; /* library argument */ -+ int dted_refcnt; /* reference count */ -+} dtrace_ecbdesc_t; -+ -+#endif /* _LINUX_DTRACE_ENABLING_H */ -diff --git a/include/uapi/linux/dtrace/enabling_defines.h b/include/uapi/linux/dtrace/enabling_defines.h -new file mode 100644 -index 0000000000000000000000000000000000000000..221c3efca015cb0737648eaa345d4910e57bb485 ---- /dev/null -+++ b/include/uapi/linux/dtrace/enabling_defines.h -@@ -0,0 +1,25 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_ENABLING_DEFINES_H -+#define _LINUX_DTRACE_ENABLING_DEFINES_H -+ -+#include <linux/dtrace/universal.h> -+ -+struct dtrace_probedesc; -+struct dtrace_repldesc; -+struct dtrace_preddesc; -+struct dtrace_actdesc; -+struct dtrace_ecbdesc; -+ -+#endif /* _LINUX_DTRACE_ENABLING_DEFINES_H */ -diff --git a/include/uapi/linux/dtrace/fasttrap.h b/include/uapi/linux/dtrace/fasttrap.h -new file mode 100644 -index 0000000000000000000000000000000000000000..4dbf1a2a35cd6f9a6b3f1ad86eaa2c67bb516ea6 ---- /dev/null -+++ b/include/uapi/linux/dtrace/fasttrap.h -@@ -0,0 +1,56 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_FASTTRAP_H -+#define _LINUX_DTRACE_FASTTRAP_H -+ -+#include <linux/dtrace/universal.h> -+#include <linux/dtrace/fasttrap_defines.h> -+ -+typedef enum fasttrap_probe_type { -+ DTFTP_NONE = 0, -+ DTFTP_ENTRY, -+ DTFTP_RETURN, -+ DTFTP_OFFSETS, -+ DTFTP_POST_OFFSETS, -+ DTFTP_IS_ENABLED -+} fasttrap_probe_type_t; -+ -+typedef struct fasttrap_probe_spec { -+ pid_t ftps_pid; /* task PID */ -+ enum fasttrap_probe_type ftps_type; /* probe type */ -+ char ftps_func[DTRACE_FUNCNAMELEN]; /* probe function */ -+ char ftps_mod[DTRACE_MODNAMELEN]; /* probe module */ -+ uint64_t ftps_pc; /* probe address */ -+ uint64_t ftps_size; /* function size (in bytes) */ -+ uint8_t ftps_glen; /* glob pattern length */ -+ char ftps_gstr[1]; /* glob pattern string */ -+} fasttrap_probe_spec_t; -+ -+typedef uint8_t fasttrap_instr_t; -+ -+typedef struct fasttrap_instr_query { -+ uint64_t ftiq_pc; -+ pid_t ftiq_pid; -+ fasttrap_instr_t ftiq_instr; -+} fasttrap_instr_query_t; -+ -+/* -+ * Include after the definitions, to get ioctl()s when fasttrap.h is included. -+ * fasttrap_ioctl.h also #includes this header, to get structures when it is -+ * included itself, as is done by headers_check. -+ */ -+ -+#include <linux/dtrace/fasttrap_ioctl.h> -+ -+#endif /* _LINUX_DTRACE_FASTTRAP_H */ -diff --git a/include/uapi/linux/dtrace/fasttrap_defines.h b/include/uapi/linux/dtrace/fasttrap_defines.h -new file mode 100644 -index 0000000000000000000000000000000000000000..4bb07564e1c454f617fc8afb786decf84910612b ---- /dev/null -+++ b/include/uapi/linux/dtrace/fasttrap_defines.h -@@ -0,0 +1,25 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_FASTTRAP_DEFINES_H -+#define _LINUX_DTRACE_FASTTRAP_DEFINES_H -+ -+#include <linux/dtrace/universal.h> -+ -+#ifndef __cplusplus -+enum fasttrap_probe_type; -+#endif -+struct fasttrap_probe_spec; -+struct fasttrap_instr_query; -+ -+#endif /* _LINUX_DTRACE_FASTTRAP_DEFINES_H */ -diff --git a/include/uapi/linux/dtrace/fasttrap_ioctl.h b/include/uapi/linux/dtrace/fasttrap_ioctl.h -new file mode 100644 -index 0000000000000000000000000000000000000000..b5a8b0731fb67cf2155c83dada7a5b09547d937b ---- /dev/null -+++ b/include/uapi/linux/dtrace/fasttrap_ioctl.h -@@ -0,0 +1,19 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+#ifndef _LINUX_DTRACE_FASTRRAP_IOCTL_H_ -+#define _LINUX_DTRACE_FASTTRAP_IOCTL_H_ -+ -+#include <linux/ioctl.h> -+#include <linux/dtrace/fasttrap.h> -+ -+#define FASTTRAPIOC 0xf4 -+#define FASTTRAPIOC_MAKEPROBE _IOW(FASTTRAPIOC, 1, struct fasttrap_probe_spec) -+#define FASTTRAPIOC_GETINSTR _IOR(FASTTRAPIOC, 2, struct fasttrap_instr_query) -+ -+#endif /* _LINUX_DTRACE_FASTTRAP_IOCTL_H_ */ -diff --git a/include/uapi/linux/dtrace/faults.h b/include/uapi/linux/dtrace/faults.h -new file mode 100644 -index 0000000000000000000000000000000000000000..afa2ae548fa6952b30fb4c6fc19e4d1436392908 ---- /dev/null -+++ b/include/uapi/linux/dtrace/faults.h -@@ -0,0 +1,20 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_FAULTS_H -+#define _LINUX_DTRACE_FAULTS_H -+ -+#include <linux/dtrace/universal.h> -+#include <linux/dtrace/faults_defines.h> -+ -+#endif /* _LINUX_DTRACE_FAULTS_H */ -diff --git a/include/uapi/linux/dtrace/faults_defines.h b/include/uapi/linux/dtrace/faults_defines.h -new file mode 100644 -index 0000000000000000000000000000000000000000..d225f2e847e4f9359c11ceaf736cbd6ae3de3474 ---- /dev/null -+++ b/include/uapi/linux/dtrace/faults_defines.h -@@ -0,0 +1,39 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_FAULTS_DEFINES_H -+#define _LINUX_DTRACE_FAULTS_DEFINES_H -+ -+#include <linux/dtrace/universal.h> -+ -+/* -+ * The constants below DTRACEFLT_LIBRARY indicate probe processing faults; -+ * constants at or above DTRACEFLT_LIBRARY indicate faults in probe -+ * postprocessing at user-level. Probe processing faults induce an ERROR -+ * probe and are replicated in unistd.d to allow users' ERROR probes to decode -+ * the error condition using thse symbolic labels. -+ */ -+#define DTRACEFLT_UNKNOWN 0 /* Unknown fault */ -+#define DTRACEFLT_BADADDR 1 /* Bad address */ -+#define DTRACEFLT_BADALIGN 2 /* Bad alignment */ -+#define DTRACEFLT_ILLOP 3 /* Illegal operation */ -+#define DTRACEFLT_DIVZERO 4 /* Divide-by-zero */ -+#define DTRACEFLT_NOSCRATCH 5 /* Out of scratch space */ -+#define DTRACEFLT_KPRIV 6 /* Illegal kernel access */ -+#define DTRACEFLT_UPRIV 7 /* Illegal user access */ -+#define DTRACEFLT_TUPOFLOW 8 /* Tuple stack overflow */ -+#define DTRACEFLT_BADSTACK 9 /* Bad stack */ -+ -+#define DTRACEFLT_LIBRARY 1000 /* Library-level fault */ -+ -+#endif /* _LINUX_DTRACE_FAULTS_DEFINES_H */ -diff --git a/include/uapi/linux/dtrace/helpers.h b/include/uapi/linux/dtrace/helpers.h -new file mode 100644 -index 0000000000000000000000000000000000000000..553f2399488120b20e37bbeee269ad2276977c6f ---- /dev/null -+++ b/include/uapi/linux/dtrace/helpers.h -@@ -0,0 +1,101 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_HELPERS_H -+#define _LINUX_DTRACE_HELPERS_H -+ -+#include <linux/dtrace/universal.h> -+#include <linux/dtrace/helpers_defines.h> -+ -+/* -+ * DTrace Helpers -+ * -+ * In general, DTrace establishes probes in processes and takes actions on -+ * processes without knowing their specific user-level structures. Instead of -+ * existing in the framework, process-specific knowledge is contained by the -+ * enabling D program -- which can apply process-specific knowledge by making -+ * appropriate use of DTrace primitives like copyin() and copyinstr() to -+ * operate on user-level data. However, there may exist some specific probes -+ * of particular semantic relevance that the application developer may wish to -+ * explicitly export. For example, an application may wish to export a probe -+ * at the point that it begins and ends certain well-defined transactions. In -+ * addition to providing probes, programs may wish to offer assistance for -+ * certain actions. For example, in highly dynamic environments (e.g., Java), -+ * it may be difficult to obtain a stack trace in terms of meaningful symbol -+ * names (the translation from instruction addresses to corresponding symbol -+ * names may only be possible in situ); these environments may wish to define -+ * a series of actions to be applied in situ to obtain a meaningful stack -+ * trace. -+ * -+ * These two mechanisms -- user-level statically defined tracing and assisting -+ * DTrace actions -- are provided via DTrace _helpers_. Helpers are specified -+ * via DOF, but unlike enabling DOF, helper DOF may contain definitions of -+ * providers, probes and their arguments. If a helper wishes to provide -+ * action assistance, probe descriptions and corresponding DIF actions may be -+ * specified in the helper DOF. For such helper actions, however, the probe -+ * description describes the specific helper: all DTrace helpers have the -+ * provider name "dtrace" and the module name "helper", and the name of the -+ * helper is contained in the function name (for example, the ustack() helper -+ * is named "ustack"). Any helper-specific name may be contained in the name -+ * (for example, if a helper were to have a constructor, it might be named -+ * "dtrace:helper:<helper>:init"). Helper actions are only called when the -+ * action that they are helping is taken. Helper actions may only return DIF -+ * expressions, and may only call the following subroutines: -+ * -+ * alloca() <= Allocates memory out of the consumer's scratch space -+ * bcopy() <= Copies memory to scratch space -+ * copyin() <= Copies memory from user-level into consumer's scratch -+ * copyinto() <= Copies memory into a specific location in scratch -+ * copyinstr() <= Copies a string into a specific location in scratch -+ * -+ * Helper actions may only access the following built-in variables: -+ * -+ * curthread <= Current kthread_t pointer -+ * tid <= Current thread identifier -+ * pid <= Current process identifier -+ * ppid <= Parent process identifier -+ * uid <= Current user ID -+ * gid <= Current group ID -+ * execname <= Current executable name -+ * zonename <= Current zone name -+ * -+ * Helper actions may not manipulate or allocate dynamic variables, but they -+ * may have clause-local and statically-allocated global variables. The -+ * helper action variable state is specific to the helper action -- variables -+ * used by the helper action may not be accessed outside of the helper -+ * action, and the helper action may not access variables that like outside -+ * of it. Helper actions may not load from kernel memory at-large; they are -+ * restricting to loading current user state (via copyin() and variants) and -+ * scratch space. As with probe enablings, helper actions are executed in -+ * program order. The result of the helper action is the result of the last -+ * executing helper expression. -+ * -+ * Helpers -- composed of either providers/probes or probes/actions (or both) -+ * -- are added by opening the "helper" minor node, and issuing an ioctl(2) -+ * (DTRACEHIOC_ADDDOF) that specifies the dof_helper_t structure. This -+ * encapsulates the name and base address of the user-level library or -+ * executable publishing the helpers and probes as well as the DOF that -+ * contains the definitions of those helpers and probes. -+ * -+ * The DTRACEHIOC_ADD and DTRACEHIOC_REMOVE are left in place for legacy -+ * helpers and should no longer be used. No other ioctls are valid on the -+ * helper minor node. -+ */ -+ -+typedef struct dof_helper { -+ char dofhp_mod[DTRACE_MODNAMELEN]; /* executable or library name */ -+ uint64_t dofhp_addr; /* base address of object */ -+ uint64_t dofhp_dof; /* address of helper DOF */ -+} dof_helper_t; -+ -+#endif /* _LINUX_DTRACE_HELPERS_H */ -diff --git a/include/uapi/linux/dtrace/helpers_defines.h b/include/uapi/linux/dtrace/helpers_defines.h -new file mode 100644 -index 0000000000000000000000000000000000000000..8bf52f05800199eac66a99187b007f9d48785484 ---- /dev/null -+++ b/include/uapi/linux/dtrace/helpers_defines.h -@@ -0,0 +1,21 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_HELPERS_DEFINES_H -+#define _LINUX_DTRACE_HELPERS_DEFINES_H -+ -+#include <linux/dtrace/universal.h> -+ -+struct dof_helper; -+ -+#endif /* _LINUX_DTRACE_HELPERS_DEFINES_H */ -diff --git a/include/uapi/linux/dtrace/ioctl.h b/include/uapi/linux/dtrace/ioctl.h -new file mode 100644 -index 0000000000000000000000000000000000000000..ef2476af2629166d7b0acd66c5d87d039c49f636 ---- /dev/null -+++ b/include/uapi/linux/dtrace/ioctl.h -@@ -0,0 +1,47 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+#ifndef _LINUX_DTRACE_IOCTL_H_ -+#define _LINUX_DTRACE_IOCTL_H_ -+ -+#include <linux/ioctl.h> -+#include <linux/dtrace/arg.h> -+#include <linux/dtrace/buffer.h> -+#include <linux/dtrace/conf.h> -+#include <linux/dtrace/dof.h> -+#include <linux/dtrace/enabling.h> -+#include <linux/dtrace/helpers.h> -+#include <linux/dtrace/metadesc.h> -+#include <linux/dtrace/stability.h> -+#include <linux/dtrace/status.h> -+#include <linux/dtrace/cpu_defines.h> -+ -+#define DTRACEIOC 0xd4 -+#define DTRACEIOC_PROVIDER _IOR(DTRACEIOC, 1, struct dtrace_providerdesc) -+#define DTRACEIOC_PROBES _IOR(DTRACEIOC, 2, struct dtrace_probedesc) -+#define DTRACEIOC_BUFSNAP _IOR(DTRACEIOC, 4, struct dtrace_bufdesc) -+#define DTRACEIOC_PROBEMATCH _IOR(DTRACEIOC, 5, struct dtrace_probedesc) -+#define DTRACEIOC_ENABLE _IOW(DTRACEIOC, 6, void *) -+#define DTRACEIOC_AGGSNAP _IOR(DTRACEIOC, 7, struct dtrace_bufdesc) -+#define DTRACEIOC_EPROBE _IOW(DTRACEIOC, 8, struct dtrace_eprobedesc) -+#define DTRACEIOC_PROBEARG _IOR(DTRACEIOC, 9, struct dtrace_argdesc) -+#define DTRACEIOC_CONF _IOR(DTRACEIOC, 10, struct dtrace_conf) -+#define DTRACEIOC_STATUS _IOR(DTRACEIOC, 11, struct dtrace_status) -+#define DTRACEIOC_GO _IOW(DTRACEIOC, 12, processorid_t) -+#define DTRACEIOC_STOP _IOW(DTRACEIOC, 13, processorid_t) -+#define DTRACEIOC_AGGDESC _IOR(DTRACEIOC, 15, struct dtrace_aggdesc) -+#define DTRACEIOC_FORMAT _IOR(DTRACEIOC, 16, struct dtrace_fmtdesc) -+#define DTRACEIOC_DOFGET _IOR(DTRACEIOC, 17, struct dof_hdr) -+#define DTRACEIOC_REPLICATE _IOR(DTRACEIOC, 18, void *) -+ -+#define DTRACEHIOC 0xd8 -+#define DTRACEHIOC_ADD _IOW(DTRACEHIOC, 1, struct dof_hdr) -+#define DTRACEHIOC_REMOVE _IOW(DTRACEHIOC, 2, int) -+#define DTRACEHIOC_ADDDOF _IOW(DTRACEHIOC, 3, struct dof_helper) -+ -+#endif /* _LINUX_DTRACE_IOCTL_H */ -diff --git a/include/uapi/linux/dtrace/metadesc.h b/include/uapi/linux/dtrace/metadesc.h -new file mode 100644 -index 0000000000000000000000000000000000000000..a6b3d82b2c97b4cb1da600362ac1b6d09f8963fd ---- /dev/null -+++ b/include/uapi/linux/dtrace/metadesc.h -@@ -0,0 +1,81 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_METADESC_H -+#define _LINUX_DTRACE_METADESC_H -+ -+#include <linux/dtrace/universal.h> -+#include <linux/dtrace/actions_defines.h> -+#include <linux/dtrace/metadesc_defines.h> -+ -+/* -+ * DTrace separates the trace data stream from the metadata stream. The only -+ * metadata tokens placed in the data stream are enabled probe identifiers -+ * (EPIDs) or (in the case of aggregations) aggregation identifiers. In order -+ * to determine the structure of the data, DTrace consumers pass the token to -+ * the kernel, and receive in return a corresponding description of the enabled -+ * probe (via the dtrace_eprobedesc structure) or the aggregation (via the -+ * dtrace_aggdesc structure). Both of these structures are expressed in terms -+ * of record descriptions (via the dtrace_recdesc structure) that describe the -+ * exact structure of the data. Some record descriptions may also contain a -+ * format identifier; this additional bit of metadata can be retrieved from the -+ * kernel, for which a format description is returned via the dtrace_fmtdesc -+ * structure. Note that all four of these structures must be bitness-neutral -+ * to allow for a 32-bit DTrace consumer on a 64-bit kernel. -+ */ -+typedef struct dtrace_recdesc { -+ dtrace_actkind_t dtrd_action; /* kind of action */ -+ uint32_t dtrd_size; /* size of record */ -+ uint32_t dtrd_offset; /* offset in ECB's data */ -+ uint16_t dtrd_alignment; /* required alignment */ -+ uint16_t dtrd_format; /* format, if any */ -+ uint64_t dtrd_arg; /* action argument */ -+ uint64_t dtrd_uarg; /* user argument */ -+} dtrace_recdesc_t; -+ -+typedef struct dtrace_eprobedesc { -+ dtrace_epid_t dtepd_epid; /* enabled probe ID */ -+ dtrace_id_t dtepd_probeid; /* probe ID */ -+ uint64_t dtepd_uarg; /* library argument */ -+ uint32_t dtepd_size; /* total size */ -+ int dtepd_nrecs; /* number of records */ -+ struct dtrace_recdesc dtepd_rec[1]; /* records themselves */ -+} dtrace_eprobedesc_t; -+ -+typedef struct dtrace_aggdesc { -+ DTRACE_PTR(char, dtagd_name); /* not filled in by kernel */ -+ dtrace_aggvarid_t dtagd_varid; /* not filled in by kernel */ -+ int dtagd_flags; /* not filled in by kernel */ -+ dtrace_aggid_t dtagd_id; /* aggregation ID */ -+ dtrace_epid_t dtagd_epid; /* enabled probe ID */ -+ uint32_t dtagd_size; /* size in bytes */ -+ int dtagd_nrecs; /* number of records */ -+ uint32_t dtagd_pad; /* explicit padding */ -+ struct dtrace_recdesc dtagd_rec[1]; /* record descriptions */ -+} dtrace_aggdesc_t; -+ -+typedef struct dtrace_fmtdesc { -+ DTRACE_PTR(char, dtfd_string); /* format string */ -+ int dtfd_length; /* length of format string */ -+ uint16_t dtfd_format; /* format identifier */ -+} dtrace_fmtdesc_t; -+ -+#define DTRACE_SIZEOF_EPROBEDESC(desc) \ -+ (sizeof(struct dtrace_eprobedesc) + ((desc)->dtepd_nrecs ? \ -+ (((desc)->dtepd_nrecs - 1) * sizeof(struct dtrace_recdesc)) : 0)) -+ -+#define DTRACE_SIZEOF_AGGDESC(desc) \ -+ (sizeof(struct dtrace_aggdesc) + ((desc)->dtagd_nrecs ? \ -+ (((desc)->dtagd_nrecs - 1) * sizeof(struct dtrace_recdesc)) : 0)) -+ -+#endif /* _LINUX_DTRACE_METADESC_H */ -diff --git a/include/uapi/linux/dtrace/metadesc_defines.h b/include/uapi/linux/dtrace/metadesc_defines.h -new file mode 100644 -index 0000000000000000000000000000000000000000..b27cc28822c87fc50c8419633cf8b57c6bea98c1 ---- /dev/null -+++ b/include/uapi/linux/dtrace/metadesc_defines.h -@@ -0,0 +1,24 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_METADESC_DEFINES_H -+#define _LINUX_DTRACE_METADESC_DEFINES_H -+ -+#include <linux/dtrace/universal.h> -+ -+struct dtrace_recdesc; -+struct dtrace_eprobedesc; -+struct dtrace_aggdesc; -+struct dtrace_fmtdesc; -+ -+#endif /* _LINUX_DTRACE_METADESC_DEFINES_H */ -diff --git a/include/uapi/linux/dtrace/options.h b/include/uapi/linux/dtrace/options.h -new file mode 100644 -index 0000000000000000000000000000000000000000..0a652ca2a1485689b06fbc250d0521c08027d52a ---- /dev/null -+++ b/include/uapi/linux/dtrace/options.h -@@ -0,0 +1,20 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_OPTIONS_H -+#define _LINUX_DTRACE_OPTIONS_H -+ -+#include <linux/dtrace/universal.h> -+#include <linux/dtrace/options_defines.h> -+ -+#endif /* _LINUX_DTRACE_OPTIONS_H */ -diff --git a/include/uapi/linux/dtrace/options_defines.h b/include/uapi/linux/dtrace/options_defines.h -new file mode 100644 -index 0000000000000000000000000000000000000000..26009c84437e7ba3459b0e35f38ccc2a99862f7d ---- /dev/null -+++ b/include/uapi/linux/dtrace/options_defines.h -@@ -0,0 +1,72 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_OPTIONS_DEFINES_H -+#define _LINUX_DTRACE_OPTIONS_DEFINES_H -+ -+#include <linux/dtrace/universal.h> -+ -+/* -+ * Run-time DTrace options are set and retrieved via DOF_SECT_OPTDESC sections -+ * in a DOF image. The dof_optdesc structure contains an option identifier and -+ * an option value. The valid option identifiers are found below; the mapping -+ * between option identifiers and option identifying strings is maintained at -+ * user-level. Note that the value of DTRACEOPT_UNSET is such that all of the -+ * following are potentially valid option values: all positive integers, zero -+ * and negative one. Some options (notably "bufpolicy" and "bufresize") take -+ * predefined tokens as their values; these are defined with -+ * DTRACEOPT_{option}_{token}. -+ */ -+ -+#define DTRACEOPT_BUFSIZE 0 /* buffer size */ -+#define DTRACEOPT_BUFPOLICY 1 /* buffer policy */ -+#define DTRACEOPT_DYNVARSIZE 2 /* dynamic variable size */ -+#define DTRACEOPT_AGGSIZE 3 /* aggregation size */ -+#define DTRACEOPT_SPECSIZE 4 /* speculation size */ -+#define DTRACEOPT_NSPEC 5 /* number of speculations */ -+#define DTRACEOPT_STRSIZE 6 /* string size */ -+#define DTRACEOPT_CLEANRATE 7 /* dynvar cleaning rate */ -+#define DTRACEOPT_CPU 8 /* CPU to trace */ -+#define DTRACEOPT_BUFRESIZE 9 /* buffer resizing policy */ -+#define DTRACEOPT_GRABANON 10 /* grab anonymous state, if any */ -+#define DTRACEOPT_FLOWINDENT 11 /* indent function entry/return */ -+#define DTRACEOPT_QUIET 12 /* only output explicitly traced data */ -+#define DTRACEOPT_STACKFRAMES 13 /* number of stack frames */ -+#define DTRACEOPT_USTACKFRAMES 14 /* number of user stack frames */ -+#define DTRACEOPT_AGGRATE 15 /* aggregation snapshot rate */ -+#define DTRACEOPT_SWITCHRATE 16 /* buffer switching rate */ -+#define DTRACEOPT_STATUSRATE 17 /* status rate */ -+#define DTRACEOPT_DESTRUCTIVE 18 /* destructive actions allowed */ -+#define DTRACEOPT_STACKINDENT 19 /* output indent for stack traces */ -+#define DTRACEOPT_RAWBYTES 20 /* always print bytes in raw form */ -+#define DTRACEOPT_JSTACKFRAMES 21 /* number of jstack() frames */ -+#define DTRACEOPT_JSTACKSTRSIZE 22 /* size of jstack() string table */ -+#define DTRACEOPT_AGGSORTKEY 23 /* sort aggregations by key */ -+#define DTRACEOPT_AGGSORTREV 24 /* reverse-sort aggregations */ -+#define DTRACEOPT_AGGSORTPOS 25 /* agg. position to sort on */ -+#define DTRACEOPT_AGGSORTKEYPOS 26 /* agg. key position to sort on */ -+#define DTRACEOPT_QUIETRESIZE 27 /* quieten buffer-resize messages */ -+#define DTRACEOPT_NORESOLVE 28 /* prevent resolution of symbols */ -+#define DTRACEOPT_PCAPSIZE 29 /* number of bytes to be captured */ -+#define DTRACEOPT_MAX 30 /* number of options */ -+ -+#define DTRACEOPT_UNSET (dtrace_optval_t)-2 /* unset option */ -+ -+#define DTRACEOPT_BUFPOLICY_RING 0 /* ring buffer */ -+#define DTRACEOPT_BUFPOLICY_FILL 1 /* fill buffer, then stop */ -+#define DTRACEOPT_BUFPOLICY_SWITCH 2 /* switch buffers */ -+ -+#define DTRACEOPT_BUFRESIZE_AUTO 0 /* automatic resizing */ -+#define DTRACEOPT_BUFRESIZE_MANUAL 1 /* manual resizing */ -+ -+#endif /* _LINUX_DTRACE_OPTIONS_DEFINES_H */ -diff --git a/include/uapi/linux/dtrace/stability.h b/include/uapi/linux/dtrace/stability.h -new file mode 100644 -index 0000000000000000000000000000000000000000..380effdab2916dd2ab0bff8c9b73d1f624476cd0 ---- /dev/null -+++ b/include/uapi/linux/dtrace/stability.h -@@ -0,0 +1,52 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_STABILITY_H -+#define _LINUX_DTRACE_STABILITY_H -+ -+#include <linux/dtrace/universal.h> -+#include <linux/dtrace/stability_defines.h> -+ -+/* -+ * Each DTrace provider advertises the name and data stability of each of its -+ * probe description components, as well as its architectural dependencies. The -+ * D compiler can query the provider attributes (dtrace_pattr_t) in order to -+ * compute the properties of an input program and report them. -+ */ -+ -+typedef struct dtrace_ppriv { -+ uint32_t dtpp_flags; /* privilege flags */ -+ uid_t dtpp_uid; /* user ID */ -+} dtrace_ppriv_t; -+ -+typedef struct dtrace_attribute { -+ dtrace_stability_t dtat_name; /* entity name stability */ -+ dtrace_stability_t dtat_data; /* entity data stability */ -+ dtrace_class_t dtat_class; /* entity data dependency */ -+} dtrace_attribute_t; -+ -+typedef struct dtrace_pattr { -+ struct dtrace_attribute dtpa_provider; /* provider attributes */ -+ struct dtrace_attribute dtpa_mod; /* module attributes */ -+ struct dtrace_attribute dtpa_func; /* function attributes */ -+ struct dtrace_attribute dtpa_name; /* name attributes */ -+ struct dtrace_attribute dtpa_args; /* args[] attributes */ -+} dtrace_pattr_t; -+ -+typedef struct dtrace_providerdesc { -+ char dtvd_name[DTRACE_PROVNAMELEN]; /* provider name */ -+ struct dtrace_pattr dtvd_attr; /* stability attributes */ -+ struct dtrace_ppriv dtvd_priv; /* privileges required */ -+} dtrace_providerdesc_t; -+ -+#endif /* _LINUX_DTRACE_STABILITY_H */ -diff --git a/include/uapi/linux/dtrace/stability_defines.h b/include/uapi/linux/dtrace/stability_defines.h -new file mode 100644 -index 0000000000000000000000000000000000000000..ca58c5c03c2b5456fd9bf89d713b063df0de1f37 ---- /dev/null -+++ b/include/uapi/linux/dtrace/stability_defines.h -@@ -0,0 +1,53 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_STABILITY_DEFINES_H -+#define _LINUX_DTRACE_STABILITY_DEFINES_H -+ -+#include <linux/dtrace/universal.h> -+ -+typedef uint8_t dtrace_stability_t; /* stability code */ -+typedef uint8_t dtrace_class_t; /* architectural dependency class */ -+ -+#define DTRACE_STABILITY_INTERNAL 0 /* private to DTrace itself */ -+#define DTRACE_STABILITY_PRIVATE 1 /* private to Sun (see docs) */ -+#define DTRACE_STABILITY_OBSOLETE 2 /* scheduled for removal */ -+#define DTRACE_STABILITY_EXTERNAL 3 /* not controlled by Sun */ -+#define DTRACE_STABILITY_UNSTABLE 4 /* new or rapidly changing */ -+#define DTRACE_STABILITY_EVOLVING 5 /* less rapidly changing */ -+#define DTRACE_STABILITY_STABLE 6 /* mature interface from Sun */ -+#define DTRACE_STABILITY_STANDARD 7 /* industry standard */ -+#define DTRACE_STABILITY_MAX 7 /* maximum valid stability */ -+ -+#define DTRACE_CLASS_UNKNOWN 0 /* unknown architectural dependency */ -+#define DTRACE_CLASS_CPU 1 /* CPU-module-specific */ -+#define DTRACE_CLASS_PLATFORM 2 /* platform-specific (uname -i) */ -+#define DTRACE_CLASS_GROUP 3 /* hardware-group-specific (uname -m) */ -+#define DTRACE_CLASS_ISA 4 /* ISA-specific (uname -p) */ -+#define DTRACE_CLASS_COMMON 5 /* common to all systems */ -+#define DTRACE_CLASS_MAX 5 /* maximum valid class */ -+ -+#define DTRACE_PRIV_NONE 0x0000 -+#define DTRACE_PRIV_KERNEL 0x0001 -+#define DTRACE_PRIV_USER 0x0002 -+#define DTRACE_PRIV_PROC 0x0004 -+#define DTRACE_PRIV_OWNER 0x0008 -+#define DTRACE_PRIV_ALL (DTRACE_PRIV_KERNEL | DTRACE_PRIV_USER | \ -+ DTRACE_PRIV_PROC | DTRACE_PRIV_OWNER) -+ -+struct dtrace_ppriv; -+struct dtrace_attribute; -+struct dtrace_pattr; -+struct dtrace_providerdesc; -+ -+#endif /* _LINUX_DTRACE_STABILITY_DEFINES_H */ -diff --git a/include/uapi/linux/dtrace/status.h b/include/uapi/linux/dtrace/status.h -new file mode 100644 -index 0000000000000000000000000000000000000000..dc324199f170381f3ff661228143751a200669ca ---- /dev/null -+++ b/include/uapi/linux/dtrace/status.h -@@ -0,0 +1,50 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_STATUS_H -+#define _LINUX_DTRACE_STATUS_H -+ -+#include <linux/dtrace/universal.h> -+ -+/* -+ * The status of DTrace is relayed via the dtrace_status structure. This -+ * structure contains members to count drops other than the capacity drops -+ * available via the buffer interface (see above). This consists of dynamic -+ * drops (including capacity dynamic drops, rinsing drops and dirty drops), and -+ * speculative drops (including capacity speculative drops, drops due to busy -+ * speculative buffers and drops due to unavailable speculative buffers). -+ * Additionally, the status structure contains a field to indicate the number -+ * of "fill"-policy buffers have been filled and a boolean field to indicate -+ * that exit() has been called. If the dtst_exiting field is non-zero, no -+ * further data will be generated until tracing is stopped (at which time any -+ * enablings of the END action will be processed); if user-level sees that -+ * this field is non-zero, tracing should be stopped as soon as possible. -+ */ -+ -+typedef struct dtrace_status { -+ uint64_t dtst_dyndrops; /* dynamic drops */ -+ uint64_t dtst_dyndrops_rinsing; /* dyn drops due to rinsing */ -+ uint64_t dtst_dyndrops_dirty; /* dyn drops due to dirty */ -+ uint64_t dtst_specdrops; /* speculative drops */ -+ uint64_t dtst_specdrops_busy; /* spec drops due to busy */ -+ uint64_t dtst_specdrops_unavail; /* spec drops due to unavail */ -+ uint64_t dtst_errors; /* total errors */ -+ uint64_t dtst_filled; /* number of filled bufs */ -+ uint64_t dtst_stkstroverflows; /* stack string tab overflows */ -+ uint64_t dtst_dblerrors; /* errors in ERROR probes */ -+ char dtst_killed; /* non-zero if killed */ -+ char dtst_exiting; /* non-zero if exit() called */ -+ char dtst_pad[6]; /* pad out to 64-bit align */ -+} dtrace_status_t; -+ -+#endif /* _LINUX_DTRACE_STATUS_H */ -diff --git a/include/uapi/linux/dtrace/universal.h b/include/uapi/linux/dtrace/universal.h -new file mode 100644 -index 0000000000000000000000000000000000000000..5c2f3f838fef435bf44cd0d4581900f1446fef12 ---- /dev/null -+++ b/include/uapi/linux/dtrace/universal.h -@@ -0,0 +1,47 @@ -+/* SPDX-License-Identifier: UPL-1.0 */ -+/* -+ * Licensed under the Universal Permissive License v 1.0 as shown at -+ * http://oss.oracle.com/licenses/upl. -+ * -+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _LINUX_DTRACE_UNIVERSAL_H_ -+#define _LINUX_DTRACE_UNIVERSAL_H_ -+ -+#define DTRACE_CPUALL -1 /* all CPUs */ -+#define DTRACE_IDNONE 0 /* invalid probe identifier */ -+#define DTRACE_EPIDNONE 0 /* invalid enabled probe identifier */ -+#define DTRACE_AGGIDNONE 0 /* invalid aggregation identifier */ -+#define DTRACE_AGGVARIDNONE 0 /* invalid aggregation variable ID */ -+#define DTRACE_CACHEIDNONE 0 /* invalid predicate cache */ -+#define DTRACE_PROVNONE 0 /* invalid provider identifier */ -+#define DTRACE_METAPROVNONE 0 /* invalid meta-provider identifier */ -+#define DTRACE_ARGNONE -1 /* invalid argument index */ -+ -+#define DTRACE_PROVNAMELEN 64 -+#define DTRACE_MODNAMELEN 64 -+#define DTRACE_FUNCNAMELEN 128 -+#define DTRACE_NAMELEN 64 -+#define DTRACE_FULLNAMELEN (DTRACE_PROVNAMELEN + DTRACE_MODNAMELEN + \ -+ DTRACE_FUNCNAMELEN + DTRACE_NAMELEN + 4) -+#define DTRACE_ARGTYPELEN 128 -+ -+typedef uint16_t dtrace_actkind_t; /* action kind */ -+ -+typedef uint32_t dtrace_aggid_t; /* aggregation identifier */ -+typedef uint32_t dtrace_cacheid_t; /* predicate cache identifier */ -+typedef uint32_t dtrace_epid_t; /* enabled probe identifier */ -+typedef uint32_t dtrace_optid_t; /* option identifier */ -+typedef uint32_t dtrace_specid_t; /* speculation identifier */ -+ -+typedef uint64_t dtrace_aggvarid_t; /* aggregation variable id */ -+typedef uint64_t dtrace_genid_t; /* generation identifier */ -+typedef uint64_t dtrace_optval_t; /* option value */ -+ -+#endif /* _LINUX_DTRACE_UNIVERSAL_H_ */ -diff --git a/init/Kconfig b/init/Kconfig -index 5a86bbbf43e052f9092da824536c8e223c4a4329..0f1b919272daaa02ac0b40632641e5e0079721de 100644 ---- a/init/Kconfig -+++ b/init/Kconfig -@@ -2052,6 +2052,8 @@ config PROFILING - Say Y here to enable the extended profiling support mechanisms used - by profilers such as OProfile. - -+source "kernel/dtrace/Kconfig" -+ - # - # Place an empty function call at each tracepoint site. Can be - # dynamically changed for a probe function. -diff --git a/init/main.c b/init/main.c -index 9d964511fe0c2d9e8e0d3e8178fd237690415ce9..f510b7af38c20bca171a3d146781f99d37e8936a 100644 ---- a/init/main.c -+++ b/init/main.c -@@ -98,6 +98,8 @@ - #include <linux/mem_encrypt.h> - #include <linux/kcsan.h> - #include <linux/init_syscalls.h> -+#include <linux/dtrace_cpu.h> -+#include <linux/dtrace_os.h> - - #include <asm/io.h> - #include <asm/bugs.h> -@@ -1057,6 +1059,10 @@ asmlinkage __visible void __init __no_sanitize_address start_kernel(void) - sfi_init_late(); - kcsan_init(); - -+#ifdef CONFIG_DTRACE -+ dtrace_os_init(); -+#endif -+ - /* Do the rest non-__init'ed, we're now alive */ - arch_call_rest_init(); - -@@ -1512,6 +1518,10 @@ static noinline void __init kernel_init_freeable(void) - - init_mm_internals(); - -+#ifdef CONFIG_DTRACE -+ dtrace_cpu_init(); -+#endif -+ - rcu_init_tasks_generic(); - do_pre_smp_initcalls(); - lockup_detector_init(); -diff --git a/kernel/Makefile b/kernel/Makefile -index 6c9f19911be03e526e29389811fda6247656a253..498cb12d89c6f57f44dd7e48f025f0176dfcbe44 100644 ---- a/kernel/Makefile -+++ b/kernel/Makefile -@@ -121,6 +121,7 @@ obj-$(CONFIG_TORTURE_TEST) += torture.o - obj-$(CONFIG_HAS_IOMEM) += iomem.o - obj-$(CONFIG_RSEQ) += rseq.o - obj-$(CONFIG_WATCH_QUEUE) += watch_queue.o -+obj-$(CONFIG_DTRACE) += dtrace/ - - obj-$(CONFIG_SYSCTL_KUNIT_TEST) += sysctl-test.o - -diff --git a/kernel/dtrace/Kconfig b/kernel/dtrace/Kconfig -new file mode 100644 -index 0000000000000000000000000000000000000000..854e4411343f9f7c773bf7fd54349fa46e6de5cb ---- /dev/null -+++ b/kernel/dtrace/Kconfig -@@ -0,0 +1,54 @@ -+# -+# Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved. -+# -+ -+menuconfig DTRACE -+ bool "DTrace (Dynamic Tracing) Support" -+ default y -+ depends on ARCH_SUPPORTS_DTRACE -+ select KALLSYMS -+ select KALLMODSYMS -+ select WAITFD -+ select CTF -+ help -+ The DTrace dynamic tracing framework. -+ -+if DTRACE -+ -+config DT_CORE -+ tristate "DTrace core" -+ default m -+ help -+ The core of DTrace: needed for all providers. -+ -+if DT_CORE -+ -+config DT_DT_TEST -+ tristate "DTrace Test Probe" -+ default m -+ help -+ A test provider used by the testsuite. -+ -+config DT_DEBUG -+ bool "DTrace debugging" -+ default m -+ help -+ This controls the inclusion of various piece of code that perform -+ internal checks within the DTrace core. It also enables all the -+ assertions within the DTrace code. -+ -+if DT_DEBUG -+ -+config DT_DEBUG_MUTEX -+ bool "DTrace mutex debugging" -+ default n -+ help -+ This controls the use of DTrace specific wrappers to output debug -+ messages whenever a mutex is locked or unlocked within the DTrace -+ code (core and providers). -+ -+endif # DT_DEBUG -+ -+endif # DT_CORE -+ -+endif #DTRACE -diff --git a/kernel/dtrace/Makefile b/kernel/dtrace/Makefile -new file mode 100644 -index 0000000000000000000000000000000000000000..872785327c3d8d9f1ec0e5555b86fd470e9d1fc2 ---- /dev/null -+++ b/kernel/dtrace/Makefile -@@ -0,0 +1,12 @@ -+# -+# Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. -+# -+ -+DT_CORE_ARCH_OBJS = $(addprefix ../../arch/$(SRCARCH)/kernel/, \ -+ dtrace_util.o) -+ -+ifdef CONFIG_DT_CORE -+obj-y += cyclic.o dtrace_os.o dtrace_cpu.o \ -+ dtrace_task.o dtrace_psinfo.o \ -+ $(DT_CORE_ARCH_OBJS) -+endif -diff --git a/kernel/dtrace/cyclic.c b/kernel/dtrace/cyclic.c -new file mode 100644 -index 0000000000000000000000000000000000000000..6497ceee378235267ca65c492f8a7e2656b34d5b ---- /dev/null -+++ b/kernel/dtrace/cyclic.c -@@ -0,0 +1,526 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: cyclic.c -+ * DESCRIPTION: Minimal cyclic implementation -+ * -+ * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/cpu.h> -+#include <linux/cyclic.h> -+#include <linux/hrtimer.h> -+#include <linux/module.h> -+#include <linux/proc_fs.h> -+#include <linux/seq_file.h> -+#include <linux/slab.h> -+#include <linux/spinlock.h> -+#include <linux/workqueue.h> -+ -+static int omni_enabled; -+ -+#define _CYCLIC_CPU_UNDEF (-1) -+#define _CYCLIC_CPU_OMNI (-2) -+#define CYCLIC_IS_OMNI(cyc) ((cyc)->cpu == _CYCLIC_CPU_OMNI) -+ -+struct cyclic_work { -+ struct work_struct work; -+ struct cyclic *cyc; -+}; -+ -+struct cyclic { -+ struct list_head list; -+ int cpu; -+ union { -+ struct { -+ struct cyc_time when; -+ struct cyc_handler hdlr; -+ uint32_t pend; -+ struct hrtimer timr; -+ struct cyclic_work work; -+ } cyc; -+ struct { -+ struct cyc_omni_handler hdlr; -+ struct list_head cycl; -+ } omni; -+ }; -+}; -+ -+static LIST_HEAD(cyclics); -+ -+static void cyclic_fire(struct work_struct *work) -+{ -+ struct cyclic_work *cwork = (struct cyclic_work *)work; -+ struct cyclic *cyc = cwork->cyc; -+ uint32_t cpnd, npnd; -+ -+ do { -+ /* -+ * We know that the 'pend' counter for the cyclic is non-zero. -+ * So, we can start with calling the handler at least once. -+ */ -+ (*cyc->cyc.hdlr.cyh_func)(cyc->cyc.hdlr.cyh_arg); -+ -+again: -+ /* -+ * The 'pend' counter may be modified by cyclic_expire() while -+ * we go through this loop. We use an atomic compare-and-set -+ * instruction to determine whether it got changed. If so, we -+ * retrieve the updated 'pend' value and try this again. -+ * -+ * Note that when the cyclic is being removed, the hrtimer will -+ * be cancelled first, which ensures that 'pend' will no longer -+ * be incremented. When that happens, this loop will simply -+ * run through the remaining pending calls, and terminate. -+ */ -+ cpnd = cyc->cyc.pend; -+ npnd = cpnd - 1; -+ if (cmpxchg(&cyc->cyc.pend, cpnd, npnd) != cpnd) -+ goto again; -+ } while (npnd > 0); -+} -+ -+/* -+ * Timer expiration handler for cyclic hrtimers. Cyclic worker functions must -+ * be able to perform a variety of tasks (including calling functions that -+ * could sleep), and therefore they cannot be called from interrupt context. -+ * -+ * We schedule a workqueue to do the actual work. -+ * -+ * But... under heavy load it is possible that the hrtimer will expire again -+ * before the workqueue had a chance to run. That would lead to missed events -+ * which isn't quite acceptable. Therefore, we use a counter to record how -+ * many times the timer has expired vs how many times the handler has been -+ * called. The counter is incremented by this function upon hrtimer expiration -+ * and decremented by the cyclic_fire. Note that the workqueue is responsible -+ * for calling the handler multiple times if the counter indicates that multiple -+ * invocation are pending. -+ * -+ * This function is called as hrtimer handler, and therefore runs in interrupt -+ * context, which by definition will ensure that manipulation of the 'pend' -+ * counter in the cyclic can be done without locking, and changes will appear -+ * atomic to the cyclic_fire(). -+ * -+ * Moral of the story: the handler may not get called at the absolute times as -+ * requested, but it will be called the correct number of times. -+ */ -+static enum hrtimer_restart cyclic_expire(struct hrtimer *timr) -+{ -+ struct cyclic *cyc = container_of(timr, struct cyclic, cyc.timr); -+ -+ /* -+ * High priority cyclics call directly into their handler. This means -+ * that the handler must satisfy all requirements for executing code in -+ * interrupt context. -+ */ -+ if (cyc->cyc.hdlr.cyh_level == CY_HIGH_LEVEL) { -+ (*cyc->cyc.hdlr.cyh_func)(cyc->cyc.hdlr.cyh_arg); -+ goto done; -+ } -+ -+ /* -+ * Increment the 'pend' counter, in case the work is already set to -+ * run. If the counter was 0 upon entry, we need to schedule the -+ * work. If the increment wraps the counter back to 0, we admit -+ * defeat, and reset it to its max value. -+ */ -+ if (cyc->cyc.pend++ == 0) -+ schedule_work_on(cyc->cpu, -+ (struct work_struct *)&cyc->cyc.work); -+ else if (cyc->cyc.pend == 0) -+ cyc->cyc.pend = UINT_MAX; -+ -+done: -+ /* -+ * Prepare the timer for the next expiration. -+ */ -+ if (cyc->cyc.when.cyt_interval == CY_INTERVAL_INF) -+ return HRTIMER_NORESTART; -+ -+ hrtimer_forward_now(timr, cyc->cyc.when.cyt_interval); -+ -+ return HRTIMER_RESTART; -+} -+ -+struct cyclic *cyclic_new(int omni) -+{ -+ struct cyclic *cyc; -+ -+ cyc = kmalloc(sizeof(struct cyclic), GFP_KERNEL); -+ if (cyc == NULL) -+ return NULL; -+ -+ INIT_LIST_HEAD(&cyc->list); -+ -+ if (!omni) { -+ cyc->cpu = _CYCLIC_CPU_UNDEF; -+ cyc->cyc.pend = 0; -+ hrtimer_init(&cyc->cyc.timr, CLOCK_MONOTONIC, -+ HRTIMER_MODE_REL_PINNED); -+ cyc->cyc.timr.function = cyclic_expire; -+ cyc->cyc.work.cyc = cyc; -+ INIT_WORK((struct work_struct *)&cyc->cyc.work, cyclic_fire); -+ } else { -+ cyc->cpu = _CYCLIC_CPU_OMNI; -+ INIT_LIST_HEAD(&cyc->omni.cycl); -+ } -+ -+ return cyc; -+} -+ -+static inline void cyclic_restart(struct cyclic *cyc) -+{ -+ if (cyc->cyc.when.cyt_interval == CY_INTERVAL_INF) -+ return; -+ -+ if (cyc->cyc.when.cyt_when == 0) -+ hrtimer_start(&cyc->cyc.timr, cyc->cyc.when.cyt_interval, -+ HRTIMER_MODE_REL_PINNED); -+ else -+ hrtimer_start(&cyc->cyc.timr, cyc->cyc.when.cyt_when, -+ HRTIMER_MODE_ABS_PINNED); -+} -+ -+/* -+ * Add a new cyclic to the system. -+ */ -+cyclic_id_t cyclic_add(struct cyc_handler *hdlr, struct cyc_time *when) -+{ -+ struct cyclic *cyc; -+ -+ if (hdlr == NULL || when == NULL) -+ return CYCLIC_NONE; -+ -+ cyc = cyclic_new(0); -+ if (cyc == NULL) -+ return CYCLIC_NONE; -+ -+ list_add(&cyc->list, &cyclics); -+ cyc->cpu = smp_processor_id(); -+ cyc->cyc.when = *when; -+ cyc->cyc.hdlr = *hdlr; -+ -+ cyclic_restart(cyc); -+ -+ return (cyclic_id_t)cyc; -+} -+EXPORT_SYMBOL(cyclic_add); -+ -+static void cyclic_omni_xcall(struct cyclic *cyc) -+{ -+ cyclic_restart(cyc); -+} -+ -+/* -+ * Add a new cyclic to the system. -+ */ -+static void cyclic_add_pinned(int cpu, struct cyclic *omni, -+ struct cyc_handler *hdlr, struct cyc_time *when) -+{ -+ struct cyclic *cyc; -+ -+ cyc = cyclic_new(0); -+ if (cyc == NULL) -+ return; -+ -+ list_add(&cyc->list, &omni->omni.cycl); -+ cyc->cpu = cpu; -+ cyc->cyc.when = *when; -+ cyc->cyc.hdlr = *hdlr; -+ -+ smp_call_function_single(cpu, (smp_call_func_t)cyclic_omni_xcall, -+ cyc, 1); -+} -+ -+/* -+ * Start a cyclic on a specific CPU as sub-cyclic to an omni-present cyclic. -+ */ -+static void cyclic_omni_start(struct cyclic *omni, int cpu) -+{ -+ struct cyc_time when; -+ struct cyc_handler hdlr; -+ -+ omni->omni.hdlr.cyo_online(omni->omni.hdlr.cyo_arg, cpu, &hdlr, &when); -+ cyclic_add_pinned(cpu, omni, &hdlr, &when); -+} -+ -+#ifdef CONFIG_HOTPLUG_CPU -+static int cyclic_cpu_offline(unsigned int cpu) -+{ -+ struct cyclic *cyc; -+ -+ list_for_each_entry(cyc, &cyclics, list) { -+ struct cyclic *c, *n; -+ -+ if (!CYCLIC_IS_OMNI(cyc)) -+ continue; -+ -+ list_for_each_entry_safe(c, n, &cyc->omni.cycl, list) { -+ if (c->cpu == cpu) -+ cyclic_remove((cyclic_id_t)c); -+ } -+ } -+ return 0; -+} -+ -+static int cyclic_cpu_online(unsigned int cpu) -+{ -+ struct cyclic *cyc; -+ -+ list_for_each_entry(cyc, &cyclics, list) { -+ struct cyclic *c, *n; -+ -+ if (!CYCLIC_IS_OMNI(cyc)) -+ continue; -+ -+ list_for_each_entry_safe(c, n, &cyc->omni.cycl, list) { -+ if (c->cpu == cpu) -+ break; -+ } -+ -+ if (c->cpu == cpu) -+ continue; -+ -+ cyclic_omni_start(cyc, cpu); -+ } -+ return 0; -+} -+#endif -+ -+/* -+ * Add a new omnipresent cyclic to the system. -+ */ -+cyclic_id_t cyclic_add_omni(struct cyc_omni_handler *omni) -+{ -+ int cpu; -+ struct cyclic *cyc; -+ -+ cyc = cyclic_new(1); -+ if (cyc == NULL) -+ return CYCLIC_NONE; -+ -+ list_add(&cyc->list, &cyclics); -+ cyc->omni.hdlr = *omni; -+ -+ for_each_online_cpu(cpu) -+ cyclic_omni_start(cyc, cpu); -+ -+ return (cyclic_id_t)cyc; -+} -+EXPORT_SYMBOL(cyclic_add_omni); -+ -+/* -+ * Remove a specific cyclic from the system. -+ */ -+void cyclic_remove(cyclic_id_t id) -+{ -+ struct cyclic *cyc = (struct cyclic *)id; -+ -+ if (CYCLIC_IS_OMNI(cyc)) { -+ struct cyclic *child, *n; -+ -+ /* -+ * If this is an omni-present cyclic, we first need to remove -+ * all the associated per-CPU cyclics. Note that the recursive -+ * call into cyclic_remove() for a child cyclic will remove it -+ * from the list of per-CPU cyclics associated with the -+ * omni-present cyclic, so we do not need to handle that here. -+ */ -+ list_for_each_entry_safe(child, n, &cyc->omni.cycl, list) -+ cyclic_remove((cyclic_id_t)child); -+ } else { -+ /* -+ * We know that hrtimer_cancel() will wait for the timer -+ * callback to finish if it is being executed at the time of -+ * making this call. It is therefore guaranteed that 'pend' -+ * will no longer get incremented. -+ * -+ * The call to cancel_work_sync() will wait for the workqueue -+ * handler to finish also, and since the handler always brings -+ * 'pend' down to zero prior to returning, it is guaranteed that -+ * (1) all pending handler calls will be made before -+ * cyclic_remove() returns -+ * (2) the amount of work to do before returning is finite. -+ */ -+ hrtimer_cancel(&cyc->cyc.timr); -+ cancel_work_sync((struct work_struct *)&cyc->cyc.work); -+ } -+ -+ list_del(&cyc->list); -+ kfree(cyc); -+} -+EXPORT_SYMBOL(cyclic_remove); -+ -+struct cyclic_reprog { -+ cyclic_id_t cycid; -+ ktime_t delta; -+}; -+ -+static void cyclic_reprogram_xcall(struct cyclic_reprog *creprog) -+{ -+ cyclic_reprogram(creprog->cycid, creprog->delta); -+} -+ -+/* -+ * Reprogram cyclic to fire with given delta from now. -+ * -+ * The underlying design makes it safe to call cyclic_reprogram from whithin a -+ * cyclic handler without race with cyclic_remove. If called from outside of the -+ * cyclic handler it is up to the owner to ensure to not call cyclic_reprogram -+ * after call to cyclic_remove. -+ * -+ * This function cannot be called from interrupt/bottom half contexts. -+ */ -+void cyclic_reprogram(cyclic_id_t id, ktime_t delta) -+{ -+ struct cyclic *cyc = (struct cyclic *)id; -+ -+ /* -+ * For omni present cyclic we reprogram child for current CPU. -+ */ -+ if (CYCLIC_IS_OMNI(cyc)) { -+ struct cyclic *c, *n; -+ -+ list_for_each_entry_safe(c, n, &cyc->omni.cycl, list) { -+ if (c->cpu != smp_processor_id()) -+ continue; -+ -+ hrtimer_start(&c->cyc.timr, delta, -+ HRTIMER_MODE_ABS_PINNED); -+ -+ break; -+ } -+ -+ return; -+ } -+ -+ /* -+ * Regular cyclic reprogram must ensure that the timer remains bound -+ * to the CPU it was registered on. In case we are called from -+ * different CPU we use xcall to trigger reprogram from correct cpu. -+ */ -+ if (cyc->cpu != smp_processor_id()) { -+ struct cyclic_reprog creprog = { -+ .cycid = id, -+ .delta = delta, -+ }; -+ -+ smp_call_function_single(cyc->cpu, (smp_call_func_t) -+ cyclic_reprogram_xcall, &creprog, 1); -+ } else { -+ hrtimer_start(&cyc->cyc.timr, delta, HRTIMER_MODE_REL_PINNED); -+ } -+} -+EXPORT_SYMBOL(cyclic_reprogram); -+ -+static void *s_start(struct seq_file *seq, loff_t *pos) -+{ -+ loff_t n = *pos; -+ struct cyclic *cyc; -+ -+ list_for_each_entry(cyc, &cyclics, list) { -+ if (n == 0) -+ return cyc; -+ -+ n--; -+ } -+ -+ return NULL; -+} -+ -+static void *s_next(struct seq_file *seq, void *p, loff_t *pos) -+{ -+ struct cyclic *cyc = p; -+ -+ ++*pos; -+ -+ cyc = list_entry(cyc->list.next, struct cyclic, list); -+ if (&cyc->list == &cyclics) -+ return NULL; -+ -+ return cyc; -+} -+ -+static void s_stop(struct seq_file *seq, void *p) -+{ -+} -+ -+static int s_show(struct seq_file *seq, void *p) -+{ -+ struct cyclic *cyc = p; -+ -+ if (CYCLIC_IS_OMNI(cyc)) { -+ struct cyclic *c; -+ -+ seq_puts(seq, "Omni-present cyclic:\n"); -+ list_for_each_entry(c, &cyc->omni.cycl, list) -+ seq_printf(seq, -+ " CPU-%d: %c %lld ns hdlr %pB arg %llx\n", -+ c->cpu, -+ c->cyc.hdlr.cyh_level == CY_HIGH_LEVEL -+ ? 'H' : 'l', -+ c->cyc.when.cyt_interval, -+ c->cyc.hdlr.cyh_func, -+ (uint64_t)c->cyc.hdlr.cyh_arg); -+ } else -+ seq_printf(seq, "CPU-%d: %c %lld ns hdlr %pB arg %llx\n", -+ cyc->cpu, -+ cyc->cyc.hdlr.cyh_level == CY_HIGH_LEVEL -+ ? 'H' : 'l', -+ cyc->cyc.when.cyt_interval, -+ cyc->cyc.hdlr.cyh_func, -+ (uint64_t)cyc->cyc.hdlr.cyh_arg); -+ -+ return 0; -+} -+ -+static const struct seq_operations cyclicinfo_ops = { -+ .start = s_start, -+ .next = s_next, -+ .stop = s_stop, -+ .show = s_show, -+}; -+ -+static int cyclicinfo_open(struct inode *inode, struct file *file) -+{ -+ return seq_open(file, &cyclicinfo_ops); -+} -+ -+static const struct proc_ops proc_cyclicinfo_ops = { -+ .proc_open = cyclicinfo_open, -+ .proc_read = seq_read, -+ .proc_lseek = seq_lseek, -+ .proc_release = seq_release, -+}; -+ -+static int __init cyclic_init(void) -+{ -+ int ret; -+ -+ proc_create("cyclicinfo", 0400, NULL, &proc_cyclicinfo_ops); -+ -+#ifdef CONFIG_HOTPLUG_CPU -+ if (!omni_enabled) { -+ ret = cpuhp_setup_state_nocalls(CPUHP_AP_CYCLIC_STARTING, -+ "Cyclic omni-timer starting", -+ cyclic_cpu_online, -+ cyclic_cpu_offline); -+ if (ret) -+ pr_warn_once("Cannot enable cyclic omni timer\n"); -+ else -+ omni_enabled = 1; -+ } -+#endif -+ -+ return 0; -+} -+module_init(cyclic_init); -diff --git a/kernel/dtrace/dtrace_cpu.c b/kernel/dtrace/dtrace_cpu.c -new file mode 100644 -index 0000000000000000000000000000000000000000..1bc6e3bb4ce01141e5c94a52766f0553793e49c0 ---- /dev/null -+++ b/kernel/dtrace/dtrace_cpu.c -@@ -0,0 +1,61 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_cpu.c -+ * DESCRIPTION: DTrce - per-CPU state -+ * -+ * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/dtrace_cpu.h> -+#include <linux/module.h> -+#include <asm/dtrace_cpuinfo.h> -+ -+DEFINE_PER_CPU_SHARED_ALIGNED(struct cpu_core, dtrace_cpu_core); -+EXPORT_PER_CPU_SYMBOL(dtrace_cpu_core); -+ -+DEFINE_PER_CPU_SHARED_ALIGNED(struct cpuinfo, dtrace_cpu_info); -+EXPORT_PER_CPU_SYMBOL(dtrace_cpu_info); -+ -+void dtrace_cpu_init(void) -+{ -+ int cpu; -+ -+ /* -+ * Force this type into the CTF for the sake of userspace's -+ * ABI requirements. -+ */ -+ cpuinfo_t *dummy __attribute__((__unused__)) = NULL; -+ -+ for_each_present_cpu(cpu) { -+ cpuinfo_arch_t *ci = &cpu_data(cpu); -+ struct cpuinfo *cpui = per_cpu_info(cpu); -+ struct cpu_core *cpuc = per_cpu_core(cpu); -+ -+ cpui->cpu_id = cpu; -+ cpui->cpu_pset = 0; -+ cpui->cpu_chip = dtrace_cpuinfo_chip(ci); -+ cpui->cpu_lgrp = 0; -+ cpui->cpu_info = ci; -+ -+ cpuc->cpuc_dtrace_flags = 0; -+ cpuc->cpuc_dcpc_intr_state = 0; -+ cpuc->cpuc_dtrace_illval = 0; -+ mutex_init(&cpuc->cpuc_pid_lock); -+ -+ cpuc->cpu_dtrace_regs = NULL; -+ cpuc->cpu_dtrace_caller = 0; -+ rwlock_init(&cpuc->cpu_ft_lock); -+ -+ cpuc->cpuc_current_probe = DTRACE_IDNONE; -+ } -+} -diff --git a/kernel/dtrace/dtrace_os.c b/kernel/dtrace/dtrace_os.c -new file mode 100644 -index 0000000000000000000000000000000000000000..d023f3913323b42678aee5a7467a4b39c378c8cc ---- /dev/null -+++ b/kernel/dtrace/dtrace_os.c -@@ -0,0 +1,332 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_os.c -+ * DESCRIPTION: DTrace - OS support functions -+ * -+ * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/binfmts.h> -+#include <linux/dtrace_cpu.h> -+#include <linux/dtrace_os.h> -+#include <linux/fs.h> -+#include <linux/hardirq.h> -+#include <linux/interrupt.h> -+#include <linux/kdebug.h> -+#include <linux/module.h> -+#include <linux/moduleloader.h> -+#include <linux/sched.h> -+#include <linux/slab.h> -+#include <linux/stacktrace.h> -+#include <linux/timekeeping.h> -+#include <linux/vmalloc.h> -+#include <linux/kallsyms.h> -+#include <linux/uaccess.h> -+#include <linux/workqueue.h> -+#include <asm/ptrace.h> -+#include <linux/init_task.h> -+#include <linux/sched/mm.h> -+#include <linux/shmem_fs.h> -+#include <linux/dtrace_task_impl.h> -+ -+/* -+ * OS SPECIFIC DTRACE SETUP -+ */ -+ -+/* -+ * DTrace pseudo module that represents vmlinux (the kernel itself). -+ * Since we populate its sdt data members only once, it can be marked -+ * as RO after init. -+ */ -+struct module *dtrace_kmod __ro_after_init = NULL; -+EXPORT_SYMBOL(dtrace_kmod); -+ -+int dtrace_ustackdepth_max = 2048; -+ -+struct kmem_cache *dtrace_pdata_cachep = NULL; -+ -+void __init dtrace_os_init(void) -+{ -+ /* -+ * Setup for module handling. -+ */ -+ dtrace_pdata_cachep = kmem_cache_create("dtrace_pdata_cache", -+ sizeof(struct dtrace_module), 0, -+ SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); -+ if (dtrace_pdata_cachep == NULL) -+ pr_debug("Can't allocate kmem cache for pdata\n"); -+ -+ /* -+ * We need to set up a psinfo structure for PID 0 (swapper). -+ */ -+ dtrace_task_os_init(); -+ dtrace_psinfo_os_init(); -+ dtrace_task_init(&init_task); -+ dtrace_psinfo_alloc(&init_task); -+} -+ -+/* -+ * MODULE SUPPORT FUNCTIONS -+ */ -+extern struct list_head *dtrace_modules; -+ -+/* -+ * Iterate over all loaded kernel modules. This is required until the linux -+ * kernel receives its own module iterator. -+ */ -+void dtrace_for_each_module(for_each_module_fn func, void *arg) -+{ -+ struct module *mp; -+ -+ if (func == NULL) -+ return; -+ -+ /* The dtrace fake module is not in the list. */ -+ func(arg, dtrace_kmod); -+ -+ list_for_each_entry(mp, dtrace_modules, list) { -+ -+#ifdef MODULES_VADDR -+ if ((uintptr_t)mp < MODULES_VADDR || -+ (uintptr_t)mp >= MODULES_END) -+ continue; -+#else -+ if ((uintptr_t)mp < VMALLOC_START || -+ (uintptr_t)mp >= VMALLOC_END) -+ continue; -+#endif -+ -+ func(arg, mp); -+ } -+} -+EXPORT_SYMBOL_GPL(dtrace_for_each_module); -+ -+ -+void dtrace_mod_pdata_alloc(struct module *mp) -+{ -+ struct dtrace_module *pdata; -+ -+ pdata = kmem_cache_alloc(dtrace_pdata_cachep, GFP_KERNEL | __GFP_ZERO); -+ if (pdata == NULL) { -+ mp->pdata = NULL; -+ return; -+ } -+ -+ dtrace_mod_pdata_init(pdata); -+ mp->pdata = pdata; -+} -+ -+void dtrace_mod_pdata_free(struct module *mp) -+{ -+ struct dtrace_module *pdata = mp->pdata; -+ -+ if (mp->pdata == NULL) -+ return; -+ -+ mp->pdata = NULL; -+ dtrace_mod_pdata_cleanup(pdata); -+ kmem_cache_free(dtrace_pdata_cachep, pdata); -+} -+ -+/* -+ * This function is called with module_mutex held. -+ */ -+int dtrace_destroy_prov(struct module *mp) -+{ -+ struct dtrace_module *pdata = mp->pdata; -+ -+ if (pdata != NULL && pdata->prov_exit != NULL) -+ return pdata->prov_exit(); -+ -+ return 1; -+} -+ -+/*---------------------------------------------------------------------------*\ -+(* TIME SUPPORT FUNCTIONS *) -+\*---------------------------------------------------------------------------*/ -+enum dtrace_vtime_state dtrace_vtime_active = 0; -+ -+/* -+ * Until Linux kernel gains lock-free realtime clock access we are maintaining -+ * our own version for lock-free access from within a probe context. -+ */ -+static struct dtrace_time_fast { -+ seqcount_latch_t dtwf_seq; -+ ktime_t dtwf_offsreal[2]; -+} dtrace_time ____cacheline_aligned; -+ -+/* -+ * Callback from timekeeper code that allows dtrace to update its own time data. -+ */ -+void dtrace_update_time(struct timekeeper *tk) -+{ -+ raw_write_seqcount_latch(&dtrace_time.dtwf_seq); -+ dtrace_time.dtwf_offsreal[0] = tk->offs_real; -+ raw_write_seqcount_latch(&dtrace_time.dtwf_seq); -+ dtrace_time.dtwf_offsreal[1] = tk->offs_real; -+} -+ -+/* Lock free walltime */ -+ktime_t dtrace_get_walltime(void) -+{ -+ u64 nsec = ktime_get_mono_fast_ns(); -+ unsigned int seq; -+ ktime_t offset; -+ -+ do { -+ seq = raw_read_seqcount_latch(&dtrace_time.dtwf_seq); -+ offset = dtrace_time.dtwf_offsreal[seq & 0x1]; -+ } while (read_seqcount_latch_retry(&dtrace_time.dtwf_seq, seq)); -+ -+ return ktime_add_ns(offset, nsec); -+} -+EXPORT_SYMBOL(dtrace_get_walltime); -+ -+ktime_t dtrace_gethrtime(void) -+{ -+ return ns_to_ktime(ktime_get_raw_fast_ns()); -+} -+EXPORT_SYMBOL(dtrace_gethrtime); -+ -+/* Needed for lockstat probes where we cannot include ktime.h */ -+u64 dtrace_gethrtime_ns(void) -+{ -+ return ktime_get_raw_fast_ns(); -+} -+EXPORT_SYMBOL(dtrace_gethrtime_ns); -+ -+void dtrace_vtime_enable(void) -+{ -+ enum dtrace_vtime_state old, new; -+ -+ do { -+ old = dtrace_vtime_active; -+ if (old == DTRACE_VTIME_ACTIVE) { -+ pr_warn_once("DTrace virtual time already enabled"); -+ return; -+ } -+ -+ new = DTRACE_VTIME_ACTIVE; -+ } while (cmpxchg(&dtrace_vtime_active, old, new) != old); -+} -+EXPORT_SYMBOL(dtrace_vtime_enable); -+ -+void dtrace_vtime_disable(void) -+{ -+ int old, new; -+ -+ do { -+ old = dtrace_vtime_active; -+ if (old == DTRACE_VTIME_INACTIVE) { -+ pr_warn_once("DTrace virtual time already disabled"); -+ return; -+ } -+ -+ new = DTRACE_VTIME_INACTIVE; -+ } while (cmpxchg(&dtrace_vtime_active, old, new) != old); -+} -+EXPORT_SYMBOL(dtrace_vtime_disable); -+ -+void dtrace_vtime_switch(struct task_struct *prev, struct task_struct *next) -+{ -+ struct dtrace_task *dprev = prev->dt_task; -+ struct dtrace_task *dnext = next->dt_task; -+ ktime_t now = dtrace_gethrtime(); -+ -+ if (dprev != NULL && ktime_nz(dprev->dt_start)) { -+ dprev->dt_vtime = ktime_add(dprev->dt_vtime, -+ ktime_sub(now, -+ dprev->dt_start)); -+ dprev->dt_start = ktime_set(0, 0); -+ } -+ -+ if (dnext != NULL) -+ dnext->dt_start = now; -+} -+ -+void dtrace_stacktrace(struct stacktrace_state *st) -+{ -+ int i; -+ -+ if ((st->flags & STACKTRACE_TYPE) == STACKTRACE_USER) { -+ dtrace_user_stacktrace(st); -+ return; -+ } -+ -+ if (st->pcs == NULL) { -+ st->depth = 0; -+ return; -+ } -+ -+ st->depth = stack_trace_save((long unsigned int *) st->pcs, -+ st->limit ? st->limit : 512, st->depth); -+ -+ /* -+ * For entirely unknown reasons, the save_stack_trace() implementation -+ * on x86_64 adds a ULONG_MAX entry after the last stack trace entry. -+ * This might be a sentinel value, but given that struct stack_trace -+ * already contains a nr_entries counter, this seems rather pointless. -+ * Alas, we need to add a special case for that... And to make matters -+ * worse, it actually does this only when there is room for it (i.e. -+ * when nr_entries < max_entries). -+ * Since ULONG_MAX is never a valid PC, we can just check for that. -+ */ -+#if defined(CONFIG_X86_64) || defined(CONFIG_ARM64) -+ if (st->depth && st->pcs[st->depth - 1] == ULONG_MAX) -+ st->depth--; -+#endif -+ -+ if (st->fps != NULL) { -+ for (i = 0; i < st->limit; i++) -+ st->fps[i] = 0; -+ } -+} -+EXPORT_SYMBOL(dtrace_stacktrace); -+ -+/* -+ * INVALID OPCODE AND PAGE FAULT HANDLING -+ */ -+static struct notifier_block dtrace_die = { -+ .notifier_call = dtrace_die_notifier, -+ .priority = 0x7fffffff -+}; -+ -+static int dtrace_enabled; -+ -+/* -+ * DTrace enable/disable must be called with dtrace_lock being held. It is not -+ * possible to check for safety here with an ASSERT as the lock itself is in the -+ * DTrace Framework kernel module. -+ */ -+int dtrace_enable(void) -+{ -+ if (dtrace_enabled) -+ return 0; -+ -+ if (register_die_notifier(&dtrace_die) != 0) -+ return 1; -+ -+ dtrace_enabled = 1; -+ return 0; -+} -+EXPORT_SYMBOL(dtrace_enable); -+ -+void dtrace_disable(void) -+{ -+ if (!dtrace_enabled) -+ return; -+ -+ unregister_die_notifier(&dtrace_die); -+ dtrace_enabled = 0; -+} -+EXPORT_SYMBOL(dtrace_disable); -diff --git a/kernel/dtrace/dtrace_psinfo.c b/kernel/dtrace/dtrace_psinfo.c -new file mode 100644 -index 0000000000000000000000000000000000000000..bb5f6fc2ce63a487a5ade3a022c51fc15e3e42ae ---- /dev/null -+++ b/kernel/dtrace/dtrace_psinfo.c -@@ -0,0 +1,212 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_psinfo.c -+ * DESCRIPTION: DTrace - DTrace psinfo implementation -+ * -+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/binfmts.h> -+#include <linux/dtrace_psinfo.h> -+#include <linux/dtrace_task_impl.h> -+#include <linux/mm.h> -+#include <linux/sched.h> -+#include <linux/sched/mm.h> -+#include <linux/slab.h> -+#include <linux/uaccess.h> -+ -+struct kmem_cache *dtrace_psinfo_cachep; -+ -+/* -+ * Free the psinfo_t structure. -+ */ -+void dtrace_psinfo_free(struct dtrace_psinfo *psinfo) -+{ -+ kfree(psinfo->dtps_argv); -+ kfree(psinfo->dtps_envp); -+ kmem_cache_free(dtrace_psinfo_cachep, psinfo); -+} -+ -+/* -+ * Allocate a new dtrace_psinfo_t structure. -+ */ -+void dtrace_psinfo_alloc(struct task_struct *tsk) -+{ -+ struct dtrace_psinfo *psinfo; -+ struct mm_struct *mm = NULL; -+ -+ if (unlikely(tsk->dt_task == NULL)) -+ return; -+ -+ if (likely(tsk->dt_task->dt_psinfo != NULL)) { -+ struct dtrace_psinfo *tmp = tsk->dt_task->dt_psinfo; -+ tsk->dt_task->dt_psinfo = NULL; -+ -+ dtrace_psinfo_put(tmp); -+ } -+ -+ psinfo = kmem_cache_alloc(dtrace_psinfo_cachep, GFP_KERNEL); -+ if (psinfo == NULL) -+ goto fail; -+ -+ mm = get_task_mm(tsk); -+ if (mm) { -+ size_t len = mm->arg_end - mm->arg_start; -+ int i = 0; -+ char *p; -+ -+ /* -+ * Construct the psargs string. -+ */ -+ if (len > 0) { -+ if (len >= PR_PSARGS_SZ) -+ len = PR_PSARGS_SZ - 1; -+ -+ i = access_process_vm(tsk, mm->arg_start, -+ psinfo->dtps_psargs, len, 0); -+ -+ if (i > 0) { -+ if (i < len) -+ len = i; -+ -+ for (i = 0, --len; i < len; i++) { -+ if (psinfo->dtps_psargs[i] == '\0') -+ psinfo->dtps_psargs[i] = ' '; -+ } -+ } -+ } -+ -+ if (i < 0) -+ i = 0; -+ -+ while (i < PR_PSARGS_SZ) -+ psinfo->dtps_psargs[i++] = 0; -+ -+ /* -+ * Determine the number of arguments. -+ */ -+ psinfo->dtps_argc = 0; -+ for (p = (char *)mm->arg_start; p < (char *)mm->arg_end; -+ psinfo->dtps_argc++) { -+ size_t l = strnlen_user(p, MAX_ARG_STRLEN); -+ -+ if (!l) -+ break; -+ -+ p += l + 1; -+ } -+ -+ /* -+ * Limit the number of stored argument pointers. -+ */ -+ len = psinfo->dtps_argc; -+ if (len >= PR_ARGV_SZ) -+ len = PR_ARGV_SZ - 1; -+ -+ psinfo->dtps_argv = kmalloc((len + 1) * sizeof(char *), -+ GFP_KERNEL); -+ if (psinfo->dtps_argv == NULL) -+ goto fail; -+ -+ /* -+ * Now populate the array of argument strings. -+ */ -+ for (i = 0, p = (char *)mm->arg_start; i < len; i++) { -+ psinfo->dtps_argv[i] = p; -+ p += strnlen_user(p, MAX_ARG_STRLEN) + 1; -+ } -+ psinfo->dtps_argv[len] = NULL; -+ -+ /* -+ * Determine the number of environment variables. -+ */ -+ psinfo->dtps_envc = 0; -+ for (p = (char *)mm->env_start; p < (char *)mm->env_end; -+ psinfo->dtps_envc++) { -+ size_t l = strnlen_user(p, MAX_ARG_STRLEN); -+ -+ if (!l) -+ break; -+ -+ p += l + 1; -+ } -+ -+ /* -+ * Limit the number of stored environment pointers. -+ */ -+ len = psinfo->dtps_envc; -+ if (len >= PR_ENVP_SZ) -+ len = PR_ENVP_SZ - 1; -+ -+ psinfo->dtps_envp = kmalloc((len + 1) * sizeof(char *), -+ GFP_KERNEL); -+ if (psinfo->dtps_envp == NULL) -+ goto fail; -+ -+ /* -+ * Now populate the array of environment variable strings. -+ */ -+ for (i = 0, p = (char *)mm->env_start; i < len; i++) { -+ psinfo->dtps_envp[i] = p; -+ p += strnlen_user(p, MAX_ARG_STRLEN) + 1; -+ } -+ psinfo->dtps_envp[len] = NULL; -+ -+ mmput(mm); -+ } else { -+ size_t len = min(TASK_COMM_LEN, PR_PSARGS_SZ); -+ int i; -+ -+ /* -+ * We end up here for tasks that do not have managed memory at -+ * all, which generally means that this is a kernel thread. -+ * If it is not, this is still safe because we know that tasks -+ * always have the comm member populated with something (even -+ * if it would be an empty string). -+ */ -+ memcpy(psinfo->dtps_psargs, tsk->comm, len); -+ for (i = len; i < PR_PSARGS_SZ; i++) -+ psinfo->dtps_psargs[i] = 0; -+ -+ psinfo->dtps_argc = 0; -+ psinfo->dtps_argv = kmalloc(sizeof(char *), GFP_KERNEL); -+ psinfo->dtps_argv[0] = NULL; -+ psinfo->dtps_envc = 0; -+ psinfo->dtps_envp = kmalloc(sizeof(char *), GFP_KERNEL); -+ psinfo->dtps_envp[0] = NULL; -+ } -+ -+ atomic_set(&psinfo->dtps_usage, 1); -+ tsk->dt_task->dt_psinfo = psinfo; /* new one */ -+ -+ return; -+ -+fail: -+ if (mm) -+ mmput(mm); -+ -+ if (psinfo) -+ dtrace_psinfo_free(psinfo); -+} -+ -+/* -+ * Initialize DTrace's psinfo subsystem. -+ */ -+void __init dtrace_psinfo_os_init(void) -+{ -+ dtrace_psinfo_cachep = kmem_cache_create("dtrace_psinfo_cache", -+ sizeof(struct dtrace_psinfo), 0, -+ SLAB_HWCACHE_ALIGN | SLAB_PANIC, -+ NULL); -+ -+} -diff --git a/kernel/dtrace/dtrace_task.c b/kernel/dtrace/dtrace_task.c -new file mode 100644 -index 0000000000000000000000000000000000000000..02bcc6b7e0a26a04f61448ac6c8d5653344b6f40 ---- /dev/null -+++ b/kernel/dtrace/dtrace_task.c -@@ -0,0 +1,237 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_task.c -+ * DESCRIPTION: DTrace - per-task data -+ * -+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/dtrace_task_impl.h> -+#include <linux/sched/mm.h> -+#include <linux/slab.h> -+ -+struct kmem_cache *dtrace_task_cachep; -+ -+void (*dtrace_helpers_fork)(struct task_struct *, struct task_struct *); -+EXPORT_SYMBOL(dtrace_helpers_fork); -+ -+/* -+ * Reset per-task sate to default values. Modifies only part of -+ * the state that does not persist across process forks. -+ */ -+static void dtrace_task_reinit(struct dtrace_task *dtsk) -+{ -+ dtsk->dt_predcache = 0; -+ dtsk->dt_stop = 0; -+ dtsk->dt_sig = 0; -+ -+ dtsk->dt_helpers = NULL; -+ dtsk->dt_probes = 0; -+ dtsk->dt_tp_count = 0; -+} -+ -+/* -+ * Allocate new per-task structure and initialize it with default -+ * values. -+ */ -+static struct dtrace_task *dtrace_task_alloc(void) -+{ -+ struct dtrace_task *dtsk; -+ -+ /* Try to allocate new task. */ -+ dtsk = kmem_cache_alloc(dtrace_task_cachep, GFP_KERNEL); -+ if (dtsk == NULL) -+ return NULL; -+ -+ /* Initialize new task. */ -+ dtrace_task_reinit(dtsk); -+ -+ dtsk->dt_vtime = ktime_set(0, 0); -+ dtsk->dt_start = ktime_set(0, 0); -+ dtsk->dt_psinfo = NULL; -+ dtsk->dt_ustack = NULL; -+ -+ return dtsk; -+} -+ -+/* -+ * Cleans all attached resources to the per-task structure so it is ready to be -+ * reused or freed. -+ */ -+static void dtrace_task_cleanup(struct task_struct *tsk) -+{ -+ struct dtrace_psinfo *psinfo; -+ -+ /* Nothing to remove. */ -+ if (tsk->dt_task == NULL) -+ return; -+ -+ /* Release psinfo if any. */ -+ psinfo = tsk->dt_task->dt_psinfo; -+ if (psinfo != NULL) { -+ tsk->dt_task->dt_psinfo = NULL; -+ dtrace_psinfo_put(psinfo); -+ } -+} -+ -+/* -+ * Kernel hooks for per-task events. -+ */ -+ -+/* -+ * Called when a new task has been created. -+ * -+ * It tries to allocate new per-task data strcture and initialize -+ * it with default values. -+ */ -+void dtrace_task_init(struct task_struct *tsk) -+{ -+ struct mm_struct *mm = NULL; -+ -+ /* Initialize new task structure */ -+ tsk->dt_task = dtrace_task_alloc(); -+ if (tsk->dt_task == NULL) -+ return; -+ -+ /* Try to setup initial userspace stack. */ -+ mm = get_task_mm(tsk); -+ if (mm) { -+ tsk->dt_task->dt_ustack = (void *)mm->start_stack; -+ mmput(mm); -+ } -+} -+ -+/* -+ * Called when a task has been duplicated. -+ * -+ * When a task is duplicated this is called early to provide new instance -+ * of per-task data. This hook is called very early after a dup has been -+ * performed. The new task shares almost everything with its parent and -+ * locking performed must be aligned with locking of the kernel. -+ * -+ * DTrace resets new task to its default values. -+ */ -+void dtrace_task_dup(struct task_struct *src, struct task_struct *dst) -+{ -+ struct dtrace_psinfo *psinfo; -+ struct dtrace_task *dtsk; -+ -+ /* Nothing to clone. */ -+ if (src->dt_task == NULL) -+ return; -+ -+ /* Allocate and reinitialize new task. */ -+ dtsk = dtrace_task_alloc(); -+ if (dtsk == NULL) { -+ dst->dt_task = NULL; -+ return; -+ } -+ dtrace_task_reinit(dtsk); -+ -+ /* Share psinfo if it is available. */ -+ psinfo = src->dt_task->dt_psinfo; -+ if (psinfo != NULL) { -+ dtrace_psinfo_get(psinfo); -+ dtsk->dt_psinfo = psinfo; -+ } -+ -+ /* Copy remaining attributes of the source task. */ -+ dtsk->dt_ustack = src->dt_task->dt_ustack; -+ dst->dt_task = dtsk; -+} -+ -+/* -+ * Called when a process has been copied. -+ * -+ * If the original task has helpers attached fork them too. -+ */ -+void dtrace_task_copy(struct task_struct *tsk, struct task_struct *child) -+{ -+ if (tsk->dt_task == NULL) -+ return; -+ -+ if (child->dt_task == NULL) -+ return; -+ -+ /* Handle helpers for this task. */ -+ if (likely(dtrace_helpers_fork == NULL)) -+ return; -+ -+ if (tsk->dt_task->dt_helpers != NULL) -+ (*dtrace_helpers_fork)(tsk, child); -+} -+ -+/* -+ * Called when a task has performed exec. -+ * -+ * If DTrace's per-task structure is already allocated it is reused for -+ * the new task. If it is not present an allocation attempt is made. -+ */ -+void dtrace_task_exec(struct task_struct *tsk) -+{ -+ struct mm_struct *mm = NULL; -+ -+ /* Try to reuse existing dtrace task. */ -+ if (tsk->dt_task != NULL) { -+ dtrace_task_cleanup(tsk); -+ dtrace_task_reinit(tsk->dt_task); -+ -+ /* Try to set up initial userspace stack. */ -+ mm = get_task_mm(tsk); -+ if (mm) { -+ tsk->dt_task->dt_ustack = (void *)mm->start_stack; -+ mmput(mm); -+ } -+ } else { -+ dtrace_task_init(tsk); -+ -+ /* No luck, we won't be able to trace this task. */ -+ if (tsk->dt_task == NULL) -+ return; -+ } -+ -+ /* Finalize init of the per-task structure. */ -+ dtrace_psinfo_alloc(tsk); -+} -+ -+/* -+ * Called when a task is about to be released. -+ * -+ * The DTrace's per-task data are disconnected and freed. -+ */ -+void dtrace_task_free(struct task_struct *tsk) -+{ -+ struct dtrace_task *dtsk = tsk->dt_task; -+ -+ /* Nothing to do. */ -+ if (dtsk == NULL) -+ return; -+ -+ /* Release the per-task data. */ -+ dtrace_task_cleanup(tsk); -+ tsk->dt_task = NULL; -+ kmem_cache_free(dtrace_task_cachep, dtsk); -+} -+ -+/* -+ * Initialize DTrace's task subsystem. -+ */ -+void __init dtrace_task_os_init(void) -+{ -+ /* Will panic if not initialized so no need to check for errors. */ -+ dtrace_task_cachep = kmem_cache_create("dtrace_task_cache", -+ sizeof(struct dtrace_task), 0, -+ SLAB_HWCACHE_ALIGN | SLAB_PANIC, -+ NULL); -+} -+ -diff --git a/kernel/exit.c b/kernel/exit.c -index 5c5859a9ba75afff23fcdffcb01eef159724c6df..da498c5f029c20d162f8665cee6cd49c6de9a06c 100644 ---- a/kernel/exit.c -+++ b/kernel/exit.c -@@ -64,6 +64,7 @@ - #include <linux/rcuwait.h> - #include <linux/compat.h> - #include <linux/io_uring.h> -+#include <linux/dtrace_os.h> - - #include <linux/uaccess.h> - #include <asm/unistd.h> -@@ -795,6 +796,9 @@ void __noreturn do_exit(long code) - tsk->exit_code = code; - taskstats_exit(tsk, group_dead); - -+ /* Remove DTrace state for this task */ -+ dtrace_task_free(tsk); -+ - exit_mm(); - - if (group_dead) -diff --git a/kernel/fork.c b/kernel/fork.c -index c675fdbd3dce1377480c4a70a496e5d1680d88ea..0d8a2b12fd90565fccba06804f9c0a58cbc6a064 100644 ---- a/kernel/fork.c -+++ b/kernel/fork.c -@@ -96,6 +96,7 @@ - #include <linux/kasan.h> - #include <linux/scs.h> - #include <linux/io_uring.h> -+#include <linux/dtrace_task_impl.h> - - #include <asm/pgalloc.h> - #include <linux/uaccess.h> -@@ -442,6 +443,7 @@ void put_task_stack(struct task_struct *tsk) - void free_task(struct task_struct *tsk) - { - scs_release(tsk); -+ dtrace_task_free(tsk); - - #ifndef CONFIG_THREAD_INFO_IN_TASK - /* -@@ -943,6 +945,8 @@ static struct task_struct *dup_task_struct(struct task_struct *orig, int node) - #ifdef CONFIG_MEMCG - tsk->active_memcg = NULL; - #endif -+ -+ dtrace_task_dup(orig, tsk); - return tsk; - - free_stack: -@@ -2300,6 +2304,25 @@ static __latent_entropy struct task_struct *copy_process( - syscall_tracepoint_update(p); - write_unlock_irq(&tasklist_lock); - -+#ifdef CONFIG_DTRACE -+ /* -+ * We make this call fairly late into the copy_process() handling, -+ * because we need to ensure that we can look up this task based on -+ * its pid using find_task_by_vpid(). We also must ensure that the -+ * tasklist_lock has been released. -+ */ -+ dtrace_task_copy(current, p); -+ -+ /* -+ * If we're called with stack_start != 0, this is almost certainly a -+ * thread being created in current. Make sure it gets its own psinfo -+ * data, because we need to record a new bottom of stack value. -+ */ -+ if (p->mm && args->stack) -+ if (p->dt_task != NULL) -+ p->dt_task->dt_ustack = (void *)args->stack; -+#endif -+ - proc_fork_connector(p); - sched_post_fork(p); - cgroup_post_fork(p, args); -diff --git a/kernel/module.c b/kernel/module.c -index 9e471dbedc83a1a080612bf4f4ffabf09f3b8aa8..f4269dabc63837a9055eeed1bab211e30422413e 100644 ---- a/kernel/module.c -+++ b/kernel/module.c -@@ -46,6 +46,7 @@ - #include <asm/mmu_context.h> - #include <linux/license.h> - #include <asm/sections.h> -+#include <linux/dtrace_os.h> - #include <linux/tracepoint.h> - #include <linux/ftrace.h> - #include <linux/livepatch.h> -@@ -90,6 +91,9 @@ - DEFINE_MUTEX(module_mutex); - EXPORT_SYMBOL_GPL(module_mutex); - static LIST_HEAD(modules); -+#ifdef CONFIG_DTRACE -+struct list_head *dtrace_modules = &modules; -+#endif /* CONFIG_DTRACE */ - - /* Work queue for freeing init sections in success case */ - static void do_free_init(struct work_struct *w); -@@ -1023,6 +1027,12 @@ SYSCALL_DEFINE2(delete_module, const char __user *, name_user, - } - } - -+ /* Try destroying DTrace provider. */ -+ if (!dtrace_destroy_prov(mod)) { -+ ret = -EBUSY; -+ goto out; -+ } -+ - /* Stop the machine so refcounts can't move and disable module. */ - ret = try_stop_module(mod, flags, &forced); - if (ret != 0) -@@ -2212,6 +2222,7 @@ void __weak module_arch_freeing_init(struct module *mod) - /* Free a module, remove from lists, etc. */ - static void free_module(struct module *mod) - { -+ dtrace_mod_pdata_free(mod); - trace_module_free(mod); - - mod_sysfs_teardown(mod); -@@ -3943,6 +3954,9 @@ static int load_module(struct load_info *info, const char __user *uargs, - /* Ftrace init must be called in the MODULE_STATE_UNFORMED state */ - ftrace_module_init(mod); - -+ /* Allocate DTrace per-module data. */ -+ dtrace_mod_pdata_alloc(mod); -+ - /* Finally it's fully formed, ready to start executing. */ - err = complete_formation(mod, info); - if (err) -diff --git a/kernel/sched/core.c b/kernel/sched/core.c -index 77aa0e788b9b76b9cd13ac3a0bda6fa9e9b0a1b2..db893818f3ea5d645ae2418906acd27889722a65 100644 ---- a/kernel/sched/core.c -+++ b/kernel/sched/core.c -@@ -13,6 +13,7 @@ - #include "sched.h" - - #include <linux/nospec.h> -+#include <linux/dtrace_os.h> - - #include <linux/kcov.h> - #include <linux/scs.h> -@@ -3600,6 +3601,11 @@ static struct rq *finish_task_switch(struct task_struct *prev) - - rq->prev_mm = NULL; - -+#ifdef CONFIG_DTRACE -+ if (dtrace_vtime_active) -+ dtrace_vtime_switch(prev, current); -+#endif -+ - /* - * A task struct has one reference for the use as "current". - * If a task dies, then it sets TASK_DEAD in tsk->state and calls -@@ -7195,6 +7201,10 @@ void __init sched_init(void) - #endif /* CONFIG_SMP */ - hrtick_rq_init(rq); - atomic_set(&rq->nr_iowait, 0); -+ -+#ifdef CONFIG_DTRACE -+ rq->dtrace_cpu_info = per_cpu_info(i); -+#endif - } - - set_load_weight(&init_task, false); -diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h -index c122176c627ec3223cfb1bbcbacf585071bf2579..f917e368e4f88fefafc62b38edfaf7ec6527aa59 100644 ---- a/kernel/sched/sched.h -+++ b/kernel/sched/sched.h -@@ -345,6 +345,7 @@ extern bool dl_cpu_busy(unsigned int cpu); - #ifdef CONFIG_CGROUP_SCHED - - #include <linux/cgroup.h> -+#include <linux/dtrace_cpu.h> - #include <linux/psi.h> - - struct cfs_rq; -@@ -1042,6 +1043,9 @@ struct rq { - /* Must be inspected within a rcu lock section */ - struct cpuidle_state *idle_state; - #endif -+#ifdef CONFIG_DTRACE -+ struct cpuinfo *dtrace_cpu_info; -+#endif - }; - - #ifdef CONFIG_FAIR_GROUP_SCHED -diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c -index 6858a31364b6456f036bbf38da4d0eca89ec3aaf..b74807546fba4907b7e054111882f6d3fa18f2ae 100644 ---- a/kernel/time/timekeeping.c -+++ b/kernel/time/timekeeping.c -@@ -22,6 +22,7 @@ - #include <linux/pvclock_gtod.h> - #include <linux/compiler.h> - #include <linux/audit.h> -+#include <linux/dtrace_os.h> - - #include "tick-internal.h" - #include "ntp_internal.h" -@@ -743,6 +744,7 @@ static void timekeeping_update(struct timekeeper *tk, unsigned int action) - tk_update_ktime_data(tk); - - update_vsyscall(tk); -+ dtrace_update_time(tk); - update_pvclock_gtod(tk, action & TK_CLOCK_WAS_SET); - - tk->tkr_mono.base_real = tk->tkr_mono.base + tk->offs_real; -diff --git a/scripts/coccinelle/dtrace/enum-elision.cocci b/scripts/coccinelle/dtrace/enum-elision.cocci -new file mode 100644 -index 0000000000000000000000000000000000000000..77a5b33bd1661d7bf024afd82c29bec9e1c9a751 ---- /dev/null -+++ b/scripts/coccinelle/dtrace/enum-elision.cocci -@@ -0,0 +1,29 @@ -+/// Reduce uses of typedefs of named enums to the name of the enum -+ -+virtual patch -+virtual context -+virtual org -+virtual report -+ -+@td@ -+type T; -+identifier E; -+@@ -+- typedef enum E -++ enum E -+ { ... -+- } T; -++ }; -+@@ -+type td.T; -+identifier td.E; -+@@ -+- T -++ enum E -+ -+@@ -+type td.T; -+identifier td.E; -+@@ -+- const T -++ const enum E -diff --git a/scripts/coccinelle/dtrace/typedef-elision.cocci b/scripts/coccinelle/dtrace/typedef-elision.cocci -new file mode 100644 -index 0000000000000000000000000000000000000000..bc4caf375b607b624b9c566bf1a2e471e463f01e ---- /dev/null -+++ b/scripts/coccinelle/dtrace/typedef-elision.cocci -@@ -0,0 +1,83 @@ -+/// Reduce uses of typedefs of named structures to the name of the structure -+ -+virtual patch -+virtual context -+virtual org -+virtual report -+ -+@td@ -+type T; -+identifier S; -+@@ -+( -+- typedef struct S -++ struct S -+ { ... -+- } T; -++ }; -+| -+ struct S; -+- typedef struct S T; -+) -+@@ -+type td.T; -+identifier td.S; -+@@ -+- T -++ struct S -+ -+@@ -+type td.T; -+identifier td.S; -+@@ -+- const T -++ const struct S -+ -+/// Now structures declared with typedefs of opaque structs, one by one -+@@ -+typedef dtrace_ecb_t; -+@@ -+- dtrace_ecb_t -++ struct dtrace_ecb -+ -+@@ -+typedef dtrace_actdesc_t; -+@@ -+- dtrace_actdesc_t -++ struct dtrace_actdesc -+ -+@@ -+typedef dtrace_state_t; -+@@ -+- dtrace_state_t -++ struct dtrace_state -+ -+@@ -+typedef dtrace_vstate_t; -+@@ -+- dtrace_vstate_t -++ struct dtrace_vstate -+ -+@@ -+typedef dtrace_mstate_t; -+@@ -+- dtrace_mstate_t -++ struct dtrace_mstate -+ -+@@ -+typedef dtrace_task_t; -+@@ -+- dtrace_task_t -++ struct dtrace_task -+ -+@@ -+typedef dtrace_psinfo_t; -+@@ -+- dtrace_psinfo_t -++ struct dtrace_psinfo -+ -+@@ -+typedef dt_fbt_bl_entry_t; -+@@ -+- dt_fbt_bl_entry_t -++ struct dt_fbt_bl_entry -diff --git a/scripts/package/mkspec b/scripts/package/mkspec -index e9ff22c6fb4c7c7082767c7c9b164e94735ea1e7..cba5be72adb926cb6a96fb9d8d497a362e6080b9 100755 ---- a/scripts/package/mkspec -+++ b/scripts/package/mkspec -@@ -150,6 +150,7 @@ $M %exclude /lib/modules/$KERNELRELEASE/source - %files headers - %defattr (-, root, root) - /usr/include -+ %exclude /usr/include/linux/dtrace - $S$M - $S$M %files devel - $S$M %defattr (-, root, root) --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/dtrace-patches/0005-dtrace-modular-components-and-x86-support.patch b/sys-kernel/cairn-sources/files/5.10.14/dtrace-patches/0005-dtrace-modular-components-and-x86-support.patch deleted file mode 100644 index 7f95d00dba49..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/dtrace-patches/0005-dtrace-modular-components-and-x86-support.patch +++ /dev/null @@ -1,18392 +0,0 @@ -From 4b3eec83a54c9bd853648e4b256fb28a078a36aa Mon Sep 17 00:00:00 2001 -From: Kris Van Hees <kris.van.hees@oracle.com> -Date: Mon, 19 Nov 2018 17:52:54 +0000 -Subject: [PATCH 05/19] dtrace: modular components and x86 support - -This implements the core DTrace module (including the entire DIF -interpreter and support for all built-in D variables and functions) and -one test provider, dt_test.ko. It uses the machinery added in the last -few commits. An x86 implementation of the architecture-dependent parts -is also added so that one platform at least can compile it. - -At this stage, almost no probes will exist: they are added by the -following commits, that add providers and SDT probes. - -Signed-off-by: Kris Van Hees <kris.van.hees@oracle.com> -Signed-off-by: Nick Alcock <nick.alcock@oracle.com> -Signed-off-by: Tomas Jedlicka <tomas.jedlicka@oracle.com> -Signed-off-by: Eugene Loh <eugene.loh@oracle.com> -Signed-off-by: David Mc Lean <david.mclean@oracle.com> -Signed-off-by: Vincent Lim <vincent.lim@oracle.com> ---- - Makefile | 1 + - arch/x86/dtrace/Makefile.arch | 11 + - arch/x86/dtrace/dtrace_asm_x86_64.S | 228 ++ - arch/x86/dtrace/dtrace_isa_x86_64.c | 228 ++ - dtrace/Makefile | 19 + - dtrace/ctf_api.h | 33 + - dtrace/dt_test.h | 30 + - dtrace/dt_test_dev.c | 176 + - dtrace/dt_test_mod.c | 52 + - dtrace/dtrace.h | 35 + - dtrace/dtrace_actdesc.c | 91 + - dtrace/dtrace_anon.c | 144 + - dtrace/dtrace_buffer.c | 490 +++ - dtrace/dtrace_debug.h | 118 + - dtrace/dtrace_dev.c | 1599 +++++++++ - dtrace/dtrace_dev.h | 35 + - dtrace/dtrace_dif.c | 4905 +++++++++++++++++++++++++++ - dtrace/dtrace_dof.c | 2504 ++++++++++++++ - dtrace/dtrace_ecb.c | 936 +++++ - dtrace/dtrace_enable.c | 449 +++ - dtrace/dtrace_fmt.c | 104 + - dtrace/dtrace_hash.c | 266 ++ - dtrace/dtrace_isa.c | 361 ++ - dtrace/dtrace_match.c | 364 ++ - dtrace/dtrace_mod.c | 45 + - dtrace/dtrace_predicate.c | 80 + - dtrace/dtrace_priv.c | 120 + - dtrace/dtrace_probe.c | 1542 +++++++++ - dtrace/dtrace_probe_ctx.c | 659 ++++ - dtrace/dtrace_ptofapi.c | 649 ++++ - dtrace/dtrace_spec.c | 434 +++ - dtrace/dtrace_state.c | 1108 ++++++ - dtrace/dtrace_util.c | 282 ++ - 33 files changed, 18098 insertions(+) - create mode 100644 arch/x86/dtrace/Makefile.arch - create mode 100644 arch/x86/dtrace/dtrace_asm_x86_64.S - create mode 100644 arch/x86/dtrace/dtrace_isa_x86_64.c - create mode 100644 dtrace/Makefile - create mode 100644 dtrace/ctf_api.h - create mode 100644 dtrace/dt_test.h - create mode 100644 dtrace/dt_test_dev.c - create mode 100644 dtrace/dt_test_mod.c - create mode 100644 dtrace/dtrace.h - create mode 100644 dtrace/dtrace_actdesc.c - create mode 100644 dtrace/dtrace_anon.c - create mode 100644 dtrace/dtrace_buffer.c - create mode 100644 dtrace/dtrace_debug.h - create mode 100644 dtrace/dtrace_dev.c - create mode 100644 dtrace/dtrace_dev.h - create mode 100644 dtrace/dtrace_dif.c - create mode 100644 dtrace/dtrace_dof.c - create mode 100644 dtrace/dtrace_ecb.c - create mode 100644 dtrace/dtrace_enable.c - create mode 100644 dtrace/dtrace_fmt.c - create mode 100644 dtrace/dtrace_hash.c - create mode 100644 dtrace/dtrace_isa.c - create mode 100644 dtrace/dtrace_match.c - create mode 100644 dtrace/dtrace_mod.c - create mode 100644 dtrace/dtrace_predicate.c - create mode 100644 dtrace/dtrace_priv.c - create mode 100644 dtrace/dtrace_probe.c - create mode 100644 dtrace/dtrace_probe_ctx.c - create mode 100644 dtrace/dtrace_ptofapi.c - create mode 100644 dtrace/dtrace_spec.c - create mode 100644 dtrace/dtrace_state.c - create mode 100644 dtrace/dtrace_util.c - -diff --git a/Makefile b/Makefile -index fb9393fa10f082c29ab717aefcc812e34f8caf9d..4b25be692ac15ae9f6eb52c4a5f135da70598b05 100644 ---- a/Makefile -+++ b/Makefile -@@ -651,6 +651,7 @@ drivers-y := drivers/ sound/ - drivers-$(CONFIG_SAMPLES) += samples/ - drivers-y += net/ virt/ - libs-y := lib/ -+dtrace-y := dtrace/ - endif # KBUILD_EXTMOD - - # The all: target is the default when no target is given on the -diff --git a/arch/x86/dtrace/Makefile.arch b/arch/x86/dtrace/Makefile.arch -new file mode 100644 -index 0000000000000000000000000000000000000000..ffb9ef4d1722b673511418c5744067ac501d49c5 ---- /dev/null -+++ b/arch/x86/dtrace/Makefile.arch -@@ -0,0 +1,11 @@ -+# -+# Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. -+# -+ -+DTARCHDIR = ../arch/x86/dtrace -+ -+ccflags-y += -I$(srctree)/arch/x86/dtrace/include -Idtrace -+ -+dtrace-obj += dtrace_asm_x86_64.o dtrace_isa_x86_64.o -+ -+dtrace-y += $(addprefix $(DTARCHDIR)/, $(dtrace-obj)) -diff --git a/arch/x86/dtrace/dtrace_asm_x86_64.S b/arch/x86/dtrace/dtrace_asm_x86_64.S -new file mode 100644 -index 0000000000000000000000000000000000000000..46d3fe1b9703f05126686ad81c00d8d76fa10cf2 ---- /dev/null -+++ b/arch/x86/dtrace/dtrace_asm_x86_64.S -@@ -0,0 +1,228 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Dynamic Tracing for Linux - x86 specific assembly -+ * -+ * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/linkage.h> -+#include <asm/smap.h> -+ -+#define CPU_DTRACE_BADADDR 0x0004 /* DTrace fault: bad address */ -+ -+#if defined(__x86_64__) -+ SYM_CODE_START(dtrace_caller) -+ movq $-1, %rax -+ ret -+ SYM_CODE_END(dtrace_caller) -+ -+#elif defined(__i386__) -+ -+ SYM_CODE_START(dtrace_caller) -+ movl $-1, %eax -+ ret -+ SYM_CODE_END(dtrace_caller) -+ -+#endif /* __i386__ */ -+ -+#if defined(__x86_64__) -+ -+ SYM_FUNC_START(dtrace_copy) -+ pushq %rbp -+ movq %rsp, %rbp -+ -+ ASM_STAC -+ xchgq %rdi, %rsi # make %rsi source, %rdi dest -+ movq %rdx, %rcx # load count -+ repz # repeat for count ... -+ smovb # move from %ds:rsi to %ed:rdi -+ ASM_CLAC -+ leave -+ ret -+ SYM_FUNC_END(dtrace_copy) -+ -+#elif defined(__i386__) -+ -+ SYM_FUNC_START(dtrace_copy) -+ pushl %ebp -+ movl %esp, %ebp -+ pushl %esi -+ pushl %edi -+ -+ movl 8(%ebp), %esi # Load source address -+ movl 12(%ebp), %edi # Load destination address -+ movl 16(%ebp), %ecx # Load count -+ repz # Repeat for count... -+ smovb # move from %ds:si to %es:di -+ -+ popl %edi -+ popl %esi -+ movl %ebp, %esp -+ popl %ebp -+ ret -+ SYM_FUNC_END(dtrace_copy) -+ -+#endif /* __i386__ */ -+ -+#if defined(__x86_64__) -+ -+ SYM_FUNC_START(dtrace_copystr) -+ pushq %rbp -+ movq %rsp, %rbp -+ -+ ASM_STAC -+0: -+ movb (%rdi), %al # load from source -+ movb %al, (%rsi) # store to destination -+ addq $1, %rdi # increment source pointer -+ addq $1, %rsi # increment destination pointer -+ subq $1, %rdx # decrement remaining count -+ cmpb $0, %al -+ je 2f -+ testq $0xfff, %rdx # test if count is 4k-aligned -+ jnz 1f # if not, continue with copying -+ testq $CPU_DTRACE_BADADDR, (%rcx) # load and test dtrace flags -+ jnz 2f -+1: -+ cmpq $0, %rdx -+ jne 0b -+2: -+ ASM_CLAC -+ leave -+ ret -+ -+ SYM_FUNC_END(dtrace_copystr) -+ -+#elif defined(__i386__) -+ -+ SYM_FUNC_START(dtrace_copystr) -+ -+ pushl %ebp # Setup stack frame -+ movl %esp, %ebp -+ pushl %ebx # Save registers -+ -+ movl 8(%ebp), %ebx # Load source address -+ movl 12(%ebp), %edx # Load destination address -+ movl 16(%ebp), %ecx # Load count -+ -+0: -+ movb (%ebx), %al # Load from source -+ movb %al, (%edx) # Store to destination -+ incl %ebx # Increment source pointer -+ incl %edx # Increment destination pointer -+ decl %ecx # Decrement remaining count -+ cmpb $0, %al -+ je 2f -+ testl $0xfff, %ecx # Check if count is 4k-aligned -+ jnz 1f -+ movl 20(%ebp), %eax # load flags pointer -+ testl $CPU_DTRACE_BADADDR, (%eax) # load and test dtrace flags -+ jnz 2f -+1: -+ cmpl $0, %ecx -+ jne 0b -+ -+2: -+ popl %ebx -+ movl %ebp, %esp -+ popl %ebp -+ ret -+ -+ SYM_FUNC_END(dtrace_copystr) -+ -+#endif /* __i386__ */ -+ -+#if defined(__x86_64__) -+ -+ SYM_CODE_START(dtrace_fuword8_nocheck) -+ xorq %rax, %rax -+ ASM_STAC -+ movb (%rdi), %al -+ ASM_CLAC -+ ret -+ SYM_CODE_END(dtrace_fuword8_nocheck) -+ -+#elif defined(__i386__) -+ -+ SYM_CODE_START(dtrace_fuword8_nocheck) -+ movl 4(%esp), %ecx -+ xorl %eax, %eax -+ movzbl (%ecx), %eax -+ ret -+ SYM_CODE_END(dtrace_fuword8_nocheck) -+ -+#endif /* __i386__ */ -+ -+#if defined(__x86_64__) -+ -+ SYM_CODE_START(dtrace_fuword16_nocheck) -+ xorq %rax, %rax -+ ASM_STAC -+ movw (%rdi), %ax -+ ASM_CLAC -+ ret -+ SYM_CODE_END(dtrace_fuword16_nocheck) -+ -+#elif defined(__i386__) -+ -+ SYM_CODE_START(dtrace_fuword16_nocheck) -+ movl 4(%esp), %ecx -+ xorl %eax, %eax -+ movzwl (%ecx), %eax -+ ret -+ SYM_CODE_END(dtrace_fuword16_nocheck) -+ -+#endif /* __i386__ */ -+ -+#if defined(__x86_64__) -+ -+ SYM_CODE_START(dtrace_fuword32_nocheck) -+ xorq %rax, %rax -+ ASM_STAC -+ movl (%rdi), %eax -+ ASM_CLAC -+ ret -+ SYM_CODE_END(dtrace_fuword32_nocheck) -+ -+#elif defined(__i386__) -+ -+ SYM_CODE_START(dtrace_fuword32_nocheck) -+ movl 4(%esp), %ecx -+ xorl %eax, %eax -+ movl (%ecx), %eax -+ ret -+ SYM_CODE_END(dtrace_fuword32_nocheck) -+ -+#endif /* __i386__ */ -+ -+#if defined(__x86_64__) -+ -+ SYM_CODE_START(dtrace_fuword64_nocheck) -+ ASM_STAC -+ movq (%rdi), %rax -+ ASM_CLAC -+ ret -+ SYM_CODE_END(dtrace_fuword64_nocheck) -+ -+#elif defined(__i386__) -+ -+ SYM_CODE_START(dtrace_fuword64_nocheck) -+ movl 4(%esp), %ecx -+ xorl %eax, %eax -+ xorl %edx, %edx -+ movl (%ecx), %eax -+ movl 4(%ecx), %edx -+ ret -+ SYM_CODE_END(dtrace_fuword64_nocheck) -+ -+#endif /* __i386__ */ -diff --git a/arch/x86/dtrace/dtrace_isa_x86_64.c b/arch/x86/dtrace/dtrace_isa_x86_64.c -new file mode 100644 -index 0000000000000000000000000000000000000000..5accadc9f121ccc9d6fc2fb63488f711a9a878d2 ---- /dev/null -+++ b/arch/x86/dtrace/dtrace_isa_x86_64.c -@@ -0,0 +1,228 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_isa_x86_64.c -+ * DESCRIPTION: DTrace - x86_64 architecture specific support functions -+ * -+ * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/dtrace_cpu.h> -+#include <asm/unwind.h> -+ -+#include "dtrace.h" -+ -+/* Register indices */ -+#define REG_TRAPNO 25 -+#define REG_GS 24 -+#define REG_FS 23 -+#define REG_ES 22 -+#define REG_DS 21 -+#define REG_SS 20 -+#define REG_RSP 19 -+#define REG_RFL 18 -+#define REG_CS 17 -+#define REG_RIP 16 -+#define REG_ERR 15 -+#define REG_RDI 14 -+#define REG_RSI 13 -+#define REG_RDX 12 -+#define REG_RCX 11 -+#define REG_RAX 10 -+#define REG_R8 9 -+#define REG_R9 8 -+#define REG_R10 7 -+#define REG_R11 6 -+#define REG_RBX 5 -+#define REG_RBP 4 -+#define REG_R12 3 -+#define REG_R13 2 -+#define REG_R14 1 -+#define REG_R15 0 -+ -+extern void dtrace_copy(uintptr_t, uintptr_t, size_t); -+extern void dtrace_copystr(uintptr_t, uintptr_t, size_t, -+ volatile uint16_t *); -+ -+uintptr_t _userlimit = 0x00007fffffffffffLL; -+uintptr_t kernelbase = 0xffff880000000000LL; -+ -+static int dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size) -+{ -+#ifdef FIXME -+ ASSERT(kaddr >= kernelbase && kaddr + size >= kaddr); -+#else -+ if (kaddr < kernelbase || kaddr + size < kaddr) { -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); -+ this_cpu_core->cpuc_dtrace_illval = kaddr; -+ return 0; -+ } -+#endif -+ -+ if (uaddr + size >= kernelbase || uaddr + size < uaddr) { -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); -+ this_cpu_core->cpuc_dtrace_illval = uaddr; -+ return 0; -+ } -+ -+ return 1; -+} -+ -+void dtrace_copyin_arch(uintptr_t uaddr, uintptr_t kaddr, size_t size, -+ volatile uint16_t *flags) -+{ -+ if (dtrace_copycheck(uaddr, kaddr, size)) -+ dtrace_copy(uaddr, kaddr, size); -+} -+ -+void dtrace_copyout(uintptr_t uaddr, uintptr_t kaddr, size_t size, -+ volatile uint16_t *flags) -+{ -+ if (dtrace_copycheck(uaddr, kaddr, size)) -+ dtrace_copy(kaddr, uaddr, size); -+} -+ -+void dtrace_copyinstr_arch(uintptr_t uaddr, uintptr_t kaddr, size_t size, -+ volatile uint16_t *flags) -+{ -+ if (dtrace_copycheck(uaddr, kaddr, size)) -+ dtrace_copystr(uaddr, kaddr, size, flags); -+} -+ -+void dtrace_copyoutstr(uintptr_t uaddr, uintptr_t kaddr, size_t size, -+ volatile uint16_t *flags) -+{ -+ if (dtrace_copycheck(uaddr, kaddr, size)) -+ dtrace_copystr(kaddr, uaddr, size, flags); -+} -+ -+#define DTRACE_FUWORD(bits) \ -+ uint##bits##_t dtrace_fuword##bits(void *uaddr) \ -+ { \ -+ extern uint##bits##_t dtrace_fuword##bits##_nocheck(void *);\ -+ \ -+ if ((uintptr_t)uaddr > _userlimit) { \ -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); \ -+ this_cpu_core->cpuc_dtrace_illval = (uintptr_t)uaddr; \ -+ return 0; \ -+ } \ -+ \ -+ return dtrace_fuword##bits##_nocheck(uaddr); \ -+ } -+ -+DTRACE_FUWORD(8) -+DTRACE_FUWORD(16) -+DTRACE_FUWORD(32) -+DTRACE_FUWORD(64) -+ -+uint64_t dtrace_getarg(int argno, int aframes) -+{ -+ unsigned long bp; -+ uint64_t *st; -+ uint64_t val; -+ int i; -+ struct unwind_state state; -+ -+ if (this_cpu_core->cpu_dtrace_regs) -+ bp = this_cpu_core->cpu_dtrace_regs->bp; -+ else { -+ unwind_start(&state, current, NULL, NULL); -+ for (i = 0; !unwind_done(&state) && i < aframes; -+ unwind_next_frame(&state)) { -+ i++; -+ } -+ -+ bp = (unsigned long)state.bp; -+ } -+ -+ ASSERT(argno >= 5); -+ -+ /* -+ * The first 5 arguments (arg0 through arg4) are passed in registers -+ * to dtrace_probe(). The remaining arguments (arg5 through arg9) are -+ * passed on the stack. -+ * -+ * Stack layout: -+ * bp[0] = pushed bp from caller -+ * bp[1] = return address -+ * bp[2] = 6th argument (arg5 -> argno = 5) -+ * bp[3] = 7th argument (arg6 -> argno = 6) -+ * ... -+ */ -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); -+ st = (uint64_t *)bp; -+ val = st[2 + (argno - 5)]; -+ DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); -+ -+ return val; -+} -+ -+ulong_t dtrace_getreg(struct task_struct *task, uint_t reg) -+{ -+ struct pt_regs *rp = task_pt_regs(task); -+ -+ int regmap[] = { -+ REG_RBX, /* 0 -> EBX */ -+ REG_RCX, /* 1 -> ECX */ -+ REG_RDX, /* 2 -> EDX */ -+ REG_RSI, /* 3 -> ESI */ -+ REG_RDI, /* 4 -> EDI */ -+ REG_RBP, /* 5 -> EBP */ -+ REG_RAX, /* 6 -> EAX */ -+ REG_DS, /* 7 -> DS */ -+ REG_ES, /* 8 -> ES */ -+ REG_FS, /* 9 -> FS */ -+ REG_GS, /* 10 -> GS */ -+ REG_TRAPNO, /* 11 -> TRAPNO */ -+ REG_RIP, /* 12 -> EIP */ -+ REG_CS, /* 13 -> CS */ -+ REG_RFL, /* 14 -> EFL */ -+ REG_RSP, /* 15 -> UESP */ -+ REG_SS, /* 16 -> SS */ -+ }; -+ -+ if (reg > REG_TRAPNO) { -+ /* -+ * Convert register alias index into register mapping index. -+ */ -+ reg -= REG_GS + 1; -+ -+ if (reg >= sizeof(regmap) / sizeof(int)) { -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); -+ return 0; -+ } -+ -+ reg = regmap[reg]; -+ } -+ -+ /* -+ * Most common case: direct index into pt_regs structure. -+ */ -+ if (reg <= REG_SS) -+ return (&rp->r15)[reg]; -+ -+ switch (reg) { -+ case REG_DS: -+ return task->thread.ds; -+ case REG_ES: -+ return task->thread.es; -+ case REG_FS: -+ return task->thread.fsbase; -+ case REG_GS: -+ return task->thread.gsbase; -+ case REG_TRAPNO: -+ return task->thread.trap_nr; -+ default: -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); -+ return 0; -+ } -+} -diff --git a/dtrace/Makefile b/dtrace/Makefile -new file mode 100644 -index 0000000000000000000000000000000000000000..36a4b97b922c4d2baecb0679e41b2d384f56a5b5 ---- /dev/null -+++ b/dtrace/Makefile -@@ -0,0 +1,19 @@ -+# -+# Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. -+# -+ -+obj-$(CONFIG_DT_CORE) += dtrace.o -+obj-$(CONFIG_DT_DT_TEST) += dt_test.o -+ -+dtrace-y := dtrace_mod.o dtrace_dev.o \ -+ dtrace_actdesc.o dtrace_anon.o \ -+ dtrace_buffer.o dtrace_dif.o dtrace_dof.o \ -+ dtrace_ecb.o dtrace_enable.o \ -+ dtrace_fmt.o dtrace_hash.o dtrace_isa.o \ -+ dtrace_match.o dtrace_priv.o \ -+ dtrace_probe.o dtrace_probe_ctx.o \ -+ dtrace_ptofapi.o dtrace_predicate.o \ -+ dtrace_spec.o dtrace_state.o dtrace_util.o -+dt_test-y := dt_test_mod.o dt_test_dev.o -+ -+-include arch/$(SRCARCH)/dtrace/Makefile.arch -diff --git a/dtrace/ctf_api.h b/dtrace/ctf_api.h -new file mode 100644 -index 0000000000000000000000000000000000000000..e09bafc676f4407c1228b3ac473de15c997e2cf6 ---- /dev/null -+++ b/dtrace/ctf_api.h -@@ -0,0 +1,33 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Compact C Type format -+ * -+ * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#ifndef __CTF_API_H_ -+#define __CTF_API_H_ -+ -+/* -+ * The CTF data model is inferred to be the caller's data model or the data -+ * model of the given object, unless ctf_setmodel() is explicitly called. -+ */ -+#define CTF_MODEL_ILP32 1 /* object data model is ILP32 */ -+#define CTF_MODEL_LP64 2 /* object data model is LP64 */ -+#ifdef CONFIG_64BIT -+# define CTF_MODEL_NATIVE CTF_MODEL_LP64 -+#else -+# define CTF_MODEL_NATIVE CTF_MODEL_ILP32 -+#endif -+ -+#endif /* __CTF_API_H_ */ -diff --git a/dtrace/dt_test.h b/dtrace/dt_test.h -new file mode 100644 -index 0000000000000000000000000000000000000000..6efe4656001b387b424fa4e4cd7aca4c2a323f50 ---- /dev/null -+++ b/dtrace/dt_test.h -@@ -0,0 +1,30 @@ -+/* -+ * Dynamic Tracing for Linux - test provider -+ * -+ * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#ifndef _DT_TEST_H_ -+#define _DT_TEST_H_ -+ -+extern void dt_test_provide(void *, const struct dtrace_probedesc *); -+extern int dt_test_enable(void *arg, dtrace_id_t, void *); -+extern void dt_test_disable(void *arg, dtrace_id_t, void *); -+extern void dt_test_destroy(void *, dtrace_id_t, void *); -+ -+extern dtrace_provider_id_t dt_test_id; -+ -+extern int dt_test_dev_init(void); -+extern void dt_test_dev_exit(void); -+ -+#endif /* _DT_TEST_H_ */ -diff --git a/dtrace/dt_test_dev.c b/dtrace/dt_test_dev.c -new file mode 100644 -index 0000000000000000000000000000000000000000..8e1f5bab8a128bdc29a345e422467e6e9d294cf0 ---- /dev/null -+++ b/dtrace/dt_test_dev.c -@@ -0,0 +1,176 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dt_test_dev.c -+ * DESCRIPTION: DTrace - test provider device driver -+ * -+ * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/fs.h> -+#include <linux/miscdevice.h> -+#include <linux/types.h> -+#include <trace/syscall.h> -+#include <asm/unistd.h> -+ -+#include "dtrace.h" -+#include "dtrace_dev.h" -+#include "dt_test.h" -+ -+static dtrace_id_t pid = DTRACE_IDNONE; -+static int enabled; -+ -+/* -+ * Some arrays of structures of different sizes populated with -+ * unchanging randomly-chosen numbers, for padding tests. -+ */ -+ -+static struct dt_test_int_char -+{ -+ int foo; -+ char bar; -+} intish[2] __attribute__((used)) = { { 47204473, 48 }, -+ { 18472, 62 } }; -+ -+static struct dt_test_long_int -+{ -+ long foo; -+ int bar; -+} longish[2] __attribute__((used)) = { { 43737975, 240724 }, -+ { 24924709, 526 } }; -+ -+static struct dt_test_longlong_long -+{ -+ long long foo; -+ long bar; -+} longlongish[2] __attribute__((used)) = { { 4294479287, 4395957 }, -+ { 5239637, 249750 } }; -+ -+static struct dt_test_like_a_scatterlist -+{ -+ unsigned long a; -+ unsigned int b; -+ unsigned int c; -+ u64 d; -+ unsigned int e; -+} scatter_failure[2] __attribute__((used)) = { { .a = 1, .b = 2, -+ .c = 3, .d = 4, .e = 5 }, -+ { .a = 6, .b = 7, -+ .c = 8, .d = 9, .e = 10 } }; -+ -+void dt_test_provide(void *arg, const struct dtrace_probedesc *desc) -+{ -+ dtrace_id_t probe; -+ -+ probe = dtrace_probe_lookup(dt_test_id, "dt_test", NULL, "test"); -+ if (probe != DTRACE_IDNONE) -+ return; -+ -+ pid = dtrace_probe_create(dt_test_id, "dt_test", NULL, "test", 1, NULL); -+} -+ -+int dt_test_enable(void *arg, dtrace_id_t id, void *parg) -+{ -+ enabled = 1; -+ -+ return 0; -+} -+ -+void dt_test_disable(void *arg, dtrace_id_t id, void *parg) -+{ -+ enabled = 0; -+} -+ -+void dt_test_destroy(void *arg, dtrace_id_t id, void *parg) -+{ -+} -+ -+void probe_p(dtrace_id_t pid, uintptr_t arg0, uintptr_t arg1, uintptr_t arg2, -+ uintptr_t arg3, uintptr_t arg4, uintptr_t arg5, uintptr_t arg6, -+ uintptr_t arg7, uintptr_t arg8, uintptr_t arg9) -+{ -+} -+ -+/* -+ * Direct calling into dtrace_probe() when passing more than 5 parameters to -+ * the probe requires a stub function. Otherwise we may not be able to get -+ * to the value of all arguments correctly. -+ */ -+void dt_test_probe(uintptr_t arg0, uintptr_t arg1, uintptr_t arg2, -+ uintptr_t arg3, uintptr_t arg4, uintptr_t arg5, -+ uintptr_t arg6, uintptr_t arg7, uintptr_t arg8, -+ uintptr_t arg9) -+{ -+ /* -+ * Yes, this is not nice. -+ * Not at all... -+ * But we're doing it anyway... -+ */ -+ typeof(probe_p) *probe_fn = (void *)&dtrace_probe; -+ -+ probe_fn(pid, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, -+ arg9); -+} -+ -+static long dt_test_ioctl(struct file *file, -+ unsigned int cmd, unsigned long arg) -+{ -+ if (enabled) { -+ dt_test_probe(cmd, arg, 2ULL, 3ULL, 4ULL, 5ULL, 6ULL, 7ULL, -+ 8ULL, 9ULL); -+ -+ return 0; -+ } -+ -+ return -EAGAIN; -+} -+ -+static int dt_test_open(struct inode *inode, struct file *file) -+{ -+ return 0; -+} -+ -+static int dt_test_close(struct inode *inode, struct file *file) -+{ -+ return 0; -+} -+ -+static const struct file_operations dt_test_fops = { -+ .owner = THIS_MODULE, -+ .unlocked_ioctl = dt_test_ioctl, -+ .open = dt_test_open, -+ .release = dt_test_close, -+}; -+ -+static struct miscdevice dt_test_dev = { -+ .minor = DT_DEV_DT_TEST_MINOR, -+ .name = "dt_test", -+ .nodename = "dtrace/provider/dt_test", -+ .fops = &dt_test_fops, -+}; -+ -+int dt_test_dev_init(void) -+{ -+ int ret = 0; -+ -+ ret = misc_register(&dt_test_dev); -+ if (ret) -+ pr_err("%s: Can't register misc device %d\n", -+ dt_test_dev.name, dt_test_dev.minor); -+ -+ return ret; -+} -+ -+void dt_test_dev_exit(void) -+{ -+ misc_deregister(&dt_test_dev); -+} -diff --git a/dtrace/dt_test_mod.c b/dtrace/dt_test_mod.c -new file mode 100644 -index 0000000000000000000000000000000000000000..d8af71665a37ad3157f1bf9d2ce14cb0a23f7508 ---- /dev/null -+++ b/dtrace/dt_test_mod.c -@@ -0,0 +1,52 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dt_test_mod.c -+ * DESCRIPTION: DTrace - test provider kernel module -+ * -+ * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/module.h> -+ -+#include "dtrace.h" -+#include "dtrace_dev.h" -+#include "dt_test.h" -+ -+MODULE_AUTHOR("Kris Van Hees (kris.van.hees@oracle.com)"); -+MODULE_DESCRIPTION("DTrace Test Probe"); -+MODULE_VERSION("v0.1"); -+MODULE_LICENSE("GPL"); -+ -+static const struct dtrace_pattr dt_test_attr = { -+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA }, -+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA }, -+}; -+ -+static struct dtrace_pops dt_test_pops = { -+ .dtps_provide = dt_test_provide, -+ .dtps_provide_module = NULL, -+ .dtps_destroy_module = NULL, -+ .dtps_enable = dt_test_enable, -+ .dtps_disable = dt_test_disable, -+ .dtps_suspend = NULL, -+ .dtps_resume = NULL, -+ .dtps_getargdesc = NULL, -+ .dtps_getargval = NULL, -+ .dtps_usermode = NULL, -+ .dtps_destroy = dt_test_destroy -+}; -+ -+DT_PROVIDER_MODULE(dt_test, DTRACE_PRIV_USER) -diff --git a/dtrace/dtrace.h b/dtrace/dtrace.h -new file mode 100644 -index 0000000000000000000000000000000000000000..f632b910ac30b60a4584ea87a5087e4bba4060fc ---- /dev/null -+++ b/dtrace/dtrace.h -@@ -0,0 +1,35 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Dynamic Tracing for Linux -+ * -+ * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#ifndef _DTRACE_H_ -+#define _DTRACE_H_ -+ -+#include <linux/dtrace_cpu.h> -+#include <linux/dtrace_os.h> -+#include <linux/sched.h> -+#include <linux/types.h> -+ -+#include "dtrace_debug.h" -+ -+#include <dtrace/types.h> -+ -+#include <linux/dtrace/dtrace.h> -+ -+#include <dtrace/provider.h> -+#include <dtrace/dtrace_impl.h> -+ -+#endif /* _DTRACE_H_ */ -diff --git a/dtrace/dtrace_actdesc.c b/dtrace/dtrace_actdesc.c -new file mode 100644 -index 0000000000000000000000000000000000000000..fada47a6e5eb08ebf47d7905eeb8dfab3bb36941 ---- /dev/null -+++ b/dtrace/dtrace_actdesc.c -@@ -0,0 +1,91 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_actdesc.c -+ * DESCRIPTION: DTrace - action implementation -+ * -+ * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/slab.h> -+#include <linux/vmalloc.h> -+ -+#include "dtrace.h" -+ -+struct dtrace_actdesc *dtrace_actdesc_create(dtrace_actkind_t kind, -+ uint32_t ntuple, -+ uint64_t uarg, uint64_t arg) -+{ -+ struct dtrace_actdesc *act; -+ -+#ifdef FIXME -+ ASSERT(!DTRACEACT_ISPRINTFLIKE(kind) || -+ (arg != 0 && (uintptr_t)arg >= KERNELBASE) || -+ (arg == 0 && kind == DTRACEACT_PRINTA)); -+#else -+ ASSERT(!DTRACEACT_ISPRINTFLIKE(kind) || -+ (arg != 0) || -+ (arg == 0 && kind == DTRACEACT_PRINTA)); -+#endif -+ -+ act = kzalloc(sizeof(struct dtrace_actdesc), GFP_KERNEL); -+ if (act == NULL) -+ return NULL; -+ -+ act->dtad_kind = kind; -+ act->dtad_ntuple = ntuple; -+ act->dtad_uarg = uarg; -+ act->dtad_arg = arg; -+ act->dtad_refcnt = 1; -+ -+ return act; -+} -+ -+void dtrace_actdesc_hold(struct dtrace_actdesc *act) -+{ -+ ASSERT(act->dtad_refcnt >= 1); -+ -+ act->dtad_refcnt++; -+} -+ -+void dtrace_actdesc_release(struct dtrace_actdesc *act, -+ struct dtrace_vstate *vstate) -+{ -+ dtrace_actkind_t kind = act->dtad_kind; -+ struct dtrace_difo *dp; -+ -+ ASSERT(act->dtad_refcnt >= 1); -+ -+ if (--act->dtad_refcnt != 0) -+ return; -+ -+ dp = act->dtad_difo; -+ if (dp != NULL) -+ dtrace_difo_release(dp, vstate); -+ -+ if (DTRACEACT_ISPRINTFLIKE(kind)) { -+ char *str = (char *)(uintptr_t)act->dtad_arg; -+ -+#ifdef FIXME -+ ASSERT((str != NULL && (uintptr_t)str >= KERNELBASE) || -+ (str == NULL && act->dtad_kind == DTRACEACT_PRINTA)); -+#else -+ ASSERT((str != NULL) || -+ (str == NULL && act->dtad_kind == DTRACEACT_PRINTA)); -+#endif -+ -+ if (str != NULL) -+ vfree(str); -+ } -+ -+ kfree(act); -+} -diff --git a/dtrace/dtrace_anon.c b/dtrace/dtrace_anon.c -new file mode 100644 -index 0000000000000000000000000000000000000000..80d0d9c1a9fd1f515a2aa5ec22d648f7f7f1a46c ---- /dev/null -+++ b/dtrace/dtrace_anon.c -@@ -0,0 +1,144 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_anon.c -+ * DESCRIPTION: DTrace - Anonymous state implementation -+ * -+ * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include "dtrace.h" -+ -+struct dtrace_anon dtrace_anon; -+ -+struct dtrace_state *dtrace_anon_grab(void) -+{ -+ struct dtrace_state *state; -+ -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ -+ state = dtrace_anon.dta_state; -+ if (state == NULL) { -+ ASSERT(dtrace_anon.dta_enabling == NULL); -+ -+ return NULL; -+ } -+ -+ ASSERT(dtrace_anon.dta_enabling != NULL); -+ ASSERT(dtrace_retained != NULL); -+ -+ dtrace_enabling_destroy(dtrace_anon.dta_enabling); -+ dtrace_anon.dta_enabling = NULL; -+ dtrace_anon.dta_state = NULL; -+ -+ return state; -+} -+ -+void dtrace_anon_property(void) -+{ -+ int i, rv; -+ struct dtrace_state *state; -+ struct dof_hdr *dof; -+ char c[32]; /* enough for "dof-data-" + digits */ -+ -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ ASSERT(MUTEX_HELD(&cpu_lock)); -+ -+ for (i = 0; ; i++) { -+ snprintf(c, sizeof(c), "dof-data-%d", i); -+ -+ dtrace_err_verbose = 1; -+ -+ dof = dtrace_dof_property(c); -+ if (dof == NULL) { -+ dtrace_err_verbose = 0; -+ break; -+ } -+ -+#ifdef FIXME -+ /* -+ * We want to create anonymous state, so we need to transition -+ * the kernel debugger to indicate that DTrace is active. If -+ * this fails (e.g. because the debugger has modified text in -+ * some way), we won't continue with the processing. -+ */ -+ if (kdi_dtrace_set(KDI_DTSET_DTRACE_ACTIVATE) != 0) { -+ pr_info("kernel debugger active; " -+ "anonymous enabling ignored."); -+ dtrace_dof_destroy(dof); -+ break; -+ } -+#endif -+ -+ /* -+ * If we haven't allocated an anonymous state, we'll do so now. -+ */ -+ state = dtrace_anon.dta_state; -+ if (state == NULL) { -+ state = dtrace_state_create(NULL); -+ dtrace_anon.dta_state = state; -+ -+ if (state == NULL) { -+ /* -+ * This basically shouldn't happen: there is no -+ * failure mode from dtrace_state_create(). -+ * Still, the interface allows for a failure -+ * mode, and we want to fail as gracefully as -+ * possible: we'll emit an error message and -+ * cease processing anonymous state in this -+ * case. -+ */ -+ pr_warn("failed to create anonymous state"); -+ dtrace_dof_destroy(dof); -+ break; -+ } -+ } -+ -+ rv = dtrace_dof_slurp(dof, &state->dts_vstate, current_cred(), -+ &dtrace_anon.dta_enabling, 0, TRUE); -+ -+ if (rv == 0) -+ rv = dtrace_dof_options(dof, state); -+ -+ dtrace_err_verbose = 0; -+ dtrace_dof_destroy(dof); -+ -+ if (rv != 0) { -+ /* -+ * This is malformed DOF; chuck any anonymous state -+ * that we created. -+ */ -+ ASSERT(dtrace_anon.dta_enabling == NULL); -+ dtrace_state_destroy(state); -+ dtrace_anon.dta_state = NULL; -+ break; -+ } -+ -+ ASSERT(dtrace_anon.dta_enabling != NULL); -+ } -+ -+ if (dtrace_anon.dta_enabling != NULL) { -+ int rval; -+ -+ /* -+ * dtrace_enabling_retain() can only fail because we are -+ * trying to retain more enablings than are allowed -- but -+ * we only have one anonymous enabling, and we are guaranteed -+ * to be allowed at least one retained enabling; we assert -+ * that dtrace_enabling_retain() returns success. -+ */ -+ rval = dtrace_enabling_retain(dtrace_anon.dta_enabling); -+ ASSERT(rval == 0); -+ -+ dtrace_enabling_dump(dtrace_anon.dta_enabling); -+ } -+} -diff --git a/dtrace/dtrace_buffer.c b/dtrace/dtrace_buffer.c -new file mode 100644 -index 0000000000000000000000000000000000000000..9e7faebc51b7002fd286579d94770a958e44e972 ---- /dev/null -+++ b/dtrace/dtrace_buffer.c -@@ -0,0 +1,490 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_buffer.c -+ * DESCRIPTION: DTrace - buffer implementation -+ * -+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/vmalloc.h> -+ -+#include "dtrace.h" -+ -+dtrace_optval_t dtrace_nonroot_maxsize = (16 * 1024 * 1024); -+ -+/* -+ * Note: called from cross call context. This function switches the two -+ * buffers on a given CPU. The atomicity of this operation is assured by -+ * disabling interrupts while the actual switch takes place; the disabling of -+ * interrupts serializes the execution with any execution of dtrace_probe() on -+ * the same CPU. -+ */ -+void dtrace_buffer_switch(struct dtrace_buffer *buf) -+{ -+ caddr_t tomax = buf->dtb_tomax; -+ caddr_t xamot = buf->dtb_xamot; -+ dtrace_icookie_t cookie; -+ -+ ASSERT(!(buf->dtb_flags & DTRACEBUF_NOSWITCH)); -+ ASSERT(!(buf->dtb_flags & DTRACEBUF_RING)); -+ -+ local_irq_save(cookie); -+ -+ dt_dbg_buf("Switch (CPU %d): tomax %p (%lld) <-> xamot %p (%lld)\n", -+ smp_processor_id(), tomax, buf->dtb_offset, -+ xamot, buf->dtb_xamot_offset); -+ -+ buf->dtb_tomax = xamot; -+ buf->dtb_xamot = tomax; -+ buf->dtb_xamot_drops = buf->dtb_drops; -+ buf->dtb_xamot_offset = buf->dtb_offset; -+ buf->dtb_xamot_errors = buf->dtb_errors; -+ buf->dtb_xamot_flags = buf->dtb_flags; -+ buf->dtb_offset = 0; -+ buf->dtb_drops = 0; -+ buf->dtb_errors = 0; -+ buf->dtb_flags &= ~(DTRACEBUF_ERROR | DTRACEBUF_DROPPED); -+ -+ local_irq_restore(cookie); -+} -+ -+/* -+ * Note: called from cross call context. This function activates a buffer -+ * on a CPU. As with dtrace_buffer_switch(), the atomicity of the operation -+ * is guaranteed by the disabling of interrupts. -+ */ -+void dtrace_buffer_activate(struct dtrace_state *state) -+{ -+ struct dtrace_buffer *buf; -+ dtrace_icookie_t cookie; -+ -+ local_irq_save(cookie); -+ -+ buf = &state->dts_buffer[smp_processor_id()]; -+ -+ if (buf->dtb_tomax != NULL) -+ /* -+ * We might like to assert that the buffer is marked inactive, -+ * but this isn't necessarily true: the buffer for the CPU -+ * that processes the BEGIN probe has its buffer activated -+ * manually. In this case, we take the (harmless) action -+ * re-clearing the bit INACTIVE bit. -+ */ -+ buf->dtb_flags &= ~DTRACEBUF_INACTIVE; -+ -+ local_irq_restore(cookie); -+} -+ -+int dtrace_buffer_alloc(struct dtrace_buffer *bufs, size_t size, int flags, -+ processorid_t cpuid) -+{ -+ processorid_t cpu; -+ struct dtrace_buffer *buf; -+ -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ ASSERT(MUTEX_HELD(&cpu_lock)); -+ -+#ifdef FIXME -+ if (size > dtrace_nonroot_maxsize && -+ !PRIV_POLICY_CHOICE(current_cred(), PRIV_ALL, FALSE)) -+ return -EFBIG; -+#endif -+ -+ for_each_online_cpu(cpu) { -+ if (cpuid != DTRACE_CPUALL && cpuid != cpu) -+ continue; -+ -+ buf = &bufs[cpu]; -+ -+ /* -+ * If there is already a buffer allocated for this CPU, it -+ * is only possible that this is a DR event. In this case, -+ * the buffer size must match our specified size. -+ */ -+ if (buf->dtb_tomax != NULL) { -+ ASSERT(buf->dtb_size == size); -+ continue; -+ } -+ -+ ASSERT(buf->dtb_xamot == NULL); -+ -+ buf->dtb_tomax = dtrace_vzalloc_try(size); -+ if (buf->dtb_tomax == NULL) -+ goto err; -+ -+ buf->dtb_size = size; -+ buf->dtb_flags = flags; -+ buf->dtb_offset = 0; -+ buf->dtb_drops = 0; -+ -+ if (flags & DTRACEBUF_NOSWITCH) -+ continue; -+ -+ buf->dtb_xamot = dtrace_vzalloc_try(size); -+ if (buf->dtb_xamot == NULL) -+ goto err; -+ } -+ -+ return 0; -+ -+err: -+ for_each_online_cpu(cpu) { -+ if (cpuid != DTRACE_CPUALL && cpuid != cpu) -+ continue; -+ -+ buf = &bufs[cpu]; -+ -+ if (buf->dtb_xamot != NULL) { -+ ASSERT(buf->dtb_tomax != NULL); -+ ASSERT(buf->dtb_size == size); -+ vfree(buf->dtb_xamot); -+ } -+ -+ if (buf->dtb_tomax != NULL) { -+ ASSERT(buf->dtb_size == size); -+ vfree(buf->dtb_tomax); -+ } -+ -+ buf->dtb_tomax = NULL; -+ buf->dtb_xamot = NULL; -+ buf->dtb_size = 0; -+ } -+ -+ return -ENOMEM; -+} -+void dtrace_buffer_drop(struct dtrace_buffer *buf) -+{ -+ buf->dtb_drops++; -+} -+ -+intptr_t dtrace_buffer_reserve(struct dtrace_buffer *buf, size_t needed, -+ size_t align, struct dtrace_state *state, -+ struct dtrace_mstate *mstate) -+{ -+ intptr_t offs = buf->dtb_offset, soffs; -+ intptr_t woffs; -+ caddr_t tomax; -+ size_t total; -+ -+ if (buf->dtb_flags & DTRACEBUF_INACTIVE) -+ return -1; -+ -+ tomax = buf->dtb_tomax; -+ if (tomax == NULL) { -+ dtrace_buffer_drop(buf); -+ return -1; -+ } -+ -+ if (!(buf->dtb_flags & (DTRACEBUF_RING | DTRACEBUF_FILL))) { -+ while (offs & (align - 1)) { -+ /* -+ * Assert that our alignment is off by a number which -+ * is itself sizeof (uint32_t) aligned. -+ */ -+ ASSERT(!((align - (offs & (align - 1))) & -+ (sizeof(uint32_t) - 1))); -+ DTRACE_STORE(uint32_t, tomax, offs, DTRACE_EPIDNONE); -+ dt_dbg_buf(" Store: %p[%ld .. %ld] <- EPIDNONE " -+ "(from %s::%d)\n", -+ buf, offs, offs + sizeof(uint32_t) - 1, -+ __func__, __LINE__); -+ offs += sizeof(uint32_t); -+ } -+ -+ soffs = offs + needed; -+ if (soffs > buf->dtb_size) { -+ dtrace_buffer_drop(buf); -+ return -1; -+ } -+ -+ if (mstate == NULL) { -+ dt_dbg_buf(" Reserve: %p[%ld .. %ld]\n", -+ buf, offs, offs + needed - 1); -+ return offs; -+ } -+ -+ mstate->dtms_scratch_base = (uintptr_t)tomax + soffs; -+ mstate->dtms_scratch_size = buf->dtb_size - soffs; -+ mstate->dtms_scratch_ptr = mstate->dtms_scratch_base; -+ -+ dt_dbg_buf(" Reserve: %p[%ld .. %ld]\n", -+ buf, offs, offs + needed - 1); -+ return offs; -+ } -+ -+ if (buf->dtb_flags & DTRACEBUF_FILL) { -+ if (state->dts_activity != DTRACE_ACTIVITY_COOLDOWN && -+ (buf->dtb_flags & DTRACEBUF_FULL)) -+ return -1; -+ -+ goto out; -+ } -+ -+ total = needed + (offs & (align - 1)); -+ -+ /* -+ * For a ring buffer, life is quite a bit more complicated. Before -+ * we can store any padding, we need to adjust our wrapping offset. -+ * (If we've never before wrapped or we're not about to, no adjustment -+ * is required.) -+ */ -+ if ((buf->dtb_flags & DTRACEBUF_WRAPPED) || -+ offs + total > buf->dtb_size) { -+ woffs = buf->dtb_xamot_offset; -+ -+ if (offs + total > buf->dtb_size) { -+ /* -+ * We can't fit in the end of the buffer. First, a -+ * sanity check that we can fit in the buffer at all. -+ */ -+ if (total > buf->dtb_size) { -+ dtrace_buffer_drop(buf); -+ return -1; -+ } -+ -+ /* -+ * We're going to be storing at the top of the buffer, -+ * so now we need to deal with the wrapped offset. We -+ * only reset our wrapped offset to 0 if it is -+ * currently greater than the current offset. If it -+ * is less than the current offset, it is because a -+ * previous allocation induced a wrap -- but the -+ * allocation didn't subsequently take the space due -+ * to an error or false predicate evaluation. In this -+ * case, we'll just leave the wrapped offset alone: if -+ * the wrapped offset hasn't been advanced far enough -+ * for this allocation, it will be adjusted in the -+ * lower loop. -+ */ -+ if (buf->dtb_flags & DTRACEBUF_WRAPPED) { -+ if (woffs >= offs) -+ woffs = 0; -+ } else -+ woffs = 0; -+ -+ /* -+ * Now we know that we're going to be storing to the -+ * top of the buffer and that there is room for us -+ * there. We need to clear the buffer from the current -+ * offset to the end (there may be old gunk there). -+ */ -+ while (offs < buf->dtb_size) -+ tomax[offs++] = 0; -+ -+ /* -+ * We need to set our offset to zero. And because we -+ * are wrapping, we need to set the bit indicating as -+ * much. We can also adjust our needed space back -+ * down to the space required by the ECB -- we know -+ * that the top of the buffer is aligned. -+ */ -+ offs = 0; -+ total = needed; -+ buf->dtb_flags |= DTRACEBUF_WRAPPED; -+ } else { -+ /* -+ * There is room for us in the buffer, so we simply -+ * need to check the wrapped offset. -+ */ -+ if (woffs < offs) { -+ /* -+ * The wrapped offset is less than the offset. -+ * This can happen if we allocated buffer space -+ * that induced a wrap, but then we didn't -+ * subsequently take the space due to an error -+ * or false predicate evaluation. This is -+ * okay; we know that _this_ allocation isn't -+ * going to induce a wrap. We still can't -+ * reset the wrapped offset to be zero, -+ * however: the space may have been trashed in -+ * the previous failed probe attempt. But at -+ * least the wrapped offset doesn't need to -+ * be adjusted at all... -+ */ -+ goto out; -+ } -+ } -+ -+ while (offs + total > woffs) { -+ dtrace_epid_t epid = *(uint32_t *)(tomax + woffs); -+ size_t size; -+ -+ if (epid == DTRACE_EPIDNONE) -+ size = sizeof(uint32_t); -+ else { -+ ASSERT(epid <= state->dts_necbs); -+ ASSERT(state->dts_ecbs[epid - 1] != NULL); -+ -+ size = state->dts_ecbs[epid - 1]->dte_size; -+ } -+ -+ ASSERT(woffs + size <= buf->dtb_size); -+ ASSERT(size != 0); -+ -+ if (woffs + size == buf->dtb_size) { -+ /* -+ * We've reached the end of the buffer; we want -+ * to set the wrapped offset to 0 and break -+ * out. However, if the offs is 0, then we're -+ * in a strange edge-condition: the amount of -+ * space that we want to reserve plus the size -+ * of the record that we're overwriting is -+ * space but subsequently don't consume it (due -+ * to a failed predicate or error) the wrapped -+ * offset will be 0 -- yet the EPID at offset 0 -+ * will not be committed. This situation is -+ * relatively easy to deal with: if we're in -+ * this case, the buffer is indistinguishable -+ * from one that hasn't wrapped; we need only -+ * finish the job by clearing the wrapped bit, -+ * explicitly setting the offset to be 0, and -+ * zero'ing out the old data in the buffer. -+ */ -+ if (offs == 0) { -+ buf->dtb_flags &= ~DTRACEBUF_WRAPPED; -+ buf->dtb_offset = 0; -+ woffs = total; -+ -+ while (woffs < buf->dtb_size) -+ tomax[woffs++] = 0; -+ } -+ -+ woffs = 0; -+ break; -+ } -+ -+ woffs += size; -+ } -+ -+ /* -+ * We have a wrapped offset. It may be that the wrapped offset -+ * has become zero -- that's okay. -+ */ -+ buf->dtb_xamot_offset = woffs; -+ } -+ -+out: -+ /* -+ * Now we can plow the buffer with any necessary padding. -+ */ -+ while (offs & (align - 1)) { -+ /* -+ * Assert that our alignment is off by a number which -+ * is itself sizeof(uint32_t) aligned. -+ */ -+ ASSERT(!((align - (offs & (align - 1))) & -+ (sizeof(uint32_t) - 1))); -+ DTRACE_STORE(uint32_t, tomax, offs, DTRACE_EPIDNONE); -+ dt_dbg_buf(" Store: %p[%ld .. %ld] <- EPIDNONE " -+ "(from %s::%d)\n", -+ buf, offs, offs + sizeof(uint32_t) - 1, -+ __func__, __LINE__); -+ offs += sizeof(uint32_t); -+ } -+ -+ if (buf->dtb_flags & DTRACEBUF_FILL) { -+ if (offs + needed > buf->dtb_size - state->dts_reserve) { -+ buf->dtb_flags |= DTRACEBUF_FULL; -+ return -1; -+ } -+ } -+ -+ if (mstate == NULL) { -+ dt_dbg_buf(" Reserve: %p[%ld .. %ld]\n", -+ buf, offs, offs + needed - 1); -+ return offs; -+ } -+ -+ /* -+ * For ring buffers and fill buffers, the scratch space is always -+ * the inactive buffer. -+ */ -+ mstate->dtms_scratch_base = (uintptr_t)buf->dtb_xamot; -+ mstate->dtms_scratch_size = buf->dtb_size; -+ mstate->dtms_scratch_ptr = mstate->dtms_scratch_base; -+ -+ dt_dbg_buf(" Reserve: %p[%ld .. %ld]\n", -+ buf, offs, offs + needed - 1); -+ return offs; -+} -+ -+void dtrace_buffer_polish(struct dtrace_buffer *buf) -+{ -+ ASSERT(buf->dtb_flags & DTRACEBUF_RING); -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ -+ if (!(buf->dtb_flags & DTRACEBUF_WRAPPED)) -+ return; -+ -+ /* -+ * We need to polish the ring buffer. There are three cases: -+ * -+ * - The first (and presumably most common) is that there is no gap -+ * between the buffer offset and the wrapped offset. In this case, -+ * there is nothing in the buffer that isn't valid data; we can -+ * mark the buffer as polished and return. -+ * -+ * - The second (less common than the first but still more common -+ * than the third) is that there is a gap between the buffer offset -+ * and the wrapped offset, and the wrapped offset is larger than the -+ * buffer offset. This can happen because of an alignment issue, or -+ * can happen because of a call to dtrace_buffer_reserve() that -+ * didn't subsequently consume the buffer space. In this case, -+ * we need to zero the data from the buffer offset to the wrapped -+ * offset. -+ * -+ * - The third (and least common) is that there is a gap between the -+ * buffer offset and the wrapped offset, but the wrapped offset is -+ * _less_ than the buffer offset. This can only happen because a -+ * call to dtrace_buffer_reserve() induced a wrap, but the space -+ * was not subsequently consumed. In this case, we need to zero the -+ * space from the offset to the end of the buffer _and_ from the -+ * top of the buffer to the wrapped offset. -+ */ -+ if (buf->dtb_offset < buf->dtb_xamot_offset) -+ memset(buf->dtb_tomax + buf->dtb_offset, 0, -+ buf->dtb_xamot_offset - buf->dtb_offset); -+ -+ if (buf->dtb_offset > buf->dtb_xamot_offset) { -+ memset(buf->dtb_tomax + buf->dtb_offset, 0, -+ buf->dtb_size - buf->dtb_offset); -+ memset(buf->dtb_tomax, 0, buf->dtb_xamot_offset); -+ } -+} -+ -+void dtrace_buffer_free(struct dtrace_buffer *bufs) -+{ -+ int cpu; -+ -+ for_each_online_cpu(cpu) { -+ struct dtrace_buffer *buf = &bufs[cpu]; -+ -+ if (buf->dtb_tomax == NULL) { -+ ASSERT(buf->dtb_xamot == NULL); -+ ASSERT(buf->dtb_size == 0); -+ -+ continue; -+ } -+ -+ if (buf->dtb_xamot != NULL) { -+ ASSERT(!(buf->dtb_flags & DTRACEBUF_NOSWITCH)); -+ -+ vfree(buf->dtb_xamot); -+ buf->dtb_xamot = NULL; -+ } -+ -+ vfree(buf->dtb_tomax); -+ buf->dtb_size = 0; -+ buf->dtb_tomax = NULL; -+ } -+} -diff --git a/dtrace/dtrace_debug.h b/dtrace/dtrace_debug.h -new file mode 100644 -index 0000000000000000000000000000000000000000..a55fd1a0436fdfd60e05290ea5ae0e3986bfc66c ---- /dev/null -+++ b/dtrace/dtrace_debug.h -@@ -0,0 +1,118 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Dynamic Tracing for Linux -+ * -+ * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#ifndef _DTRACE_DEBUG_H_ -+#define _DTRACE_DEBUG_H_ -+ -+#ifdef CONFIG_DT_DEBUG -+ -+/* -+ * Enable all output and use dynamic debug when supported. -+ */ -+# ifdef CONFIG_DYNAMIC_DEBUG -+ -+# define DT_DBG_AGG -+# define DT_DBG_BUF -+# define DT_DBG_DIF -+# define DT_DBG_DOF -+# define DT_DBG_ENABLE -+# define DT_DBG_IOCTL -+# define DT_DBG_PROBE -+# define DT_DBG_PROVIDER -+ -+# define dt_dbg_print(fmt, ...) pr_debug(fmt, ## __VA_ARGS__) -+ -+# else /* CONFIG_DYNAMIC_DEBUG */ -+ -+# undef DT_DBG_AGG -+# undef DT_DBG_BUF -+# undef DT_DBG_DIF -+# undef DT_DBG_DOF -+# undef DT_DBG_ENABLE -+# undef DT_DBG_IOCTL -+# undef DT_DBG_PROBE -+# undef DT_DBG_PROVIDER -+ -+# define dt_dbg_print(fmt, ...) pr_info(fmt, ## __VA_ARGS__) -+ -+# endif /* CONFIG_DYNAMIC_DEBUG */ -+ -+#else /* CONFIG_DT_DEBUG */ -+ -+# undef DT_DBG_AGG -+# undef DT_DBG_BUF -+# undef DT_DBG_DIF -+# undef DT_DBG_DOF -+# undef DT_DBG_ENABLE -+# undef DT_DBG_IOCTL -+# undef DT_DBG_PROBE -+# undef DT_DBG_PROVIDER -+ -+#endif /* CONFIG_DT_DEBUG */ -+ -+/* -+ * Here are the actual actions for the various debug cases. -+ */ -+#ifdef DT_DBG_AGG -+# define dt_dbg_agg(fmt, ...) dt_dbg_print(fmt, ## __VA_ARGS__) -+#else -+# define dt_dbg_agg(fmt, ...) -+#endif -+ -+#ifdef DT_DBG_BUF -+# define dt_dbg_buf(fmt, ...) dt_dbg_print(fmt, ## __VA_ARGS__) -+#else -+# define dt_dbg_buf(fmt, ...) -+#endif -+ -+#ifdef DT_DBG_DIF -+# define dt_dbg_dif(fmt, ...) dt_dbg_print(fmt, ## __VA_ARGS__) -+#else -+# define dt_dbg_dif(fmt, ...) -+#endif -+ -+#ifdef DT_DBG_DOF -+# define dt_dbg_dof(fmt, ...) dt_dbg_print(fmt, ## __VA_ARGS__) -+#else -+# define dt_dbg_dof(fmt, ...) -+#endif -+ -+#ifdef DT_DBG_ENABLE -+# define dt_dbg_enable(fmt, ...) dt_dbg_print(fmt, ## __VA_ARGS__) -+#else -+# define dt_dbg_enable(fmt, ...) -+#endif -+ -+#ifdef DT_DBG_IOCTL -+# define dt_dbg_ioctl(fmt, ...) dt_dbg_print(fmt, ## __VA_ARGS__) -+#else -+# define dt_dbg_ioctl(fmt, ...) -+#endif -+ -+#ifdef DT_DBG_PROBE -+# define dt_dbg_probe(fmt, ...) dt_dbg_print(fmt, ## __VA_ARGS__) -+#else -+# define dt_dbg_probe(fmt, ...) -+#endif -+ -+#ifdef DT_DBG_PROVIDER -+# define dt_dbg_prov(fmt, ...) dt_dbg_print(fmt, ## __VA_ARGS__) -+#else -+# define dt_dbg_prov(fmt, ...) -+#endif -+ -+#endif /* _DTRACE_DEBUG_H_ */ -diff --git a/dtrace/dtrace_dev.c b/dtrace/dtrace_dev.c -new file mode 100644 -index 0000000000000000000000000000000000000000..0e52c936b9e03bdf56d2a11e41528ed9b461af66 ---- /dev/null -+++ b/dtrace/dtrace_dev.c -@@ -0,0 +1,1599 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_dev.c -+ * DESCRIPTION: DTrace - Framework device driver -+ * -+ * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/delay.h> -+#include <dtrace/types.h> -+#include <linux/dtrace/ioctl.h> -+#include <linux/fs.h> -+#include <linux/jiffies.h> -+#include <linux/kernel.h> -+#include <linux/miscdevice.h> -+#include <linux/slab.h> -+#include <linux/vmalloc.h> -+#include <linux/uaccess.h> -+ -+#include "ctf_api.h" -+#include "dtrace.h" -+#include "dtrace_dev.h" -+ -+extern char *dtrace_helptrace_buffer; -+extern int dtrace_helptrace_bufsize; -+extern int dtrace_helptrace_enabled; -+ -+int dtrace_opens; -+int dtrace_err_verbose; -+ -+struct dtrace_pops dtrace_provider_ops = { -+ (void (*)(void *, const struct dtrace_probedesc *))dtrace_nullop, -+ (void (*)(void *, struct module *))dtrace_nullop, -+ (int (*)(void *, dtrace_id_t, void *))dtrace_enable_nullop, -+ (void (*)(void *, dtrace_id_t, void *))dtrace_nullop, -+ (void (*)(void *, dtrace_id_t, void *))dtrace_nullop, -+ (void (*)(void *, dtrace_id_t, void *))dtrace_nullop, -+ NULL, -+ NULL, -+ NULL, -+ (void (*)(void *, dtrace_id_t, void *))dtrace_nullop, -+ (void (*)(void *, struct module *))dtrace_nullop, -+}; -+ -+static size_t dtrace_retain_max = 1024; -+ -+struct dtrace_toxrange *dtrace_toxrange; -+int dtrace_toxranges; -+static int dtrace_toxranges_max; -+ -+struct kmem_cache *dtrace_state_cachep; -+ -+struct user_namespace *init_user_namespace; -+ -+static struct dtrace_pattr dtrace_provider_attr = { -+{ DTRACE_STABILITY_STABLE, DTRACE_STABILITY_STABLE, DTRACE_CLASS_COMMON }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_STABLE, DTRACE_STABILITY_STABLE, DTRACE_CLASS_COMMON }, -+{ DTRACE_STABILITY_STABLE, DTRACE_STABILITY_STABLE, DTRACE_CLASS_COMMON }, -+}; -+ -+DEFINE_MUTEX(dtrace_lock); -+ -+void dtrace_nullop(void) -+{ -+} -+ -+int dtrace_enable_nullop(void) -+{ -+ return 0; -+} -+ -+ -+#ifdef CONFIG_DT_DEBUG -+static void dtrace_ioctl_sizes(void) -+{ -+#define DBG_PRINT(x) dt_dbg_ioctl("Size of %s: %lx\n", #x, sizeof(x)) -+ DBG_PRINT(struct dtrace_providerdesc); -+ DBG_PRINT(struct dtrace_probedesc); -+ DBG_PRINT(struct dtrace_bufdesc); -+ DBG_PRINT(struct dtrace_eprobedesc); -+ DBG_PRINT(struct dtrace_argdesc); -+ DBG_PRINT(struct dtrace_conf); -+ DBG_PRINT(struct dtrace_status); -+ DBG_PRINT(processorid_t); -+ DBG_PRINT(struct dtrace_aggdesc); -+ DBG_PRINT(struct dtrace_fmtdesc); -+ DBG_PRINT(struct dof_hdr); -+#undef DBG_PRINT -+} -+ -+#endif -+ -+static int dtrace_open(struct inode *inode, struct file *file) -+{ -+ struct dtrace_state *state; -+ uint32_t priv; -+ kuid_t uid; -+ -+ dtrace_cred2priv(file->f_cred, &priv, &uid); -+ if (priv == DTRACE_PRIV_NONE) -+ return -EACCES; -+ -+#ifdef CONFIG_DT_DEBUG -+ dtrace_ioctl_sizes(); -+#endif -+ mutex_lock(&module_mutex); -+ mutex_lock(&dtrace_provider_lock); -+ dtrace_probe_provide(NULL, NULL); -+ mutex_unlock(&dtrace_provider_lock); -+ mutex_unlock(&module_mutex); -+ -+ mutex_lock(&cpu_lock); -+ mutex_lock(&dtrace_lock); -+ -+ /* -+ * Do not let a consumer continue if it is not possible to enable -+ * DTrace. -+ */ -+ if (dtrace_enable() != 0) { -+ mutex_unlock(&dtrace_lock); -+ mutex_unlock(&cpu_lock); -+ return -EBUSY; -+ } -+ -+ dtrace_opens++; -+ dtrace_membar_producer(); -+ -+ state = dtrace_state_create(file); -+ mutex_unlock(&cpu_lock); -+ -+ if (state == NULL) { -+ if (--dtrace_opens == 0 && dtrace_anon.dta_enabling == NULL) -+ dtrace_disable(); -+ mutex_unlock(&dtrace_lock); -+ -+ return -EAGAIN; -+ } -+ -+ file->private_data = state; -+ mutex_unlock(&dtrace_lock); -+ -+ return 0; -+} -+ -+static long dtrace_ioctl(struct file *file, -+ unsigned int cmd, unsigned long arg) -+{ -+ struct dtrace_state *state; -+ int rval; -+ void __user *argp = (void __user *)arg; -+ -+ state = (struct dtrace_state *) file->private_data; -+ if (state->dts_anon) { -+ ASSERT(dtrace_anon.dta_state == NULL); -+ state = state->dts_anon; -+ } -+ -+ switch (cmd) { -+ case DTRACEIOC_PROVIDER: { -+ struct dtrace_providerdesc pvd; -+ struct dtrace_provider *pvp; -+ -+ dt_dbg_ioctl("IOCTL PROVIDER (cmd %#x), argp %p\n", cmd, argp); -+ -+ if (copy_from_user(&pvd, argp, sizeof(pvd)) != 0) -+ return -EFAULT; -+ -+ pvd.dtvd_name[DTRACE_PROVNAMELEN - 1] = '\0'; -+ mutex_lock(&dtrace_provider_lock); -+ -+ for (pvp = dtrace_provider; pvp != NULL; pvp = pvp->dtpv_next) { -+ if (strcmp(pvp->dtpv_name, pvd.dtvd_name) == 0) -+ break; -+ } -+ -+ mutex_unlock(&dtrace_provider_lock); -+ -+ dt_dbg_ioctl(" Provider '%s' %sfound\n", -+ pvd.dtvd_name, pvp ? "" : "not "); -+ if (pvp == NULL) -+ return -ESRCH; -+ -+ memcpy(&pvd.dtvd_priv, &pvp->dtpv_priv, -+ sizeof(struct dtrace_ppriv)); -+ memcpy(&pvd.dtvd_attr, &pvp->dtpv_attr, -+ sizeof(struct dtrace_pattr)); -+ -+ if (copy_to_user(argp, &pvd, sizeof(pvd)) != 0) -+ return -EFAULT; -+ -+ return 0; -+ } -+ -+ case DTRACEIOC_EPROBE: { -+ struct dtrace_eprobedesc epdesc; -+ struct dtrace_ecb *ecb; -+ struct dtrace_action *act; -+ void *buf; -+ size_t size; -+ uint8_t *dest; -+ int nrecs; -+ -+ dt_dbg_ioctl("IOCTL EPROBE (cmd %#x), argp %p\n", cmd, argp); -+ -+ if (copy_from_user(&epdesc, argp, sizeof(epdesc)) != 0) -+ return -EFAULT; -+ -+ mutex_lock(&dtrace_lock); -+ -+ ecb = dtrace_epid2ecb(state, epdesc.dtepd_epid); -+ if (ecb == NULL) { -+ mutex_unlock(&dtrace_lock); -+ return -EINVAL; -+ } -+ -+ if (ecb->dte_probe == NULL) { -+ mutex_unlock(&dtrace_lock); -+ return -EINVAL; -+ } -+ -+ epdesc.dtepd_probeid = ecb->dte_probe->dtpr_id; -+ epdesc.dtepd_uarg = ecb->dte_uarg; -+ epdesc.dtepd_size = ecb->dte_size; -+ -+ nrecs = epdesc.dtepd_nrecs; -+ epdesc.dtepd_nrecs = 0; -+ for (act = ecb->dte_action; act != NULL; act = act->dta_next) { -+ if (DTRACEACT_ISAGG(act->dta_kind) || act->dta_intuple) -+ continue; -+ -+ epdesc.dtepd_nrecs++; -+ } -+ -+ /* -+ * Now that we have the size, we need to allocate a temporary -+ * buffer in which to store the complete description. We need -+ * the temporary buffer to be able to drop dtrace_lock() -+ * across the copy_to_user(), below. -+ */ -+ size = sizeof(struct dtrace_eprobedesc) + -+ (epdesc.dtepd_nrecs * sizeof(struct dtrace_recdesc)); -+ -+ buf = vmalloc(size); -+ if (buf == NULL) -+ return -ENOMEM; -+ -+ dest = buf; -+ memcpy(dest, &epdesc, sizeof(epdesc)); -+ dest += offsetof(struct dtrace_eprobedesc, dtepd_rec[0]); -+ -+ for (act = ecb->dte_action; act != NULL; act = act->dta_next) { -+ if (DTRACEACT_ISAGG(act->dta_kind) || act->dta_intuple) -+ continue; -+ -+ if (nrecs-- == 0) -+ break; -+ -+ memcpy(dest, &act->dta_rec, -+ sizeof(struct dtrace_recdesc)); -+ dest += sizeof(struct dtrace_recdesc); -+ } -+ -+ mutex_unlock(&dtrace_lock); -+ -+ if (copy_to_user(argp, buf, -+ (uintptr_t)(dest - (uint8_t *)buf)) != 0) { -+ vfree(buf); -+ return -EFAULT; -+ } -+ -+ vfree(buf); -+ return 0; -+ } -+ -+ case DTRACEIOC_AGGDESC: { -+ struct dtrace_aggdesc aggdesc; -+ struct dtrace_action *act; -+ struct dtrace_aggregation *agg; -+ int nrecs; -+ uint32_t offs; -+ struct dtrace_recdesc *lrec; -+ void *buf; -+ size_t size; -+ uint8_t *dest; -+ -+ dt_dbg_ioctl("IOCTL AGGDESC (cmd %#x), argp %p\n", cmd, argp); -+ -+ if (copy_from_user(&aggdesc, argp, sizeof(aggdesc)) != 0) -+ return -EFAULT; -+ -+ mutex_lock(&dtrace_lock); -+ -+ agg = dtrace_aggid2agg(state, aggdesc.dtagd_id); -+ if (agg == NULL) { -+ mutex_unlock(&dtrace_lock); -+ return -EINVAL; -+ } -+ -+ aggdesc.dtagd_epid = agg->dtag_ecb->dte_epid; -+ -+ nrecs = aggdesc.dtagd_nrecs; -+ aggdesc.dtagd_nrecs = 0; -+ -+ offs = agg->dtag_base; -+ lrec = &agg->dtag_action.dta_rec; -+ aggdesc.dtagd_size = lrec->dtrd_offset + lrec->dtrd_size - -+ offs; -+ -+ for (act = agg->dtag_first; ; act = act->dta_next) { -+ ASSERT(act->dta_intuple || -+ DTRACEACT_ISAGG(act->dta_kind)); -+ -+ /* -+ * If this action has a record size of zero, it -+ * denotes an argument to the aggregating action. -+ * Because the presence of this record doesn't (or -+ * shouldn't) affect the way the data is interpreted, -+ * we don't copy it out to save user-level the -+ * confusion of dealing with a zero-length record. -+ */ -+ if (act->dta_rec.dtrd_size == 0) { -+ ASSERT(agg->dtag_hasarg); -+ continue; -+ } -+ -+ aggdesc.dtagd_nrecs++; -+ -+ if (act == &agg->dtag_action) -+ break; -+ } -+ -+ /* -+ * Now that we have the size, we need to allocate a temporary -+ * buffer in which to store the complete description. We need -+ * the temporary buffer to be able to drop dtrace_lock() -+ * across the copyout(), below. -+ */ -+ size = sizeof(struct dtrace_aggdesc) + -+ (aggdesc.dtagd_nrecs * sizeof(struct dtrace_recdesc)); -+ -+ buf = vmalloc(size); -+ if (buf == NULL) -+ return -ENOMEM; -+ -+ dest = buf; -+ memcpy(dest, &aggdesc, sizeof(aggdesc)); -+ dest += offsetof(struct dtrace_aggdesc, dtagd_rec[0]); -+ -+ for (act = agg->dtag_first; ; act = act->dta_next) { -+ struct dtrace_recdesc rec = act->dta_rec; -+ -+ /* -+ * See the comment in the above loop for why we pass -+ * over zero-length records. -+ */ -+ if (rec.dtrd_size == 0) { -+ ASSERT(agg->dtag_hasarg); -+ continue; -+ } -+ -+ if (nrecs-- == 0) -+ break; -+ -+ rec.dtrd_offset -= offs; -+ memcpy(dest, &rec, sizeof(rec)); -+ dest += sizeof(struct dtrace_recdesc); -+ -+ if (act == &agg->dtag_action) -+ break; -+ } -+ -+ mutex_unlock(&dtrace_lock); -+ -+ if (copy_to_user(argp, buf, -+ (uintptr_t)(dest - (uint8_t *)buf)) != 0) { -+ vfree(buf); -+ return -EFAULT; -+ } -+ -+ vfree(buf); -+ return 0; -+ } -+ -+ case DTRACEIOC_ENABLE: { -+ struct dof_hdr *dof; -+ struct dtrace_enabling *enab = NULL; -+ struct dtrace_vstate *vstate; -+ int err = 0; -+ int rv; -+ -+ dt_dbg_ioctl("IOCTL ENABLE (cmd %#x), argp %p\n", cmd, argp); -+ -+ rv = 0; -+ -+ /* -+ * If a NULL argument has been passed, we take this as our -+ * cue to reevaluate our enablings. -+ */ -+ if (argp == NULL) { -+ dtrace_enabling_matchall(); -+ -+ return 0; -+ } -+ -+ dof = dtrace_dof_copyin(argp, &rval); -+ if (dof == NULL) -+ return rval; -+ -+ mutex_lock(&cpu_lock); -+ mutex_lock(&dtrace_lock); -+ vstate = &state->dts_vstate; -+ -+ if (state->dts_activity != DTRACE_ACTIVITY_INACTIVE) { -+ mutex_unlock(&dtrace_lock); -+ mutex_unlock(&cpu_lock); -+ dtrace_dof_destroy(dof); -+ return -EBUSY; -+ } -+ -+ if (dtrace_dof_slurp(dof, vstate, file->f_cred, &enab, 0, -+ TRUE) != 0) { -+ mutex_unlock(&dtrace_lock); -+ mutex_unlock(&cpu_lock); -+ dtrace_dof_destroy(dof); -+ return -EINVAL; -+ } -+ -+ rval = dtrace_dof_options(dof, state); -+ if (rval != 0) { -+ dtrace_enabling_destroy(enab); -+ mutex_unlock(&dtrace_lock); -+ mutex_unlock(&cpu_lock); -+ dtrace_dof_destroy(dof); -+ return rval; -+ } -+ -+ err = dtrace_enabling_match(enab, &rv); -+ if (err == 0) -+ err = dtrace_enabling_retain(enab); -+ else -+ dtrace_enabling_destroy(enab); -+ -+ mutex_unlock(&dtrace_lock); -+ mutex_unlock(&cpu_lock); -+ dtrace_dof_destroy(dof); -+ -+ return err == 0 ? rv : err; -+ } -+ -+ case DTRACEIOC_REPLICATE: { -+ struct dtrace_repldesc desc; -+ struct dtrace_probedesc *match = &desc.dtrpd_match; -+ struct dtrace_probedesc *create = &desc.dtrpd_create; -+ int err; -+ -+ dt_dbg_ioctl("IOCTL REPLICATE (cmd %#x), argp %p\n", -+ cmd, argp); -+ -+ if (copy_from_user(&desc, argp, sizeof(desc)) != 0) -+ return -EFAULT; -+ -+ match->dtpd_provider[DTRACE_PROVNAMELEN - 1] = '\0'; -+ match->dtpd_mod[DTRACE_MODNAMELEN - 1] = '\0'; -+ match->dtpd_func[DTRACE_FUNCNAMELEN - 1] = '\0'; -+ match->dtpd_name[DTRACE_NAMELEN - 1] = '\0'; -+ -+ create->dtpd_provider[DTRACE_PROVNAMELEN - 1] = '\0'; -+ create->dtpd_mod[DTRACE_MODNAMELEN - 1] = '\0'; -+ create->dtpd_func[DTRACE_FUNCNAMELEN - 1] = '\0'; -+ create->dtpd_name[DTRACE_NAMELEN - 1] = '\0'; -+ -+ mutex_lock(&dtrace_lock); -+ err = dtrace_enabling_replicate(state, match, create); -+ mutex_unlock(&dtrace_lock); -+ -+ return err; -+ } -+ -+ case DTRACEIOC_PROBEMATCH: -+ case DTRACEIOC_PROBES: { -+ int id; -+ struct dtrace_probe *probe = NULL; -+ struct dtrace_probedesc desc; -+ struct dtrace_probekey pkey; -+ uint32_t priv; -+ kuid_t uid; -+ -+ dt_dbg_ioctl("IOCTL %s (cmd %#x), argp %p\n", -+ cmd == DTRACEIOC_PROBES ? "PROBES" -+ : "PROBEMATCH", -+ cmd, argp); -+ -+ if (copy_from_user(&desc, argp, sizeof(desc)) != 0) -+ return -EFAULT; -+ -+ desc.dtpd_provider[DTRACE_PROVNAMELEN - 1] = '\0'; -+ desc.dtpd_mod[DTRACE_MODNAMELEN - 1] = '\0'; -+ desc.dtpd_func[DTRACE_FUNCNAMELEN - 1] = '\0'; -+ desc.dtpd_name[DTRACE_NAMELEN - 1] = '\0'; -+ dt_dbg_ioctl(" Probe ID %d %s:%s:%s:%s\n", -+ desc.dtpd_id, desc.dtpd_provider, desc.dtpd_mod, -+ desc.dtpd_func, desc.dtpd_name); -+ -+ /* -+ * Before we attempt to match this probe, we want to give -+ * all providers the opportunity to provide it. -+ */ -+ if (desc.dtpd_id == DTRACE_IDNONE) { -+ mutex_lock(&module_mutex); -+ mutex_lock(&dtrace_provider_lock); -+ dtrace_probe_provide(&desc, NULL); -+ mutex_unlock(&dtrace_provider_lock); -+ mutex_unlock(&module_mutex); -+ } -+ -+ if (cmd == DTRACEIOC_PROBEMATCH) { -+ dtrace_probekey(&desc, &pkey); -+ pkey.dtpk_id = DTRACE_IDNONE; -+ } -+ -+ dtrace_cred2priv(file->f_cred, &priv, &uid); -+ -+ mutex_lock(&dtrace_lock); -+ -+ id = desc.dtpd_id; -+ if (cmd == DTRACEIOC_PROBEMATCH) { -+ int m = 0; -+ -+ while ((probe = dtrace_probe_get_next(&id)) -+ != NULL) { -+ m = dtrace_match_probe(probe, &pkey, priv, uid); -+ if (m) -+ break; -+ -+ id++; -+ } -+ -+ if (m < 0) { -+ mutex_unlock(&dtrace_lock); -+ return -EINVAL; -+ } -+ } else { -+ while ((probe = dtrace_probe_get_next(&id)) -+ != NULL) { -+ if (dtrace_match_priv(probe, priv, uid)) -+ break; -+ -+ id++; -+ } -+ } -+ -+ if (probe == NULL) { -+ mutex_unlock(&dtrace_lock); -+ return -ESRCH; -+ } -+ -+ dtrace_probe_description(probe, &desc); -+ mutex_unlock(&dtrace_lock); -+ -+ if (copy_to_user(argp, &desc, sizeof(desc)) != 0) -+ return -EFAULT; -+ -+ return 0; -+ } -+ -+ case DTRACEIOC_PROBEARG: { -+ struct dtrace_argdesc desc; -+ struct dtrace_probe *probe; -+ struct dtrace_provider *prov; -+ -+ dt_dbg_ioctl("IOCTL PROBEARG (cmd %#x), argp %p\n", cmd, argp); -+ -+ if (copy_from_user(&desc, argp, sizeof(desc)) != 0) -+ return -EFAULT; -+ -+ if (desc.dtargd_id == DTRACE_IDNONE) -+ return -EINVAL; -+ -+ if (desc.dtargd_ndx == DTRACE_ARGNONE) -+ return -EINVAL; -+ -+ mutex_lock(&module_mutex); -+ mutex_lock(&dtrace_provider_lock); -+ mutex_lock(&dtrace_lock); -+ -+ probe = dtrace_probe_lookup_id(desc.dtargd_id); -+ if (probe == NULL) { -+ mutex_unlock(&dtrace_lock); -+ mutex_unlock(&dtrace_provider_lock); -+ mutex_unlock(&module_mutex); -+ -+ return -EINVAL; -+ } -+ -+ mutex_unlock(&dtrace_lock); -+ -+ prov = probe->dtpr_provider; -+ -+ if (prov->dtpv_pops.dtps_getargdesc == NULL) { -+ /* -+ * There isn't any typed information for this probe. -+ * Set the argument number to DTRACE_ARGNONE. -+ */ -+ desc.dtargd_ndx = DTRACE_ARGNONE; -+ } else { -+ desc.dtargd_native[0] = '\0'; -+ desc.dtargd_xlate[0] = '\0'; -+ desc.dtargd_mapping = desc.dtargd_ndx; -+ -+ prov->dtpv_pops.dtps_getargdesc( -+ prov->dtpv_arg, probe->dtpr_id, -+ probe->dtpr_arg, &desc); -+ } -+ -+ mutex_unlock(&dtrace_provider_lock); -+ mutex_unlock(&module_mutex); -+ -+ if (copy_to_user(argp, &desc, sizeof(desc)) != 0) -+ return -EFAULT; -+ -+ return 0; -+ } -+ -+ case DTRACEIOC_GO: { -+ processorid_t cpuid; -+ -+ dt_dbg_ioctl("IOCTL GO (cmd %#x), argp %p\n", cmd, argp); -+ -+ rval = dtrace_state_go(state, &cpuid); -+ -+ if (rval != 0) -+ return rval; -+ -+ if (copy_to_user(argp, &cpuid, sizeof(cpuid)) != 0) -+ return -EFAULT; -+ -+ return 0; -+ } -+ -+ case DTRACEIOC_STOP: { -+ processorid_t cpuid; -+ -+ dt_dbg_ioctl("IOCTL STOP (cmd %#x), argp %p\n", cmd, argp); -+ -+ mutex_lock(&dtrace_lock); -+ rval = dtrace_state_stop(state, &cpuid); -+ mutex_unlock(&dtrace_lock); -+ -+ if (rval != 0) -+ return rval; -+ -+ if (copy_to_user(argp, &cpuid, sizeof(cpuid)) != 0) -+ return -EFAULT; -+ -+ return 0; -+ } -+ -+ case DTRACEIOC_DOFGET: { -+ struct dof_hdr hdr, *dof; -+ uint64_t len; -+ -+ dt_dbg_ioctl("IOCTL DOFGET (cmd %#x), argp %p\n", cmd, argp); -+ -+ if (copy_from_user(&hdr, argp, sizeof(hdr)) != 0) -+ return -EFAULT; -+ -+ mutex_lock(&dtrace_lock); -+ dof = dtrace_dof_create(state); -+ mutex_unlock(&dtrace_lock); -+ if (dof == NULL) -+ return -ENOMEM; -+ -+ len = min(hdr.dofh_loadsz, dof->dofh_loadsz); -+ rval = copy_to_user(argp, dof, len); -+ dtrace_dof_destroy(dof); -+ -+ return rval == 0 ? 0 : -EFAULT; -+ } -+ -+ case DTRACEIOC_AGGSNAP: -+ case DTRACEIOC_BUFSNAP: { -+ struct dtrace_bufdesc desc; -+ caddr_t cached; -+ struct dtrace_buffer *buf; -+ -+ dt_dbg_ioctl("IOCTL %s (cmd %#x), argp %p\n", -+ cmd == DTRACEIOC_AGGSNAP ? "AGGSNAP" -+ : "BUFSNAP", -+ cmd, argp); -+ -+ if (copy_from_user(&desc, argp, sizeof(desc)) != 0) -+ return -EFAULT; -+ -+ if (desc.dtbd_cpu < 0 || desc.dtbd_cpu >= NR_CPUS) -+ return -EINVAL; -+ -+ mutex_lock(&dtrace_lock); -+ -+ if (cmd == DTRACEIOC_BUFSNAP) -+ buf = &state->dts_buffer[desc.dtbd_cpu]; -+ else -+ buf = &state->dts_aggbuffer[desc.dtbd_cpu]; -+ -+ if (buf->dtb_flags & (DTRACEBUF_RING | DTRACEBUF_FILL)) { -+ size_t sz = buf->dtb_offset; -+ -+ if (state->dts_activity != DTRACE_ACTIVITY_STOPPED) { -+ mutex_unlock(&dtrace_lock); -+ return -EBUSY; -+ } -+ -+ /* -+ * If this buffer has already been consumed, we're -+ * going to indicate that there's nothing left here -+ * to consume. -+ */ -+ if (buf->dtb_flags & DTRACEBUF_CONSUMED) { -+ mutex_unlock(&dtrace_lock); -+ -+ desc.dtbd_size = 0; -+ desc.dtbd_drops = 0; -+ desc.dtbd_errors = 0; -+ desc.dtbd_oldest = 0; -+ sz = sizeof(desc); -+ -+ if (copy_to_user(argp, &desc, sz) != 0) -+ return -EFAULT; -+ -+ return 0; -+ } -+ -+ /* -+ * If this is a ring buffer that has wrapped, we want -+ * to copy the whole thing out. -+ */ -+ if (buf->dtb_flags & DTRACEBUF_WRAPPED) { -+ dtrace_buffer_polish(buf); -+ sz = buf->dtb_size; -+ } -+ -+ if (copy_to_user(desc.dtbd_data, buf->dtb_tomax, -+ sz) != 0) { -+ mutex_unlock(&dtrace_lock); -+ return -EFAULT; -+ } -+ -+ desc.dtbd_size = sz; -+ desc.dtbd_drops = buf->dtb_drops; -+ desc.dtbd_errors = buf->dtb_errors; -+ desc.dtbd_oldest = buf->dtb_xamot_offset; -+ -+ mutex_unlock(&dtrace_lock); -+ -+ if (copy_to_user(argp, &desc, sizeof(desc)) != 0) -+ return -EFAULT; -+ -+ buf->dtb_flags |= DTRACEBUF_CONSUMED; -+ -+ return 0; -+ } -+ -+ if (buf->dtb_tomax == NULL) { -+ ASSERT(buf->dtb_xamot == NULL); -+ mutex_unlock(&dtrace_lock); -+ return -ENOENT; -+ } -+ -+ cached = buf->dtb_tomax; -+ -+ dtrace_xcall(desc.dtbd_cpu, -+ (dtrace_xcall_t)dtrace_buffer_switch, buf); -+ -+ state->dts_errors += buf->dtb_xamot_errors; -+ -+ /* -+ * If the buffers did not actually switch, then the cross call -+ * did not take place -- presumably because the given CPU is -+ * not in the ready set. If this is the case, we'll return -+ * ENOENT. -+ */ -+ if (buf->dtb_tomax == cached) { -+ ASSERT(buf->dtb_xamot != cached); -+ mutex_unlock(&dtrace_lock); -+ return -ENOENT; -+ } -+ -+ ASSERT(cached == buf->dtb_xamot); -+ -+ /* -+ * We have our snapshot; now copy it out. -+ */ -+ if (copy_to_user(desc.dtbd_data, buf->dtb_xamot, -+ buf->dtb_xamot_offset) != 0) { -+ mutex_unlock(&dtrace_lock); -+ return -EFAULT; -+ } -+ -+ desc.dtbd_size = buf->dtb_xamot_offset; -+ desc.dtbd_drops = buf->dtb_xamot_drops; -+ desc.dtbd_errors = buf->dtb_xamot_errors; -+ desc.dtbd_oldest = 0; -+ -+ mutex_unlock(&dtrace_lock); -+ -+ /* -+ * Finally, copy out the buffer description. -+ */ -+ if (copy_to_user(argp, &desc, sizeof(desc)) != 0) -+ return -EFAULT; -+ -+ return 0; -+ } -+ -+ case DTRACEIOC_CONF: { -+ struct dtrace_conf conf; -+ -+ dt_dbg_ioctl("IOCTL CONF (cmd %#x), argp %p\n", cmd, argp); -+ -+ memset(&conf, 0, sizeof(conf)); -+ conf.dtc_difversion = DIF_VERSION; -+ conf.dtc_difintregs = DIF_DIR_NREGS; -+ conf.dtc_diftupregs = DIF_DTR_NREGS; -+ conf.dtc_ctfmodel = CTF_MODEL_NATIVE; -+ conf.dtc_maxbufs = nr_cpu_ids; -+ -+ if (copy_to_user(argp, &conf, sizeof(conf)) != 0) -+ return -EFAULT; -+ -+ return 0; -+ } -+ -+ case DTRACEIOC_STATUS: { -+ struct dtrace_status stat; -+ struct dtrace_dstate *dstate; -+ int i, j; -+ uint64_t nerrs; -+ -+ dt_dbg_ioctl("IOCTL STATUS (cmd %#x), argp %p\n", cmd, argp); -+ -+ /* -+ * See the comment in dtrace_state_deadman() for the reason -+ * for setting dts_laststatus to UINT64_MAX before setting -+ * it to the correct value. -+ */ -+ state->dts_laststatus = ns_to_ktime(UINT64_MAX); -+ dtrace_membar_producer(); -+ state->dts_laststatus = dtrace_gethrtime(); -+ -+ memset(&stat, 0, sizeof(stat)); -+ -+ mutex_lock(&dtrace_lock); -+ -+ if (state->dts_activity == DTRACE_ACTIVITY_INACTIVE) { -+ mutex_unlock(&dtrace_lock); -+ return -ENOENT; -+ } -+ -+ if (state->dts_activity == DTRACE_ACTIVITY_DRAINING) -+ stat.dtst_exiting = 1; -+ -+ nerrs = state->dts_errors; -+ dstate = &state->dts_vstate.dtvs_dynvars; -+ -+ for (i = 0; i < NR_CPUS; i++) { -+ struct dtrace_dstate_percpu *dcpu; -+ -+ dcpu = &dstate->dtds_percpu[i]; -+ stat.dtst_dyndrops += dcpu->dtdsc_drops; -+ stat.dtst_dyndrops_dirty += dcpu->dtdsc_dirty_drops; -+ stat.dtst_dyndrops_rinsing += dcpu->dtdsc_rinsing_drops; -+ -+ if (state->dts_buffer[i].dtb_flags & DTRACEBUF_FULL) -+ stat.dtst_filled++; -+ -+ nerrs += state->dts_buffer[i].dtb_errors; -+ -+ for (j = 0; j < state->dts_nspeculations; j++) { -+ struct dtrace_speculation *spec; -+ struct dtrace_buffer *buf; -+ -+ spec = &state->dts_speculations[j]; -+ buf = &spec->dtsp_buffer[i]; -+ stat.dtst_specdrops += buf->dtb_xamot_drops; -+ } -+ } -+ -+ stat.dtst_specdrops_busy = state->dts_speculations_busy; -+ stat.dtst_specdrops_unavail = state->dts_speculations_unavail; -+ stat.dtst_stkstroverflows = state->dts_stkstroverflows; -+ stat.dtst_dblerrors = state->dts_dblerrors; -+ stat.dtst_killed = (state->dts_activity == -+ DTRACE_ACTIVITY_KILLED); -+ stat.dtst_errors = nerrs; -+ -+ mutex_unlock(&dtrace_lock); -+ -+ if (copy_to_user(argp, &stat, sizeof(stat)) != 0) -+ return -EFAULT; -+ -+ return 0; -+ } -+ -+ case DTRACEIOC_FORMAT: { -+ struct dtrace_fmtdesc fmt; -+ char *str; -+ int len; -+ -+ dt_dbg_ioctl("IOCTL FORMAT (cmd %#x), argp %p\n", cmd, argp); -+ -+ if (copy_from_user(&fmt, argp, sizeof(fmt)) != 0) -+ return -EFAULT; -+ -+ mutex_lock(&dtrace_lock); -+ -+ if (fmt.dtfd_format == 0 || -+ fmt.dtfd_format > state->dts_nformats) { -+ mutex_unlock(&dtrace_lock); -+ return -EINVAL; -+ } -+ -+ /* -+ * Format strings are allocated contiguously and they are -+ * never freed; if a format index is less than the number -+ * of formats, we can assert that the format map is non-NULL -+ * and that the format for the specified index is non-NULL. -+ */ -+ ASSERT(state->dts_formats != NULL); -+ str = state->dts_formats[fmt.dtfd_format - 1]; -+ ASSERT(str != NULL); -+ -+ len = strlen(str) + 1; -+ -+ if (len > fmt.dtfd_length) { -+ fmt.dtfd_length = len; -+ -+ if (copy_to_user(argp, &fmt, sizeof(fmt)) != 0) { -+ mutex_unlock(&dtrace_lock); -+ return -EINVAL; -+ } -+ } else { -+ if (copy_to_user(fmt.dtfd_string, str, len) != 0) { -+ mutex_unlock(&dtrace_lock); -+ return -EINVAL; -+ } -+ } -+ -+ mutex_unlock(&dtrace_lock); -+ -+ return 0; -+ } -+ -+ default: -+ dt_dbg_ioctl("IOCTL ??? (cmd %#x), argp %p\n", -+ cmd, argp); -+ break; -+ } -+ -+ return -ENOTTY; -+} -+ -+static int dtrace_close(struct inode *inode, struct file *file) -+{ -+ struct dtrace_state *state = file->private_data; -+ -+ mutex_lock(&cpu_lock); -+ mutex_lock(&dtrace_lock); -+ -+ /* -+ * If there is anonymous state, destroy that first. -+ */ -+ if (state->dts_anon) { -+ ASSERT(dtrace_anon.dta_state == NULL); -+ dtrace_state_destroy(state->dts_anon); -+ } -+ -+ dtrace_state_destroy(state); -+ ASSERT(dtrace_opens > 0); -+ -+ if (--dtrace_opens == 0 && dtrace_anon.dta_enabling == NULL) -+ dtrace_disable(); -+ -+ mutex_unlock(&dtrace_lock); -+ mutex_unlock(&cpu_lock); -+ -+ return 0; -+} -+ -+static int dtrace_helper_open(struct inode *inode, struct file *file) -+{ -+ return 0; -+} -+ -+static long dtrace_helper_ioctl(struct file *file, -+ unsigned int cmd, unsigned long arg) -+{ -+ int rval; -+ struct dof_helper help, *dhp = NULL; -+ void __user *argp = (void __user *)arg; -+ -+ switch (cmd) { -+ case DTRACEHIOC_ADDDOF: -+ dt_dbg_ioctl("Helper IOCTL ADDDOF (cmd %#x), argp %p\n", -+ cmd, argp); -+ -+ if (copy_from_user(&help, argp, sizeof(help)) != 0) { -+ dtrace_dof_error(NULL, "failed to copy DOF helper"); -+ return -EFAULT; -+ } -+ -+ dhp = &help; -+ argp = (void __user *)help.dofhp_dof; -+ -+ /* fallthrough */ -+ -+ case DTRACEHIOC_ADD: { -+ struct dof_hdr *dof = dtrace_dof_copyin(argp, &rval); -+ -+ if (dof == NULL) -+ return rval; -+ -+ if (cmd == DTRACEHIOC_ADD) -+ dt_dbg_ioctl("Helper IOCTL ADD (cmd %#x), argp %p\n", -+ cmd, argp); -+ -+ mutex_lock(&dtrace_lock); -+ -+ /* -+ * The dtrace_helper_slurp() routine takes responsibility for -+ * the dof -- it may free it now, or it may save it and free it -+ * later. -+ */ -+ rval = dtrace_helper_slurp(dof, dhp); -+ if (rval == -1) -+ rval = -EINVAL; -+ -+ mutex_unlock(&dtrace_lock); -+ -+ dt_dbg_ioctl("Helper IOCTL %s returning %d\n", -+ cmd == DTRACEHIOC_ADD ? "ADD" -+ : "ADDDOF", -+ rval); -+ -+ return rval; -+ } -+ -+ case DTRACEHIOC_REMOVE: -+ dt_dbg_ioctl("Helper IOCTL REMOVE (cmd %#x), argp %p\n", -+ cmd, argp); -+ -+ mutex_lock(&dtrace_lock); -+ -+ rval = dtrace_helper_destroygen((uintptr_t)argp); -+ -+ mutex_unlock(&dtrace_lock); -+ -+ dt_dbg_ioctl("Helper IOCTL REMOVE returning %d\n", rval); -+ -+ return rval; -+ default: -+ dt_dbg_ioctl("Helper IOCTL ??? (cmd %#x), argp %p\n", -+ cmd, argp); -+ break; -+ } -+ -+ return -ENOTTY; -+} -+ -+static int dtrace_helper_close(struct inode *inode, struct file *file) -+{ -+ return 0; -+} -+ -+static const struct file_operations dtrace_fops = { -+ .owner = THIS_MODULE, -+ .unlocked_ioctl = dtrace_ioctl, -+ .open = dtrace_open, -+ .release = dtrace_close, -+}; -+ -+static const struct file_operations helper_fops = { -+ .owner = THIS_MODULE, -+ .unlocked_ioctl = dtrace_helper_ioctl, -+ .compat_ioctl = dtrace_helper_ioctl, -+ .open = dtrace_helper_open, -+ .release = dtrace_helper_close, -+}; -+ -+static struct miscdevice dtrace_dev = { -+ .minor = DT_DEV_DTRACE_MINOR, -+ .name = "dtrace", -+ .nodename = "dtrace/dtrace", -+ .fops = &dtrace_fops, -+}; -+ -+static struct miscdevice helper_dev = { -+ .minor = DT_DEV_HELPER_MINOR, -+ .name = "helper", -+ .nodename = "dtrace/helper", -+ .fops = &helper_fops, -+}; -+ -+static void dtrace_module_loaded(struct module *mp) -+{ -+ struct dtrace_provider *prv; -+ -+ mutex_lock(&module_mutex); -+ mutex_lock(&dtrace_provider_lock); -+ -+ /* -+ * Give all providers a chance to register probes for this module. -+ */ -+ for (prv = dtrace_provider; prv != NULL; prv = prv->dtpv_next) -+ prv->dtpv_pops.dtps_provide_module(prv->dtpv_arg, mp); -+ -+ mutex_unlock(&dtrace_provider_lock); -+ mutex_unlock(&module_mutex); -+ -+ /* -+ * If we have any retained enablings, we need to match against them. -+ */ -+ mutex_lock(&dtrace_lock); -+ -+ if (dtrace_retained == NULL) { -+ mutex_unlock(&dtrace_lock); -+ return; -+ } -+ -+ mutex_unlock(&dtrace_lock); -+ dtrace_enabling_matchall(); -+} -+ -+static void dtrace_module_unloaded(struct module *mp) -+{ -+ struct dtrace_probe template, *probe, *first, *next; -+ struct dtrace_provider *prv; -+ -+ template.dtpr_mod = mp->name; -+ -+ mutex_lock(&module_mutex); -+ mutex_lock(&dtrace_provider_lock); -+ mutex_lock(&dtrace_lock); -+ -+ if (dtrace_bymod == NULL) { -+ /* -+ * The DTrace module is loaded (obviously) but not attached; -+ * we don't have any work to do. -+ */ -+ mutex_unlock(&dtrace_lock); -+ mutex_unlock(&dtrace_provider_lock); -+ mutex_unlock(&module_mutex); -+ return; -+ } -+ -+ for (probe = first = dtrace_hash_lookup(dtrace_bymod, &template); -+ probe != NULL; probe = probe->dtpr_nextmod) { -+ if (probe->dtpr_ecb != NULL) { -+ mutex_unlock(&dtrace_lock); -+ mutex_unlock(&dtrace_provider_lock); -+ mutex_unlock(&module_mutex); -+ -+ /* -+ * This shouldn't _actually_ be possible -- we're -+ * unloading a module that has an enabled probe in it. -+ * (It's normally up to the provider to make sure that -+ * this can't happen.) However, because dtps_enable() -+ * doesn't have a failure mode, there can be an -+ * enable/unload race. Upshot: we don't want to -+ * assert, but we're not going to disable the -+ * probe, either. -+ */ -+ if (dtrace_err_verbose) { -+ pr_warn("unloaded module '%s' " -+ "had enabled probes", mp->name); -+ } -+ -+ return; -+ } -+ } -+ -+ probe = first; -+ -+ for (first = NULL; probe != NULL; probe = next) { -+ dtrace_probe_remove_id(probe->dtpr_id); -+ -+ next = probe->dtpr_nextmod; -+ dtrace_hash_remove(dtrace_bymod, probe); -+ dtrace_hash_remove(dtrace_byfunc, probe); -+ dtrace_hash_remove(dtrace_byname, probe); -+ -+ if (first == NULL) { -+ first = probe; -+ probe->dtpr_nextmod = NULL; -+ } else { -+ probe->dtpr_nextmod = first; -+ first = probe; -+ } -+ } -+ -+ /* -+ * We've removed all of the module's probes from the hash chains and -+ * from the probe array. Now issue a dtrace_sync() to be sure that -+ * everyone has cleared out from any probe array processing. -+ */ -+ dtrace_sync(); -+ -+ for (probe = first; probe != NULL; probe = first) { -+ first = probe->dtpr_nextmod; -+ prv = probe->dtpr_provider; -+ prv->dtpv_pops.dtps_destroy(prv->dtpv_arg, probe->dtpr_id, -+ probe->dtpr_arg); -+ kfree(probe->dtpr_mod); -+ kfree(probe->dtpr_func); -+ kfree(probe->dtpr_name); -+ kfree(probe); -+ } -+ -+ /* -+ * Notify providers to cleanup per-module data for this module. -+ */ -+ for (prv = dtrace_provider; prv != NULL; prv = prv->dtpv_next) -+ if (prv->dtpv_pops.dtps_destroy_module != NULL) -+ prv->dtpv_pops.dtps_destroy_module(prv->dtpv_arg, mp); -+ -+ mutex_unlock(&dtrace_lock); -+ mutex_unlock(&dtrace_provider_lock); -+ mutex_unlock(&module_mutex); -+} -+ -+/* -+ * Register a toxic range. -+ */ -+static void dtrace_toxrange_add(uintptr_t base, uintptr_t limit) -+{ -+ if (dtrace_toxranges >= dtrace_toxranges_max) { -+ int osize, nsize; -+ struct dtrace_toxrange *range; -+ -+ osize = dtrace_toxranges_max * sizeof(struct dtrace_toxrange); -+ -+ if (osize == 0) { -+ ASSERT(dtrace_toxrange == NULL); -+ ASSERT(dtrace_toxranges_max == 0); -+ -+ dtrace_toxranges_max = 1; -+ } else -+ dtrace_toxranges_max <<= 1; -+ -+ nsize = dtrace_toxranges_max * sizeof(struct dtrace_toxrange); -+ range = vzalloc(nsize); -+ if (range == NULL) { -+ pr_warn("Failed to add toxic range: out of memory\n"); -+ return; -+ } -+ -+ if (dtrace_toxrange != NULL) { -+ ASSERT(osize != 0); -+ -+ memcpy(range, dtrace_toxrange, osize); -+ vfree(dtrace_toxrange); -+ } -+ -+ dtrace_toxrange = range; -+ } -+ -+ ASSERT(dtrace_toxrange[dtrace_toxranges].dtt_base == (uintptr_t)NULL); -+ ASSERT(dtrace_toxrange[dtrace_toxranges].dtt_limit == (uintptr_t)NULL); -+ -+ dtrace_toxrange[dtrace_toxranges].dtt_base = base; -+ dtrace_toxrange[dtrace_toxranges].dtt_limit = limit; -+ dtrace_toxranges++; -+} -+ -+/* -+ * Check if an address falls within a toxic region. -+ */ -+int dtrace_istoxic(uintptr_t kaddr, size_t size) -+{ -+ uintptr_t taddr, tsize; -+ int i; -+ -+ for (i = 0; i < dtrace_toxranges; i++) { -+ taddr = dtrace_toxrange[i].dtt_base; -+ tsize = dtrace_toxrange[i].dtt_limit - taddr; -+ -+ if (kaddr - taddr < tsize) { -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); -+ this_cpu_core->cpuc_dtrace_illval = kaddr; -+ return 1; -+ } -+ -+ if (taddr - kaddr < size) { -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); -+ this_cpu_core->cpuc_dtrace_illval = kaddr; -+ return 1; -+ } -+ } -+ -+ return 0; -+} -+ -+static int dtrace_mod_notifier(struct notifier_block *nb, unsigned long val, -+ void *args) -+{ -+ struct module *mp = args; -+ -+ if (!mp) -+ return NOTIFY_DONE; -+ -+ switch (val) { -+ case MODULE_STATE_LIVE: -+ dtrace_module_loaded(mp); -+ break; -+ -+ case MODULE_STATE_GOING: -+ dtrace_module_unloaded(mp); -+ break; -+ } -+ -+ return NOTIFY_DONE; -+} -+ -+static struct notifier_block dtrace_modmgmt = { -+ .notifier_call = dtrace_mod_notifier, -+}; -+ -+/* -+ * Initialize the DTrace core. -+ * -+ * Equivalent to: dtrace_attach() -+ */ -+int dtrace_dev_init(void) -+{ -+ dtrace_provider_id_t id; -+ int rc = 0; -+ struct cred *cred; -+ -+ /* -+ * Register the device for the DTrace core. -+ */ -+ rc = misc_register(&dtrace_dev); -+ if (rc) { -+ pr_err("%s: Can't register misc device %d\n", -+ dtrace_dev.name, dtrace_dev.minor); -+ -+ return rc; -+ } -+ -+ /* -+ * Register the device for the DTrace helper. -+ */ -+ rc = misc_register(&helper_dev); -+ if (rc) { -+ pr_err("%s: Can't register misc device %d\n", -+ helper_dev.name, helper_dev.minor); -+ -+ misc_deregister(&dtrace_dev); -+ return rc; -+ } -+ -+ mutex_lock(&cpu_lock); -+ mutex_lock(&module_mutex); -+ mutex_lock(&dtrace_provider_lock); -+ mutex_lock(&dtrace_lock); -+ -+ rc = dtrace_probe_init(); -+ if (rc) { -+ pr_err("Failed to initialize DTrace core\n"); -+ -+ goto errout; -+ } -+ -+#if IS_ENABLED(CONFIG_DT_FASTTRAP) -+ dtrace_helpers_cleanup = dtrace_helpers_destroy; -+ dtrace_helpers_fork = dtrace_helpers_duplicate; -+#endif -+#ifdef FIXME -+ dtrace_cpu_init = dtrace_cpu_setup_initial; -+ dtrace_cpustart_init = dtrace_suspend; -+ dtrace_cpustart_fini = dtrace_resume; -+ dtrace_debugger_init = dtrace_suspend; -+ dtrace_debugger_fini = dtrace_resume; -+ -+ register_cpu_setup_func((cpu_setup_func_t *)dtrace_cpu_setup, NULL); -+#endif -+ -+#ifdef FIXME -+ dtrace_taskq = taskq_create("dtrace_taskq", 1, maxclsyspri, 1, INT_MAX, -+ 0); -+#endif -+ -+ dtrace_state_cachep = kmem_cache_create("dtrace_state_cache", -+ sizeof(struct dtrace_dstate_percpu) * NR_CPUS, -+ 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); -+ -+ /* From now on the failures are results of failed allocations. */ -+ rc = -ENOMEM; -+ -+ /* -+ * Create the probe hashtables. -+ */ -+ dtrace_bymod = dtrace_hash_create( -+ offsetof(struct dtrace_probe, dtpr_mod), -+ offsetof(struct dtrace_probe, dtpr_nextmod), -+ offsetof(struct dtrace_probe, dtpr_prevmod)); -+ if (dtrace_bymod == NULL) -+ goto errout; -+ -+ dtrace_byfunc = dtrace_hash_create( -+ offsetof(struct dtrace_probe, dtpr_func), -+ offsetof(struct dtrace_probe, dtpr_nextfunc), -+ offsetof(struct dtrace_probe, dtpr_prevfunc)); -+ if (dtrace_byfunc == NULL) -+ goto errout; -+ -+ dtrace_byname = dtrace_hash_create( -+ offsetof(struct dtrace_probe, dtpr_name), -+ offsetof(struct dtrace_probe, dtpr_nextname), -+ offsetof(struct dtrace_probe, dtpr_prevname)); -+ if (dtrace_byname == NULL) -+ goto errout; -+ -+ /* -+ * Initialize cred. -+ */ -+ cred = prepare_kernel_cred(NULL); -+ if (cred == NULL) -+ goto errout; -+ -+ init_user_namespace = cred->user_ns; -+ put_cred(cred); -+ -+ /* -+ * Ensure that the X configuration parameter has a legal value. -+ */ -+ if (dtrace_retain_max < 1) { -+ pr_warn("Illegal value (%lu) for dtrace_retain_max; " -+ "setting to 1", (unsigned long)dtrace_retain_max); -+ -+ dtrace_retain_max = 1; -+ } -+ -+ /* -+ * Discover our toxic ranges. -+ */ -+ dtrace_toxic_ranges(dtrace_toxrange_add); -+ -+ /* -+ * Register ourselves as a provider. -+ */ -+ dtrace_register("dtrace", &dtrace_provider_attr, DTRACE_PRIV_NONE, 0, -+ &dtrace_provider_ops, NULL, &id); -+ -+ ASSERT(dtrace_provider != NULL); -+ ASSERT((dtrace_provider_id_t)dtrace_provider == id); -+ -+ /* -+ * Create BEGIN, END, and ERROR probes. -+ */ -+ dtrace_probeid_begin = dtrace_probe_create( -+ (dtrace_provider_id_t)dtrace_provider, NULL, -+ NULL, "BEGIN", 0, NULL); -+ if (dtrace_probeid_begin == DTRACE_IDNONE) -+ goto errout; -+ -+ dtrace_probeid_end = dtrace_probe_create( -+ (dtrace_provider_id_t)dtrace_provider, NULL, -+ NULL, "END", 0, NULL); -+ if (dtrace_probeid_end == DTRACE_IDNONE) -+ goto errout; -+ -+ dtrace_probeid_error = dtrace_probe_create( -+ (dtrace_provider_id_t)dtrace_provider, NULL, -+ NULL, "ERROR", 1, NULL); -+ if (dtrace_probeid_error == DTRACE_IDNONE) -+ goto errout; -+ -+ dtrace_anon_property(); -+ -+ /* -+ * If DTrace helper tracing is enabled, we need to allocate a trace -+ * buffer. -+ */ -+ if (dtrace_helptrace_enabled) { -+ ASSERT(dtrace_helptrace_buffer == NULL); -+ -+ dtrace_helptrace_buffer = vzalloc(dtrace_helptrace_bufsize); -+ -+ if (dtrace_helptrace_buffer == NULL) { -+ pr_warn("Cannot allocate helptrace buffer; " -+ "disabling dtrace_helptrace\n"); -+ dtrace_helptrace_enabled = 0; -+ } -+ } -+ -+#ifdef FIXME -+ /* -+ * There is usually code here to handle the case where there already -+ * are providers when we get to this code. On Linux, that does not -+ * seem to be possible since the DTrace core module (this code) is -+ * loaded as a dependency for each provider, and thus this -+ * initialization code is executed prior to the initialization code of -+ * the first provider causing the core to be loaded. -+ */ -+#endif -+ -+ if (register_module_notifier(&dtrace_modmgmt)) -+ goto errout; -+ -+ mutex_unlock(&dtrace_lock); -+ mutex_unlock(&dtrace_provider_lock); -+ mutex_unlock(&module_mutex); -+ mutex_unlock(&cpu_lock); -+ -+ return 0; -+ -+errout: -+ if (dtrace_provider != NULL) -+ (void) dtrace_unregister((dtrace_provider_id_t)dtrace_provider); -+ -+ dtrace_hash_destroy(dtrace_bymod); -+ dtrace_hash_destroy(dtrace_byfunc); -+ dtrace_hash_destroy(dtrace_byname); -+ -+ misc_deregister(&helper_dev); -+ misc_deregister(&dtrace_dev); -+ -+ mutex_unlock(&dtrace_lock); -+ mutex_unlock(&dtrace_provider_lock); -+ mutex_unlock(&module_mutex); -+ mutex_unlock(&cpu_lock); -+ -+ return rc; -+} -+ -+void dtrace_dev_exit(void) -+{ -+ mutex_lock(&cpu_lock); -+ mutex_lock(&module_mutex); -+ mutex_lock(&dtrace_provider_lock); -+ mutex_lock(&dtrace_lock); -+ -+ dtrace_unregister((dtrace_provider_id_t)dtrace_provider); -+ dtrace_provider = NULL; -+ -+ dtrace_probe_exit(); -+ -+ unregister_module_notifier(&dtrace_modmgmt); -+ -+#if IS_ENABLED(CONFIG_DT_FASTTRAP) -+ dtrace_helpers_cleanup = NULL; -+ dtrace_helpers_fork = NULL; -+#endif -+#ifdef FIXME -+ dtrace_cpu_init = NULL; -+ dtrace_cpustart_init = NULL; -+ dtrace_cpustart_fini = NULL; -+ dtrace_debugger_init = NULL; -+ dtrace_debugger_fini = NULL; -+ -+ unregister_cpu_setup_func((cpu_setup_func_t *)dtrace_cpu_setup, NULL); -+#endif -+ -+ mutex_unlock(&cpu_lock); -+ -+ dtrace_hash_destroy(dtrace_bymod); -+ dtrace_hash_destroy(dtrace_byfunc); -+ dtrace_hash_destroy(dtrace_byname); -+ dtrace_bymod = NULL; -+ dtrace_byfunc = NULL; -+ dtrace_byname = NULL; -+ -+ /* -+ * If DTrace helper tracing is enabled, we need to free the trace -+ * buffer. -+ */ -+ if (dtrace_helptrace_enabled || dtrace_helptrace_buffer) -+ vfree(dtrace_helptrace_buffer); -+ -+ kmem_cache_destroy(dtrace_state_cachep); -+ -+ mutex_unlock(&dtrace_lock); -+ mutex_unlock(&dtrace_provider_lock); -+ mutex_unlock(&module_mutex); -+ -+ misc_deregister(&helper_dev); -+ misc_deregister(&dtrace_dev); -+} -diff --git a/dtrace/dtrace_dev.h b/dtrace/dtrace_dev.h -new file mode 100644 -index 0000000000000000000000000000000000000000..11ae2deb17a15ac27c95b021f95455417b3c15e4 ---- /dev/null -+++ b/dtrace/dtrace_dev.h -@@ -0,0 +1,35 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Dynamic Tracing for Linux -+ * -+ * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#ifndef _DTRACE_DEV_H_ -+#define _DTRACE_DEV_H_ -+ -+#define DT_DEV_DTRACE_MINOR (16) -+#define DT_DEV_HELPER_MINOR (DT_DEV_DTRACE_MINOR + 1) -+#define DT_DEV_PROFILE_MINOR (DT_DEV_HELPER_MINOR + 1) -+#define DT_DEV_SYSTRACE_MINOR (DT_DEV_PROFILE_MINOR + 1) -+#define DT_DEV_FBT_MINOR (DT_DEV_SYSTRACE_MINOR + 1) -+#define DT_DEV_SDT_MINOR (DT_DEV_FBT_MINOR + 1) -+#define DT_DEV_FASTTRAP_MINOR (DT_DEV_SDT_MINOR + 1) -+#define DT_DEV_LOCKSTAT_MINOR (DT_DEV_FASTTRAP_MINOR + 1) -+#define DT_DEV_DT_TEST_MINOR (DT_DEV_LOCKSTAT_MINOR + 1) -+#define DT_DEV_DT_PERF_MINOR (DT_DEV_DT_TEST_MINOR + 1) -+ -+extern int dtrace_dev_init(void); -+extern void dtrace_dev_exit(void); -+ -+#endif /* _DTRACE_DEV_H_ */ -diff --git a/dtrace/dtrace_dif.c b/dtrace/dtrace_dif.c -new file mode 100644 -index 0000000000000000000000000000000000000000..ae7f01b4ed9b76ea957dbfe080e1ac8fda995329 ---- /dev/null -+++ b/dtrace/dtrace_dif.c -@@ -0,0 +1,4905 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_dif.c -+ * DESCRIPTION: DTrace - DIF object implementation -+ * -+ * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/dtrace_cpu.h> -+#include <linux/dtrace_task_impl.h> -+#include <linux/fdtable.h> -+#include <linux/hardirq.h> -+#include <linux/if_arp.h> -+#include <linux/if_ether.h> -+#include <linux/if_infiniband.h> -+#include <linux/in6.h> -+#include <linux/inet.h> -+#include <linux/kdev_t.h> -+#include <linux/slab.h> -+#include <linux/socket.h> -+#include <linux/vmalloc.h> -+#include <net/ipv6.h> -+#include <asm/byteorder.h> -+ -+#include <linux/mount.h> -+ -+#include "dtrace.h" -+ -+size_t dtrace_global_maxsize = 16 * 1024; -+ -+/* -+ * This externally visible variable (accessible through the backtick (`) -+ * syntax is provided as a source of well-known, zero-filled memory. Some -+ * translators use this in their implementation. -+ */ -+const char dtrace_zero[256] = { 0, }; -+ -+uint64_t dtrace_vtime_references; -+ -+static const char hexdigits[] = "0123456789abcdef"; -+ -+static int dtrace_difo_err(uint_t pc, const char *format, ...) -+{ -+ char buf[256]; -+ -+ if (dtrace_err_verbose) { -+ va_list alist; -+ size_t len = strlen(format); -+ -+ pr_err("dtrace DIF object error: [%u]: ", pc); -+ -+ if (len >= 256 - sizeof(KERN_ERR)) { -+ pr_err("<invalid format string>"); -+ return 1; -+ } -+ -+ memcpy(buf, KERN_ERR, sizeof(KERN_ERR)); -+ memcpy(buf + sizeof(KERN_ERR), format, len); -+ -+ va_start(alist, format); -+ vprintk(buf, alist); -+ va_end(alist); -+ } -+ -+ return 1; -+} -+ -+/* -+ * Validate a DTrace DIF object by checking the IR instructions. The following -+ * rules are currently enforced by dtrace_difo_validate(): -+ * -+ * 1. Each instruction must have a valid opcode -+ * 2. Each register, string, variable, or subroutine reference must be valid -+ * 3. No instruction can modify register %r0 (must be zero) -+ * 4. All instruction reserved bits must be set to zero -+ * 5. The last instruction must be a "ret" instruction -+ * 6. All branch targets must reference a valid instruction _after_ the branch -+ */ -+int dtrace_difo_validate(struct dtrace_difo *dp, struct dtrace_vstate *vstate, -+ uint_t nregs, const struct cred *cr) -+{ -+ int err = 0, i; -+ int (*efunc)(uint_t pc, const char *, ...) = dtrace_difo_err; -+ int kcheckload = 0; -+ uint_t pc; -+ -+ kcheckload = cr == NULL || -+ (vstate->dtvs_state->dts_cred.dcr_visible & -+ DTRACE_CRV_KERNEL) == 0; -+ -+ dp->dtdo_destructive = 0; -+ -+ for (pc = 0; pc < dp->dtdo_len && err == 0; pc++) { -+ dif_instr_t instr = dp->dtdo_buf[pc]; -+ uint_t r1 = DIF_INSTR_R1(instr); -+ uint_t r2 = DIF_INSTR_R2(instr); -+ uint_t rd = DIF_INSTR_RD(instr); -+ uint_t rs = DIF_INSTR_RS(instr); -+ uint_t label = DIF_INSTR_LABEL(instr); -+ uint_t v = DIF_INSTR_VAR(instr); -+ uint_t subr = DIF_INSTR_SUBR(instr); -+ uint_t diftype = DIF_INSTR_TYPE(instr); -+ uint_t op = DIF_INSTR_OP(instr); -+ -+ switch (op) { -+ case DIF_OP_OR: -+ case DIF_OP_XOR: -+ case DIF_OP_AND: -+ case DIF_OP_SLL: -+ case DIF_OP_SRL: -+ case DIF_OP_SRA: -+ case DIF_OP_SUB: -+ case DIF_OP_ADD: -+ case DIF_OP_MUL: -+ case DIF_OP_SDIV: -+ case DIF_OP_UDIV: -+ case DIF_OP_SREM: -+ case DIF_OP_UREM: -+ case DIF_OP_COPYS: -+ if (r1 >= nregs) -+ err += efunc(pc, "invalid register %u\n", r1); -+ if (r2 >= nregs) -+ err += efunc(pc, "invalid register %u\n", r2); -+ if (rd >= nregs) -+ err += efunc(pc, "invalid register %u\n", rd); -+ if (rd == 0) -+ err += efunc(pc, "cannot write to %r0\n"); -+ break; -+ case DIF_OP_NOT: -+ case DIF_OP_MOV: -+ case DIF_OP_ALLOCS: -+ if (r1 >= nregs) -+ err += efunc(pc, "invalid register %u\n", r1); -+ if (r2 != 0) -+ err += efunc(pc, "non-zero reserved bits\n"); -+ if (rd >= nregs) -+ err += efunc(pc, "invalid register %u\n", rd); -+ if (rd == 0) -+ err += efunc(pc, "cannot write to %r0\n"); -+ break; -+ case DIF_OP_LDSB: -+ case DIF_OP_LDSH: -+ case DIF_OP_LDSW: -+ case DIF_OP_LDUB: -+ case DIF_OP_LDUH: -+ case DIF_OP_LDUW: -+ case DIF_OP_LDX: -+ if (r1 >= nregs) -+ err += efunc(pc, "invalid register %u\n", r1); -+ if (r2 != 0) -+ err += efunc(pc, "non-zero reserved bits\n"); -+ if (rd >= nregs) -+ err += efunc(pc, "invalid register %u\n", rd); -+ if (rd == 0) -+ err += efunc(pc, "cannot write to %r0\n"); -+ if (kcheckload) -+ dp->dtdo_buf[pc] = DIF_INSTR_LOAD( -+ op + DIF_OP_RLDSB - -+ DIF_OP_LDSB, -+ r1, rd); -+ break; -+ case DIF_OP_RLDSB: -+ case DIF_OP_RLDSH: -+ case DIF_OP_RLDSW: -+ case DIF_OP_RLDUB: -+ case DIF_OP_RLDUH: -+ case DIF_OP_RLDUW: -+ case DIF_OP_RLDX: -+ if (r1 >= nregs) -+ err += efunc(pc, "invalid register %u\n", r1); -+ if (r2 != 0) -+ err += efunc(pc, "non-zero reserved bits\n"); -+ if (rd >= nregs) -+ err += efunc(pc, "invalid register %u\n", rd); -+ if (rd == 0) -+ err += efunc(pc, "cannot write to %r0\n"); -+ break; -+ case DIF_OP_ULDSB: -+ case DIF_OP_ULDSH: -+ case DIF_OP_ULDSW: -+ case DIF_OP_ULDUB: -+ case DIF_OP_ULDUH: -+ case DIF_OP_ULDUW: -+ case DIF_OP_ULDX: -+ if (r1 >= nregs) -+ err += efunc(pc, "invalid register %u\n", r1); -+ if (r2 != 0) -+ err += efunc(pc, "non-zero reserved bits\n"); -+ if (rd >= nregs) -+ err += efunc(pc, "invalid register %u\n", rd); -+ if (rd == 0) -+ err += efunc(pc, "cannot write to %r0\n"); -+ break; -+ case DIF_OP_STB: -+ case DIF_OP_STH: -+ case DIF_OP_STW: -+ case DIF_OP_STX: -+ if (r1 >= nregs) -+ err += efunc(pc, "invalid register %u\n", r1); -+ if (r2 != 0) -+ err += efunc(pc, "non-zero reserved bits\n"); -+ if (rd >= nregs) -+ err += efunc(pc, "invalid register %u\n", rd); -+ if (rd == 0) -+ err += efunc(pc, "cannot write to 0 address\n"); -+ break; -+ case DIF_OP_CMP: -+ case DIF_OP_SCMP: -+ if (r1 >= nregs) -+ err += efunc(pc, "invalid register %u\n", r1); -+ if (r2 >= nregs) -+ err += efunc(pc, "invalid register %u\n", r2); -+ if (rd != 0) -+ err += efunc(pc, "non-zero reserved bits\n"); -+ break; -+ case DIF_OP_TST: -+ if (r1 >= nregs) -+ err += efunc(pc, "invalid register %u\n", r1); -+ if (r2 != 0 || rd != 0) -+ err += efunc(pc, "non-zero reserved bits\n"); -+ break; -+ case DIF_OP_BA: -+ case DIF_OP_BE: -+ case DIF_OP_BNE: -+ case DIF_OP_BG: -+ case DIF_OP_BGU: -+ case DIF_OP_BGE: -+ case DIF_OP_BGEU: -+ case DIF_OP_BL: -+ case DIF_OP_BLU: -+ case DIF_OP_BLE: -+ case DIF_OP_BLEU: -+ if (label >= dp->dtdo_len) -+ err += efunc(pc, "invalid branch target %u\n", -+ label); -+ if (label <= pc) -+ err += efunc(pc, "backward branch to %u\n", -+ label); -+ break; -+ case DIF_OP_RET: -+ if (r1 != 0 || r2 != 0) -+ err += efunc(pc, "non-zero reserved bits\n"); -+ if (rd >= nregs) -+ err += efunc(pc, "invalid register %u\n", rd); -+ break; -+ case DIF_OP_NOP: -+ case DIF_OP_POPTS: -+ case DIF_OP_FLUSHTS: -+ if (r1 != 0 || r2 != 0 || rd != 0) -+ err += efunc(pc, "non-zero reserved bits\n"); -+ break; -+ case DIF_OP_SETX: -+ if (DIF_INSTR_INTEGER(instr) >= dp->dtdo_intlen) -+ err += efunc(pc, "invalid integer ref %u\n", -+ DIF_INSTR_INTEGER(instr)); -+ if (rd >= nregs) -+ err += efunc(pc, "invalid register %u\n", rd); -+ if (rd == 0) -+ err += efunc(pc, "cannot write to %r0\n"); -+ break; -+ case DIF_OP_SETS: -+ if (DIF_INSTR_STRING(instr) >= dp->dtdo_strlen) -+ err += efunc(pc, "invalid string ref %u\n", -+ DIF_INSTR_STRING(instr)); -+ if (rd >= nregs) -+ err += efunc(pc, "invalid register %u\n", rd); -+ if (rd == 0) -+ err += efunc(pc, "cannot write to %r0\n"); -+ break; -+ case DIF_OP_LDGA: -+ case DIF_OP_LDTA: -+ if (r1 > DIF_VAR_ARRAY_MAX) -+ err += efunc(pc, "invalid array %u\n", r1); -+ if (r2 >= nregs) -+ err += efunc(pc, "invalid register %u\n", r2); -+ if (rd >= nregs) -+ err += efunc(pc, "invalid register %u\n", rd); -+ if (rd == 0) -+ err += efunc(pc, "cannot write to %r0\n"); -+ break; -+ case DIF_OP_LDGS: -+ case DIF_OP_LDTS: -+ case DIF_OP_LDLS: -+ case DIF_OP_LDGAA: -+ case DIF_OP_LDTAA: -+ if (v < DIF_VAR_OTHER_MIN || v > DIF_VAR_OTHER_MAX) -+ err += efunc(pc, "invalid variable %u\n", v); -+ if (rd >= nregs) -+ err += efunc(pc, "invalid register %u\n", rd); -+ if (rd == 0) -+ err += efunc(pc, "cannot write to %r0\n"); -+ break; -+ case DIF_OP_STGS: -+ case DIF_OP_STTS: -+ case DIF_OP_STLS: -+ case DIF_OP_STGAA: -+ case DIF_OP_STTAA: -+ if (v < DIF_VAR_OTHER_UBASE || v > DIF_VAR_OTHER_MAX) -+ err += efunc(pc, "invalid variable %u\n", v); -+ if (rs >= nregs) -+ err += efunc(pc, "invalid register %u\n", rd); -+ break; -+ case DIF_OP_CALL: -+ if (subr > DIF_SUBR_MAX) -+ err += efunc(pc, "invalid subr %u\n", subr); -+ if (rd >= nregs) -+ err += efunc(pc, "invalid register %u\n", rd); -+ if (rd == 0) -+ err += efunc(pc, "cannot write to %r0\n"); -+ -+ if (subr == DIF_SUBR_COPYOUT || -+ subr == DIF_SUBR_COPYOUTSTR) -+ dp->dtdo_destructive = 1; -+ break; -+ case DIF_OP_PUSHTR: -+ if (diftype != DIF_TYPE_STRING && diftype != DIF_TYPE_CTF) -+ err += efunc(pc, "invalid ref type %u\n", -+ diftype); -+ if (r2 >= nregs) -+ err += efunc(pc, "invalid register %u\n", r2); -+ if (rs >= nregs) -+ err += efunc(pc, "invalid register %u\n", rs); -+ break; -+ case DIF_OP_PUSHTV: -+ if (diftype != DIF_TYPE_CTF) -+ err += efunc(pc, "invalid val type %u\n", -+ diftype); -+ if (r2 >= nregs) -+ err += efunc(pc, "invalid register %u\n", r2); -+ if (rs >= nregs) -+ err += efunc(pc, "invalid register %u\n", rs); -+ break; -+ default: -+ err += efunc(pc, "invalid opcode %u\n", -+ DIF_INSTR_OP(instr)); -+ } -+ } -+ -+ if (dp->dtdo_len != 0 && -+ DIF_INSTR_OP(dp->dtdo_buf[dp->dtdo_len - 1]) != DIF_OP_RET) { -+ err += efunc(dp->dtdo_len - 1, -+ "expected 'ret' as last DIF instruction\n"); -+ } -+ -+ if (!(dp->dtdo_rtype.dtdt_flags & DIF_TF_BYREF)) { -+ /* -+ * If we're not returning by reference, the size must be either -+ * 0 or the size of one of the base types. -+ */ -+ switch (dp->dtdo_rtype.dtdt_size) { -+ case 0: -+ case sizeof(uint8_t): -+ case sizeof(uint16_t): -+ case sizeof(uint32_t): -+ case sizeof(uint64_t): -+ break; -+ -+ default: -+ err += efunc(dp->dtdo_len - 1, "bad return size\n"); -+ } -+ } -+ -+ for (i = 0; i < dp->dtdo_varlen && err == 0; i++) { -+ struct dtrace_difv *v = &dp->dtdo_vartab[i], -+ *existing = NULL; -+ struct dtrace_diftype *vt, *et; -+ uint_t id, ndx; -+ -+ if (v->dtdv_scope != DIFV_SCOPE_GLOBAL && -+ v->dtdv_scope != DIFV_SCOPE_THREAD && -+ v->dtdv_scope != DIFV_SCOPE_LOCAL) { -+ err += efunc(i, "unrecognized variable scope %d\n", -+ v->dtdv_scope); -+ break; -+ } -+ -+ if (v->dtdv_kind != DIFV_KIND_ARRAY && -+ v->dtdv_kind != DIFV_KIND_SCALAR) { -+ err += efunc(i, "unrecognized variable type %d\n", -+ v->dtdv_kind); -+ break; -+ } -+ -+ id = v->dtdv_id; -+ if (id > DIF_VARIABLE_MAX) { -+ err += efunc(i, "%d exceeds variable id limit\n", id); -+ break; -+ } -+ -+ if (id < DIF_VAR_OTHER_UBASE) -+ continue; -+ -+ /* -+ * For user-defined variables, we need to check that this -+ * definition is identical to any previous definition that we -+ * encountered. -+ */ -+ ndx = id - DIF_VAR_OTHER_UBASE; -+ -+ switch (v->dtdv_scope) { -+ case DIFV_SCOPE_GLOBAL: -+ if (ndx < vstate->dtvs_nglobals) { -+ struct dtrace_statvar *svar; -+ -+ svar = vstate->dtvs_globals[ndx]; -+ if (svar != NULL) -+ existing = &svar->dtsv_var; -+ } -+ -+ break; -+ -+ case DIFV_SCOPE_THREAD: -+ if (ndx < vstate->dtvs_ntlocals) -+ existing = &vstate->dtvs_tlocals[ndx]; -+ break; -+ -+ case DIFV_SCOPE_LOCAL: -+ if (ndx < vstate->dtvs_nlocals) { -+ struct dtrace_statvar *svar; -+ -+ svar = vstate->dtvs_locals[ndx]; -+ if (svar != NULL) -+ existing = &svar->dtsv_var; -+ } -+ -+ break; -+ } -+ -+ vt = &v->dtdv_type; -+ -+ if (vt->dtdt_flags & DIF_TF_BYREF) { -+ if (vt->dtdt_size == 0) { -+ err += efunc(i, "zero-sized variable\n"); -+ break; -+ } -+ -+ if (v->dtdv_scope == DIFV_SCOPE_GLOBAL && -+ vt->dtdt_size > dtrace_global_maxsize) { -+ err += efunc(i, "oversized by-ref global\n"); -+ break; -+ } -+ } -+ -+ if (existing == NULL || existing->dtdv_id == 0) -+ continue; -+ -+ ASSERT(existing->dtdv_id == v->dtdv_id); -+ ASSERT(existing->dtdv_scope == v->dtdv_scope); -+ -+ if (existing->dtdv_kind != v->dtdv_kind) -+ err += efunc(i, "%d changed variable kind\n", id); -+ -+ et = &existing->dtdv_type; -+ -+ if (vt->dtdt_flags != et->dtdt_flags) { -+ err += efunc(i, "%d changed variable type flags\n", id); -+ break; -+ } -+ -+ if (vt->dtdt_size != 0 && vt->dtdt_size != et->dtdt_size) { -+ err += efunc(i, "%d changed variable type size\n", id); -+ break; -+ } -+ } -+ -+ return err; -+} -+ -+/* -+ * Validate a DTrace DIF object that it is to be used as a helper. Helpers -+ * are much more constrained than normal DIFOs. Specifically, they may -+ * not: -+ * -+ * 1. Make calls to subroutines other than copyin(), copyinstr() or -+ * miscellaneous string routines -+ * 2. Access DTrace variables other than the args[] array, and the -+ * curthread, pid, ppid, tid, execname, zonename, uid and gid variables. -+ * 3. Have thread-local variables. -+ * 4. Have dynamic variables. -+ */ -+int dtrace_difo_validate_helper(struct dtrace_difo *dp) -+{ -+ int (*efunc)(uint_t pc, const char *, ...) = dtrace_difo_err; -+ int err = 0; -+ uint_t pc; -+ -+ for (pc = 0; pc < dp->dtdo_len; pc++) { -+ dif_instr_t instr = dp->dtdo_buf[pc]; -+ uint_t v = DIF_INSTR_VAR(instr); -+ uint_t subr = DIF_INSTR_SUBR(instr); -+ uint_t op = DIF_INSTR_OP(instr); -+ -+ switch (op) { -+ case DIF_OP_OR: -+ case DIF_OP_XOR: -+ case DIF_OP_AND: -+ case DIF_OP_SLL: -+ case DIF_OP_SRL: -+ case DIF_OP_SRA: -+ case DIF_OP_SUB: -+ case DIF_OP_ADD: -+ case DIF_OP_MUL: -+ case DIF_OP_SDIV: -+ case DIF_OP_UDIV: -+ case DIF_OP_SREM: -+ case DIF_OP_UREM: -+ case DIF_OP_COPYS: -+ case DIF_OP_NOT: -+ case DIF_OP_MOV: -+ case DIF_OP_RLDSB: -+ case DIF_OP_RLDSH: -+ case DIF_OP_RLDSW: -+ case DIF_OP_RLDUB: -+ case DIF_OP_RLDUH: -+ case DIF_OP_RLDUW: -+ case DIF_OP_RLDX: -+ case DIF_OP_ULDSB: -+ case DIF_OP_ULDSH: -+ case DIF_OP_ULDSW: -+ case DIF_OP_ULDUB: -+ case DIF_OP_ULDUH: -+ case DIF_OP_ULDUW: -+ case DIF_OP_ULDX: -+ case DIF_OP_STB: -+ case DIF_OP_STH: -+ case DIF_OP_STW: -+ case DIF_OP_STX: -+ case DIF_OP_ALLOCS: -+ case DIF_OP_CMP: -+ case DIF_OP_SCMP: -+ case DIF_OP_TST: -+ case DIF_OP_BA: -+ case DIF_OP_BE: -+ case DIF_OP_BNE: -+ case DIF_OP_BG: -+ case DIF_OP_BGU: -+ case DIF_OP_BGE: -+ case DIF_OP_BGEU: -+ case DIF_OP_BL: -+ case DIF_OP_BLU: -+ case DIF_OP_BLE: -+ case DIF_OP_BLEU: -+ case DIF_OP_RET: -+ case DIF_OP_NOP: -+ case DIF_OP_POPTS: -+ case DIF_OP_FLUSHTS: -+ case DIF_OP_SETX: -+ case DIF_OP_SETS: -+ case DIF_OP_LDGA: -+ case DIF_OP_LDLS: -+ case DIF_OP_STGS: -+ case DIF_OP_STLS: -+ case DIF_OP_PUSHTR: -+ case DIF_OP_PUSHTV: -+ break; -+ -+ case DIF_OP_LDGS: -+ if (v >= DIF_VAR_OTHER_UBASE) -+ break; -+ -+ if (v >= DIF_VAR_ARG0 && v <= DIF_VAR_ARG9) -+ break; -+ -+ if (v == DIF_VAR_CURTHREAD || v == DIF_VAR_PID || -+ v == DIF_VAR_PPID || v == DIF_VAR_TID || -+ v == DIF_VAR_EXECNAME || v == DIF_VAR_ZONENAME || -+ v == DIF_VAR_UID || v == DIF_VAR_GID) -+ break; -+ -+ err += efunc(pc, "illegal variable %u\n", v); -+ break; -+ -+ case DIF_OP_LDTA: -+ case DIF_OP_LDGAA: -+ case DIF_OP_LDTAA: -+ err += efunc(pc, "illegal dynamic variable load\n"); -+ break; -+ -+ case DIF_OP_STTS: -+ case DIF_OP_STGAA: -+ case DIF_OP_STTAA: -+ err += efunc(pc, "illegal dynamic variable store\n"); -+ break; -+ -+ case DIF_OP_CALL: -+ if (subr == DIF_SUBR_ALLOCA || -+ subr == DIF_SUBR_BCOPY || -+ subr == DIF_SUBR_COPYIN || -+ subr == DIF_SUBR_COPYINTO || -+ subr == DIF_SUBR_COPYINSTR || -+ subr == DIF_SUBR_INDEX || -+ subr == DIF_SUBR_INET_NTOA || -+ subr == DIF_SUBR_INET_NTOA6 || -+ subr == DIF_SUBR_INET_NTOP || -+ subr == DIF_SUBR_LINK_NTOP || -+ subr == DIF_SUBR_LLTOSTR || -+ subr == DIF_SUBR_RINDEX || -+ subr == DIF_SUBR_STRCHR || -+ subr == DIF_SUBR_STRJOIN || -+ subr == DIF_SUBR_STRRCHR || -+ subr == DIF_SUBR_STRSTR || -+ subr == DIF_SUBR_HTONS || -+ subr == DIF_SUBR_HTONL || -+ subr == DIF_SUBR_HTONLL || -+ subr == DIF_SUBR_NTOHS || -+ subr == DIF_SUBR_NTOHL || -+ subr == DIF_SUBR_NTOHLL) -+ break; -+ -+ err += efunc(pc, "invalid subr %u\n", subr); -+ break; -+ -+ default: -+ err += efunc(pc, "invalid opcode %u\n", -+ DIF_INSTR_OP(instr)); -+ } -+ } -+ -+ return err; -+} -+ -+/* -+ * Returns 1 if the expression in the DIF object can be cached on a per-thread -+ * basis; 0 if not. -+ */ -+int dtrace_difo_cacheable(struct dtrace_difo *dp) -+{ -+ int i; -+ -+ if (dp == NULL) -+ return 0; -+ -+ for (i = 0; i < dp->dtdo_varlen; i++) { -+ struct dtrace_difv *v = &dp->dtdo_vartab[i]; -+ -+ if (v->dtdv_scope != DIFV_SCOPE_GLOBAL) -+ continue; -+ -+ switch (v->dtdv_id) { -+ case DIF_VAR_CURTHREAD: -+ case DIF_VAR_PID: -+ case DIF_VAR_TID: -+ case DIF_VAR_EXECNAME: -+ case DIF_VAR_ZONENAME: -+ break; -+ -+ default: -+ return 0; -+ } -+ } -+ -+ /* -+ * This DIF object may be cacheable. Now we need to look for any -+ * array loading instructions, any memory loading instructions, or -+ * any stores to thread-local variables. -+ */ -+ for (i = 0; i < dp->dtdo_len; i++) { -+ uint_t op = DIF_INSTR_OP(dp->dtdo_buf[i]); -+ -+ if ((op >= DIF_OP_LDSB && op <= DIF_OP_LDX) || -+ (op >= DIF_OP_ULDSB && op <= DIF_OP_ULDX) || -+ (op >= DIF_OP_RLDSB && op <= DIF_OP_RLDX) || -+ op == DIF_OP_LDGA || op == DIF_OP_STTS) -+ return 0; -+ } -+ -+ return 1; -+} -+ -+/* -+ * This routine calculates the dynamic variable chunksize for a given DIF -+ * object. The calculation is not fool-proof, and can probably be tricked by -+ * malicious DIF -- but it works for all compiler-generated DIF. Because this -+ * calculation is likely imperfect, dtrace_dynvar() is able to gracefully fail -+ * if a dynamic variable size exceeds the chunksize. -+ */ -+static void dtrace_difo_chunksize(struct dtrace_difo *dp, -+ struct dtrace_vstate *vstate) -+{ -+ uint64_t sval = 0; -+ struct dtrace_key tupregs[DIF_DTR_NREGS + 2]; /* + thread + id */ -+ const dif_instr_t *text = dp->dtdo_buf; -+ uint_t pc, srd = 0; -+ uint_t ttop = 0; -+ size_t size, ksize; -+ uint_t id, i; -+ -+ for (pc = 0; pc < dp->dtdo_len; pc++) { -+ dif_instr_t instr = text[pc]; -+ uint_t op = DIF_INSTR_OP(instr); -+ uint_t rd = DIF_INSTR_RD(instr); -+ uint_t r1 = DIF_INSTR_R1(instr); -+ uint_t nkeys = 0; -+ uchar_t scope; -+ struct dtrace_key *key = tupregs; -+ -+ switch (op) { -+ case DIF_OP_SETX: -+ sval = dp->dtdo_inttab[DIF_INSTR_INTEGER(instr)]; -+ srd = rd; -+ continue; -+ -+ case DIF_OP_STTS: -+ key = &tupregs[DIF_DTR_NREGS]; -+ key[0].dttk_size = 0; -+ key[1].dttk_size = 0; -+ nkeys = 2; -+ scope = DIFV_SCOPE_THREAD; -+ break; -+ -+ case DIF_OP_STGAA: -+ case DIF_OP_STTAA: -+ nkeys = ttop; -+ -+ if (DIF_INSTR_OP(instr) == DIF_OP_STTAA) -+ key[nkeys++].dttk_size = 0; -+ -+ key[nkeys++].dttk_size = 0; -+ -+ if (op == DIF_OP_STTAA) -+ scope = DIFV_SCOPE_THREAD; -+ else -+ scope = DIFV_SCOPE_GLOBAL; -+ -+ break; -+ -+ case DIF_OP_PUSHTR: -+ if (ttop == DIF_DTR_NREGS) -+ return; -+ -+ /* -+ * If the register for the size of the "pushtr" is %r0 -+ * (or the value is 0) and the type is a string, we'll -+ * use the system-wide default string size. -+ */ -+ if ((srd == 0 || sval == 0) && r1 == DIF_TYPE_STRING) -+ tupregs[ttop++].dttk_size = -+ dtrace_strsize_default; -+ else { -+ if (srd == 0) -+ return; -+ -+ tupregs[ttop++].dttk_size = sval; -+ } -+ -+ break; -+ -+ case DIF_OP_PUSHTV: -+ if (ttop == DIF_DTR_NREGS) -+ return; -+ -+ tupregs[ttop++].dttk_size = 0; -+ break; -+ -+ case DIF_OP_FLUSHTS: -+ ttop = 0; -+ break; -+ -+ case DIF_OP_POPTS: -+ if (ttop != 0) -+ ttop--; -+ break; -+ } -+ -+ sval = 0; -+ srd = 0; -+ -+ if (nkeys == 0) -+ continue; -+ -+ /* -+ * We have a dynamic variable allocation; calculate its size. -+ */ -+ for (ksize = 0, i = 0; i < nkeys; i++) -+ ksize += P2ROUNDUP(key[i].dttk_size, sizeof(uint64_t)); -+ -+ size = sizeof(struct dtrace_dynvar); -+ size += sizeof(struct dtrace_key) * (nkeys - 1); -+ size += ksize; -+ -+ /* -+ * Now we need to determine the size of the stored data. -+ */ -+ id = DIF_INSTR_VAR(instr); -+ -+ for (i = 0; i < dp->dtdo_varlen; i++) { -+ struct dtrace_difv *v = &dp->dtdo_vartab[i]; -+ -+ if (v->dtdv_id == id && v->dtdv_scope == scope) { -+ size += v->dtdv_type.dtdt_size; -+ break; -+ } -+ } -+ -+ if (i == dp->dtdo_varlen) -+ return; -+ -+ /* -+ * We have the size. If this is larger than the chunk size -+ * for our dynamic variable state, reset the chunk size. -+ */ -+ size = P2ROUNDUP(size, sizeof(uint64_t)); -+ -+ if (size > vstate->dtvs_dynvars.dtds_chunksize) -+ vstate->dtvs_dynvars.dtds_chunksize = size; -+ } -+} -+ -+void dtrace_difo_hold(struct dtrace_difo *dp) -+{ -+ int i; -+ -+ dp->dtdo_refcnt++; -+ ASSERT(dp->dtdo_refcnt != 0); -+ -+ for (i = 0; i < dp->dtdo_varlen; i++) { -+ struct dtrace_difv *v = &dp->dtdo_vartab[i]; -+ -+ if (v->dtdv_id != DIF_VAR_VTIMESTAMP) -+ continue; -+ -+ if (dtrace_vtime_references++ == 0) -+ dtrace_vtime_enable(); -+ } -+} -+ -+void dtrace_difo_init(struct dtrace_difo *dp, struct dtrace_vstate *vstate) -+{ -+ int i, oldsvars, osz, nsz, otlocals, ntlocals; -+ uint_t id; -+ -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ ASSERT(dp->dtdo_buf != NULL && dp->dtdo_len != 0); -+ -+ for (i = 0; i < dp->dtdo_varlen; i++) { -+ struct dtrace_difv *v = &dp->dtdo_vartab[i]; -+ struct dtrace_statvar *svar, ***svarp; -+ size_t dsize = 0; -+ uint8_t scope = v->dtdv_scope; -+ int *np; -+ -+ id = v->dtdv_id; -+ if (id < DIF_VAR_OTHER_UBASE) -+ continue; -+ -+ id -= DIF_VAR_OTHER_UBASE; -+ -+ switch (scope) { -+ case DIFV_SCOPE_THREAD: -+ while (id >= (otlocals = vstate->dtvs_ntlocals)) { -+ struct dtrace_difv *tlocals; -+ -+ ntlocals = otlocals << 1; -+ if (ntlocals == 0) -+ ntlocals = 1; -+ -+ osz = otlocals * sizeof(struct dtrace_difv); -+ nsz = ntlocals * sizeof(struct dtrace_difv); -+ -+ tlocals = vzalloc(nsz); -+ -+ if (osz != 0) { -+ memcpy(tlocals, vstate->dtvs_tlocals, -+ osz); -+ vfree(vstate->dtvs_tlocals); -+ } -+ -+ vstate->dtvs_tlocals = tlocals; -+ vstate->dtvs_ntlocals = ntlocals; -+ } -+ -+ vstate->dtvs_tlocals[id] = *v; -+ continue; -+ -+ case DIFV_SCOPE_LOCAL: -+ np = &vstate->dtvs_nlocals; -+ svarp = &vstate->dtvs_locals; -+ -+ if (v->dtdv_type.dtdt_flags & DIF_TF_BYREF) -+ dsize = NR_CPUS * -+ (v->dtdv_type.dtdt_size + -+ sizeof(uint64_t)); -+ else -+ dsize = NR_CPUS * sizeof(uint64_t); -+ -+ break; -+ -+ case DIFV_SCOPE_GLOBAL: -+ np = &vstate->dtvs_nglobals; -+ svarp = &vstate->dtvs_globals; -+ -+ if (v->dtdv_type.dtdt_flags & DIF_TF_BYREF) -+ dsize = v->dtdv_type.dtdt_size + -+ sizeof(uint64_t); -+ -+ break; -+ -+ default: -+ ASSERT(0); -+ continue; /* not reached */ -+ } -+ -+ while (id >= (oldsvars = *np)) { -+ struct dtrace_statvar **statics; -+ int newsvars, oldsize, newsize; -+ -+ newsvars = oldsvars << 1; -+ if (newsvars == 0) -+ newsvars = 1; -+ -+ oldsize = oldsvars * sizeof(struct dtrace_statvar *); -+ newsize = newsvars * sizeof(struct dtrace_statvar *); -+ -+ statics = vzalloc(newsize); -+ -+ if (oldsize != 0) { -+ memcpy(statics, *svarp, oldsize); -+ vfree(*svarp); -+ } -+ -+ *svarp = statics; -+ *np = newsvars; -+ } -+ -+ svar = (*svarp)[id]; -+ if (svar == NULL) { -+ svar = kzalloc(sizeof(struct dtrace_statvar), -+ GFP_KERNEL); -+ svar->dtsv_var = *v; -+ -+ svar->dtsv_size = dsize; -+ if (svar->dtsv_size != 0) { -+ svar->dtsv_data = -+ (uint64_t)(uintptr_t)vzalloc(dsize); -+ } -+ -+ (*svarp)[id] = svar; -+ } -+ -+ svar->dtsv_refcnt++; -+ } -+ -+ dtrace_difo_chunksize(dp, vstate); -+ dtrace_difo_hold(dp); -+} -+ -+struct dtrace_difo *dtrace_difo_duplicate(struct dtrace_difo *dp, -+ struct dtrace_vstate *vstate) -+{ -+ struct dtrace_difo *new; -+ size_t sz; -+ -+ ASSERT(dp->dtdo_buf != NULL); -+ ASSERT(dp->dtdo_refcnt != 0); -+ -+ new = kzalloc(sizeof(struct dtrace_difo), GFP_KERNEL); -+ -+ ASSERT(dp->dtdo_buf != NULL); -+ sz = dp->dtdo_len * sizeof(dif_instr_t); -+ new->dtdo_buf = vmalloc(sz); -+ memcpy(new->dtdo_buf, dp->dtdo_buf, sz); -+ new->dtdo_len = dp->dtdo_len; -+ -+ if (dp->dtdo_strtab != NULL) { -+ ASSERT(dp->dtdo_strlen != 0); -+ new->dtdo_strtab = vmalloc(dp->dtdo_strlen); -+ memcpy(new->dtdo_strtab, dp->dtdo_strtab, dp->dtdo_strlen); -+ new->dtdo_strlen = dp->dtdo_strlen; -+ } -+ -+ if (dp->dtdo_inttab != NULL) { -+ ASSERT(dp->dtdo_intlen != 0); -+ sz = dp->dtdo_intlen * sizeof(uint64_t); -+ new->dtdo_inttab = vmalloc(sz); -+ memcpy(new->dtdo_inttab, dp->dtdo_inttab, sz); -+ new->dtdo_intlen = dp->dtdo_intlen; -+ } -+ -+ if (dp->dtdo_vartab != NULL) { -+ ASSERT(dp->dtdo_varlen != 0); -+ sz = dp->dtdo_varlen * sizeof(struct dtrace_difv); -+ new->dtdo_vartab = vmalloc(sz); -+ memcpy(new->dtdo_vartab, dp->dtdo_vartab, sz); -+ new->dtdo_varlen = dp->dtdo_varlen; -+ } -+ -+ dtrace_difo_init(new, vstate); -+ -+ return new; -+} -+ -+void dtrace_difo_destroy(struct dtrace_difo *dp, struct dtrace_vstate *vstate) -+{ -+ int i; -+ -+ ASSERT(dp->dtdo_refcnt == 0); -+ -+ for (i = 0; i < dp->dtdo_varlen; i++) { -+ struct dtrace_difv *v = &dp->dtdo_vartab[i]; -+ struct dtrace_statvar *svar, **svarp; -+ uint_t id; -+ uint8_t scope = v->dtdv_scope; -+ int *np; -+ -+ switch (scope) { -+ case DIFV_SCOPE_THREAD: -+ continue; -+ -+ case DIFV_SCOPE_LOCAL: -+ np = &vstate->dtvs_nlocals; -+ svarp = vstate->dtvs_locals; -+ break; -+ -+ case DIFV_SCOPE_GLOBAL: -+ np = &vstate->dtvs_nglobals; -+ svarp = vstate->dtvs_globals; -+ break; -+ -+ default: -+ BUG(); -+ } -+ -+ id = v->dtdv_id; -+ if (id < DIF_VAR_OTHER_UBASE) -+ continue; -+ -+ id -= DIF_VAR_OTHER_UBASE; -+ ASSERT(id < *np); -+ -+ svar = svarp[id]; -+ ASSERT(svar != NULL); -+ ASSERT(svar->dtsv_refcnt > 0); -+ -+ if (--svar->dtsv_refcnt > 0) -+ continue; -+ -+ if (svar->dtsv_size != 0) { -+ ASSERT((void *)(uintptr_t)svar->dtsv_data != NULL); -+ vfree((void *)(uintptr_t)svar->dtsv_data); -+ } -+ -+ kfree(svar); -+ svarp[id] = NULL; -+ } -+ -+ vfree(dp->dtdo_buf); -+ vfree(dp->dtdo_inttab); -+ vfree(dp->dtdo_strtab); -+ vfree(dp->dtdo_vartab); -+ kfree(dp); -+} -+ -+void dtrace_difo_release(struct dtrace_difo *dp, struct dtrace_vstate *vstate) -+{ -+ int i; -+ -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ ASSERT(dp->dtdo_refcnt != 0); -+ -+ for (i = 0; i < dp->dtdo_varlen; i++) { -+ struct dtrace_difv *v = &dp->dtdo_vartab[i]; -+ -+ if (v->dtdv_id != DIF_VAR_VTIMESTAMP) -+ continue; -+ -+ ASSERT(dtrace_vtime_references > 0); -+ -+ if (--dtrace_vtime_references == 0) -+ dtrace_vtime_disable(); -+ } -+ -+ if (--dp->dtdo_refcnt == 0) -+ dtrace_difo_destroy(dp, vstate); -+} -+ -+/* -+ * The key for a thread-local variable consists of the lower 60 bits of the -+ * task pid, prefixed by a 4 bits indicating whether a hard_irq is active. -+ * This accounts for a case where some older drivers re-enable interrupts -+ * and can nest in hard irq context. -+ * -+ * All per-cpu idle threads share same pid 0. In this special case we replace -+ * the pid with cpu id (an idle thread is bound to a single cpu). If pid is -+ * not 0 then a NR_CPUS is added. This assures that the thread key for idle -+ * thread never conflicts with regular pids in range 0..NR_CPUS. -+ * -+ * We add DIF_VARIABLE_MAX to the pid to assure that the thread key is never -+ * equal to a variable identifier. This is necessary (but not sufficient) to -+ * assure that global associative arrays never collide with thread-local -+ * variables. To guarantee that they cannot collide, we must also define the -+ * order for keying dynamic variables. That order is: -+ * -+ * [ key0 ] ... [ keyn ] [ variable-key ] [ tls-key ] -+ * -+ * Because the variable-key and the tls-key are in orthogonal spaces, there is -+ * no way for a global variable key signature to match a thread-local key -+ * signature. -+ */ -+#define DTRACE_TLS_THRKEY(where) \ -+ { \ -+ uint_t intr = hardirq_count() >> HARDIRQ_SHIFT; \ -+ uint_t cpu = (current->flags & PF_IDLE) ? \ -+ smp_processor_id() : NR_CPUS; \ -+ \ -+ (where) = ((current->pid + cpu + DIF_VARIABLE_MAX) & \ -+ (((uint64_t)1 << 60) - 1)) | \ -+ ((uint64_t)intr << 60); \ -+ } -+ -+#ifndef FIXME -+# define DTRACE_ALIGNCHECK(addr, size, flags) -+#endif -+ -+/* -+ * Test whether a range of memory starting at testaddr of size testsz falls -+ * within the range of memory described by addr, sz. We take care to avoid -+ * problems with overflow and underflow of the unsigned quantities, and -+ * disallow all negative sizes. Ranges of size 0 are allowed. -+ */ -+#define DTRACE_INRANGE(testaddr, testsz, baseaddr, basesz) \ -+ ((testaddr) - (baseaddr) < (basesz) && \ -+ (testaddr) + (testsz) - (baseaddr) <= (basesz) && \ -+ (testaddr) + (testsz) >= (testaddr)) -+ -+#define DTRACE_LOADFUNC(bits) \ -+ uint##bits##_t dtrace_load##bits(uintptr_t addr) \ -+ { \ -+ size_t size = bits / NBBY; \ -+ uint##bits##_t rval; \ -+ int i; \ -+ volatile uint16_t *flags = (volatile uint16_t *) \ -+ &this_cpu_core->cpuc_dtrace_flags; \ -+ \ -+ /* \ -+ * Deviation from the OpenSolaris code... Protect \ -+ * against dereferencing the NULL pointer since that \ -+ * really causes us a lot of grief (crash). \ -+ */ \ -+ if (addr == 0) { \ -+ *flags |= CPU_DTRACE_BADADDR; \ -+ this_cpu_core->cpuc_dtrace_illval = addr; \ -+ return 0; \ -+ } \ -+ \ -+ DTRACE_ALIGNCHECK(addr, size, flags); \ -+ \ -+ for (i = 0; i < dtrace_toxranges; i++) { \ -+ if (addr >= dtrace_toxrange[i].dtt_limit) \ -+ continue; \ -+ \ -+ if (addr + size <= dtrace_toxrange[i].dtt_base) \ -+ continue; \ -+ \ -+ /* \ -+ * This address falls within a toxic region. \ -+ */ \ -+ *flags |= CPU_DTRACE_BADADDR; \ -+ this_cpu_core->cpuc_dtrace_illval = addr; \ -+ return 0; \ -+ } \ -+ \ -+ *flags |= CPU_DTRACE_NOFAULT; \ -+ rval = *((volatile uint##bits##_t *)addr); \ -+ *flags &= ~CPU_DTRACE_NOFAULT; \ -+ \ -+ return !(*flags & CPU_DTRACE_FAULT) ? rval : 0; \ -+ } -+ -+/* -+ * Use the DTRACE_LOADFUNC macro to define functions for each of loading a -+ * uint8_t, a uint16_t, a uint32_t and a uint64_t. -+ */ -+DTRACE_LOADFUNC(8) -+DTRACE_LOADFUNC(16) -+DTRACE_LOADFUNC(32) -+DTRACE_LOADFUNC(64) -+ -+#define DT_BSWAP_8(x) ((x) & 0xff) -+#define DT_BSWAP_16(x) ((DT_BSWAP_8(x) << 8) | DT_BSWAP_8((x) >> 8)) -+#define DT_BSWAP_32(x) ((DT_BSWAP_16(x) << 16) | DT_BSWAP_16((x) >> 16)) -+#define DT_BSWAP_64(x) ((DT_BSWAP_32(x) << 32) | DT_BSWAP_32((x) >> 32)) -+ -+static int dtrace_inscratch(uintptr_t dest, size_t size, -+ struct dtrace_mstate *mstate) -+{ -+ if (dest < mstate->dtms_scratch_base) -+ return 0; -+ -+ if (dest + size < dest) -+ return 0; -+ -+ if (dest + size > mstate->dtms_scratch_ptr) -+ return 0; -+ -+ return 1; -+} -+ -+static int dtrace_canstore_statvar(uint64_t addr, size_t sz, -+ struct dtrace_statvar **svars, int nsvars) -+{ -+ int i; -+ -+ for (i = 0; i < nsvars; i++) { -+ struct dtrace_statvar *svar = svars[i]; -+ -+ if (svar == NULL || svar->dtsv_size == 0) -+ continue; -+ -+ if (DTRACE_INRANGE(addr, sz, svar->dtsv_data, svar->dtsv_size)) -+ return 1; -+ } -+ -+ return 0; -+} -+ -+/* -+ * Check to see if the address is within a memory region to which a store may -+ * be issued. This includes the DTrace scratch areas, and any DTrace variable -+ * region. The caller of dtrace_canstore() is responsible for performing any -+ * alignment checks that are needed before stores are actually executed. -+ */ -+static int dtrace_canstore(uint64_t addr, size_t sz, -+ struct dtrace_mstate *mstate, -+ struct dtrace_vstate *vstate) -+{ -+ /* -+ * First, check to see if the address is in scratch space... -+ */ -+ if (DTRACE_INRANGE(addr, sz, mstate->dtms_scratch_base, -+ mstate->dtms_scratch_size)) -+ return 1; -+ -+ /* -+ * Now check to see if it's a dynamic variable. This check will pick -+ * up both thread-local variables and any global dynamically-allocated -+ * variables. -+ */ -+ if (DTRACE_INRANGE(addr, sz, (uintptr_t)vstate->dtvs_dynvars.dtds_base, -+ vstate->dtvs_dynvars.dtds_size)) { -+ struct dtrace_dstate *dstate = &vstate->dtvs_dynvars; -+ uintptr_t base = (uintptr_t)dstate->dtds_base + -+ (dstate->dtds_hashsize * -+ sizeof(struct dtrace_dynhash)); -+ uintptr_t chunkoffs; -+ uint64_t num; -+ -+ /* -+ * Before we assume that we can store here, we need to make -+ * sure that it isn't in our metadata -- storing to our -+ * dynamic variable metadata would corrupt our state. For -+ * the range to not include any dynamic variable metadata, -+ * it must: -+ * -+ * (1) Start above the hash table that is at the base of -+ * the dynamic variable space -+ * -+ * (2) Have a starting chunk offset that is beyond the -+ * dtrace_dynvar_t that is at the base of every chunk -+ * -+ * (3) Not span a chunk boundary -+ */ -+ if (addr < base) -+ return 0; -+ -+ num = addr - base; -+ chunkoffs = do_div(num, dstate->dtds_chunksize); -+ -+ if (chunkoffs < sizeof(struct dtrace_dynvar)) -+ return 0; -+ -+ if (chunkoffs + sz > dstate->dtds_chunksize) -+ return 0; -+ -+ return 1; -+ } -+ -+ /* -+ * Finally, check the static local and global variables. These checks -+ * take the longest, so we perform them last. -+ */ -+ if (dtrace_canstore_statvar(addr, sz, vstate->dtvs_locals, -+ vstate->dtvs_nlocals)) -+ return 1; -+ -+ if (dtrace_canstore_statvar(addr, sz, vstate->dtvs_globals, -+ vstate->dtvs_nglobals)) -+ return 1; -+ -+ return 0; -+} -+ -+/* -+ * Convenience routine to check to see if the address is within a memory -+ * region in which a load may be issued given the user's privilege level; -+ * if not, it sets the appropriate error flags and loads 'addr' into the -+ * illegal value slot. -+ * -+ * DTrace subroutines (DIF_SUBR_*) should use this helper to implement -+ * appropriate memory access protection. -+ */ -+int -+dtrace_canload(uintptr_t addr, size_t sz, struct dtrace_mstate *mstate, -+ struct dtrace_vstate *vstate) -+{ -+ volatile uintptr_t *illval = &this_cpu_core->cpuc_dtrace_illval; -+ -+ /* -+ * If we hold the privilege to read from kernel memory, then -+ * everything is readable. -+ */ -+ if ((mstate->dtms_access & DTRACE_ACCESS_KERNEL) != 0) -+ return 1; -+ -+ /* -+ * You can obviously read that which you can store. -+ */ -+ if (dtrace_canstore(addr, sz, mstate, vstate)) -+ return 1; -+ -+ /* -+ * We're allowed to read from our own string table. -+ */ -+ if (DTRACE_INRANGE(addr, sz, (uintptr_t)mstate->dtms_difo->dtdo_strtab, -+ mstate->dtms_difo->dtdo_strlen)) -+ return 1; -+ -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_KPRIV); -+ *illval = addr; -+ -+ return 0; -+} -+ -+/* -+ * Convenience routine to check to see if a given string is within a memory -+ * region in which a load may be issued given the user's privilege level; -+ * this exists so that we don't need to issue unnecessary dtrace_strlen() -+ * calls in the event that the user has all privileges. -+ */ -+static int -+dtrace_strcanload(uint64_t addr, size_t sz, struct dtrace_mstate *mstate, -+ struct dtrace_vstate *vstate) -+{ -+ size_t strsz; -+ -+ /* -+ * If we hold the privilege to read from kernel memory, then -+ * everything is readable. -+ */ -+ if ((mstate->dtms_access & DTRACE_ACCESS_KERNEL) != 0) -+ return 1; -+ -+ strsz = 1 + dtrace_strlen((char *)(uintptr_t)addr, sz); -+ if (dtrace_canload(addr, strsz, mstate, vstate)) -+ return 1; -+ -+ return 0; -+} -+ -+/* -+ * Convenience routine to check to see if a given variable is within a memory -+ * region in which a load may be issued given the user's privilege level. -+ */ -+int dtrace_vcanload(void *src, struct dtrace_diftype *diftype, -+ struct dtrace_mstate *mstate, -+ struct dtrace_vstate *vstate) -+{ -+ size_t sz; -+ -+ ASSERT(diftype->dtdt_flags & DIF_TF_BYREF); -+ -+ /* -+ * If we hold the privilege to read from kernel memory, then -+ * everything is readable. -+ */ -+ if ((mstate->dtms_access & DTRACE_ACCESS_KERNEL) != 0) -+ return 1; -+ -+ if (diftype->dtdt_kind == DIF_TYPE_STRING) -+ sz = dtrace_strlen( -+ src, -+ vstate->dtvs_state->dts_options[DTRACEOPT_STRSIZE] -+ ) + 1; -+ else -+ sz = diftype->dtdt_size; -+ -+ return dtrace_canload((uintptr_t)src, sz, mstate, vstate); -+} -+ -+/* -+ * Copy src to dst using safe memory accesses. The src is assumed to be unsafe -+ * memory specified by the DIF program. The dst is assumed to be safe memory -+ * that we can store to directly because it is managed by DTrace. As with -+ * standard bcopy, overlapping copies are handled properly. -+ */ -+static void dtrace_bcopy(const void *src, void *dst, size_t len) -+{ -+ if (len != 0) { -+ uint8_t *s1 = dst; -+ const uint8_t *s2 = src; -+ -+ if (s1 <= s2) { -+ do { -+ *s1++ = dtrace_load8((uintptr_t)s2++); -+ } while (--len != 0); -+ } else { -+ s2 += len; -+ s1 += len; -+ -+ do { -+ *--s1 = dtrace_load8((uintptr_t)--s2); -+ } while (--len != 0); -+ } -+ } -+} -+ -+/* -+ * Copy src to dst using safe memory accesses, up to either the specified -+ * length, or the point that a nul byte is encountered. The src is assumed to -+ * be unsafe memory specified by the DIF program. The dst is assumed to be -+ * safe memory that we can store to directly because it is managed by DTrace. -+ * Unlike dtrace_bcopy(), overlapping regions are not handled. -+ */ -+static void dtrace_strcpy(const void *src, void *dst, size_t len) -+{ -+ if (len != 0) { -+ uint8_t *s1 = dst, c; -+ const uint8_t *s2 = src; -+ -+ do { -+ *s1++ = c = dtrace_load8((uintptr_t)s2++); -+ } while (--len != 0 && c != '\0'); -+ } -+} -+/* -+ * Copy src to dst, deriving the size and type from the specified (BYREF) -+ * variable type. The src is assumed to be unsafe memory specified by the DIF -+ * program. The dst is assumed to be DTrace variable memory that is of the -+ * specified type; we assume that we can store to directly. -+ */ -+static void dtrace_vcopy(void *src, void *dst, struct dtrace_diftype *diftype) -+{ -+ ASSERT(diftype->dtdt_flags & DIF_TF_BYREF); -+ -+ if (diftype->dtdt_kind == DIF_TYPE_STRING) -+ dtrace_strcpy(src, dst, diftype->dtdt_size); -+ else -+ dtrace_bcopy(src, dst, diftype->dtdt_size); -+} -+ -+/* -+ * Compare s1 to s2 using safe memory accesses. The s1 data is assumed to be -+ * unsafe memory specified by the DIF program. The s2 data is assumed to be -+ * safe memory that we can access directly because it is managed by DTrace. -+ */ -+static int dtrace_bcmp(const void *s1, const void *s2, size_t len) -+{ -+ volatile uint16_t *flags; -+ -+ flags = (volatile uint16_t *)&this_cpu_core->cpuc_dtrace_flags; -+ -+ if (s1 == s2) -+ return 0; -+ -+ if (s1 == NULL || s2 == NULL) -+ return 1; -+ -+ if (s1 != s2 && len != 0) { -+ const uint8_t *ps1 = s1; -+ const uint8_t *ps2 = s2; -+ -+ do { -+ if (dtrace_load8((uintptr_t)ps1++) != *ps2++) -+ return 1; -+ } while (--len != 0 && !(*flags & CPU_DTRACE_FAULT)); -+ } -+ -+ return 0; -+} -+ -+/* -+ * Zero the specified region using a simple byte-by-byte loop. Note that this -+ * is for safe DTrace-managed memory only. -+ */ -+void dtrace_bzero(void *dst, size_t len) -+{ -+ uchar_t *cp; -+ -+ for (cp = dst; len != 0; len--) -+ *cp++ = 0; -+} -+ -+#define DTRACE_DYNHASH_FREE 0 -+#define DTRACE_DYNHASH_SINK 1 -+#define DTRACE_DYNHASH_VALID 2 -+ -+/* -+ * Depending on the value of the op parameter, this function looks-up, -+ * allocates or deallocates an arbitrarily-keyed dynamic variable. If an -+ * allocation is requested, this function will return a pointer to a -+ * dtrace_dynvar_t corresponding to the allocated variable -- or NULL if no -+ * variable can be allocated. If NULL is returned, the appropriate counter -+ * will be incremented. -+ */ -+static struct dtrace_dynvar *dtrace_dynvar(struct dtrace_dstate *dstate, -+ uint_t nkeys, -+ struct dtrace_key *key, -+ size_t dsize, -+ enum dtrace_dynvar_op op, -+ struct dtrace_mstate *mstate, -+ struct dtrace_vstate *vstate) -+{ -+ uint64_t hashval = DTRACE_DYNHASH_VALID; -+ struct dtrace_dynhash *hash = dstate->dtds_hash; -+ struct dtrace_dynvar *free, *new_free, *next, *dvar, *start, -+ *prev = NULL; -+ processorid_t me = smp_processor_id(), cpu = me; -+ struct dtrace_dstate_percpu *dcpu = &dstate->dtds_percpu[me]; -+ size_t bucket, ksize; -+ size_t chunksize = dstate->dtds_chunksize; -+ uintptr_t kdata, lock; -+ enum dtrace_dstate_state nstate; -+ uint_t i; -+ -+ ASSERT(nkeys != 0); -+ -+ /* -+ * Hash the key. As with aggregations, we use Jenkins' "One-at-a-time" -+ * algorithm. For the by-value portions, we perform the algorithm in -+ * 16-bit chunks (as opposed to 8-bit chunks). This speeds things up a -+ * bit, and seems to have only a minute effect on distribution. For -+ * the by-reference data, we perform "One-at-a-time" iterating (safely) -+ * over each referenced byte. It's painful to do this, but it's much -+ * better than pathological hash distribution. The efficacy of the -+ * hashing algorithm (and a comparison with other algorithms) may be -+ * found by running the ::dtrace_dynstat MDB dcmd. -+ */ -+ for (i = 0; i < nkeys; i++) { -+ if (key[i].dttk_size == 0) { -+ uint64_t val = key[i].dttk_value; -+ -+ hashval += (val >> 48) & 0xffff; -+ hashval += (hashval << 10); -+ hashval ^= (hashval >> 6); -+ -+ hashval += (val >> 32) & 0xffff; -+ hashval += (hashval << 10); -+ hashval ^= (hashval >> 6); -+ -+ hashval += (val >> 16) & 0xffff; -+ hashval += (hashval << 10); -+ hashval ^= (hashval >> 6); -+ -+ hashval += val & 0xffff; -+ hashval += (hashval << 10); -+ hashval ^= (hashval >> 6); -+ } else { -+ /* -+ * This is incredibly painful, but it beats the hell -+ * out of the alternative. -+ */ -+ uint64_t j, size = key[i].dttk_size; -+ uintptr_t base = (uintptr_t)key[i].dttk_value; -+ -+ if (!dtrace_canload(base, size, mstate, vstate)) -+ break; -+ -+ for (j = 0; j < size; j++) { -+ hashval += dtrace_load8(base + j); -+ hashval += (hashval << 10); -+ hashval ^= (hashval >> 6); -+ } -+ } -+ } -+ -+ if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_FAULT)) -+ return NULL; -+ -+ hashval += (hashval << 3); -+ hashval ^= (hashval >> 11); -+ hashval += (hashval << 15); -+ -+ /* -+ * There is a remote chance (ideally, 1 in 2^31) that our hashval -+ * comes out to be one of our two sentinel hash values. If this -+ * actually happens, we set the hashval to be a value known to be a -+ * non-sentinel value. -+ */ -+ if (hashval == DTRACE_DYNHASH_FREE || hashval == DTRACE_DYNHASH_SINK) -+ hashval = DTRACE_DYNHASH_VALID; -+ -+ /* -+ * Yes, it's painful to do a divide here. If the cycle count becomes -+ * important here, tricks can be pulled to reduce it. (However, it's -+ * critical that hash collisions be kept to an absolute minimum; -+ * they're much more painful than a divide.) It's better to have a -+ * solution that generates few collisions and still keeps things -+ * relatively simple. -+ * -+ * Linux cannot do a straight 64-bit divide without gcc requiring -+ * linking in code that the kernel doesn't link, so we need to use an -+ * alternative. -+ * -+ * bucket = hashval % dstate->dtds_hashsize; -+ */ -+ { -+ uint64_t num; -+ -+ num = hashval; -+ bucket = do_div(num, dstate->dtds_hashsize); -+ } -+ -+ if (op == DTRACE_DYNVAR_DEALLOC) { -+ volatile uintptr_t *lockp = &hash[bucket].dtdh_lock; -+ -+ for (;;) { -+ while ((lock = *lockp) & 1) -+ continue; -+ -+ if (cmpxchg(lockp, lock, (lock + 1)) == lock) -+ break; -+ } -+ -+ dtrace_membar_producer(); -+ } -+ -+top: -+ prev = NULL; -+ lock = hash[bucket].dtdh_lock; -+ -+ dtrace_membar_consumer(); -+ -+ start = hash[bucket].dtdh_chain; -+ ASSERT(start != NULL && (start->dtdv_hashval == DTRACE_DYNHASH_SINK || -+ start->dtdv_hashval != DTRACE_DYNHASH_FREE || -+ op != DTRACE_DYNVAR_DEALLOC)); -+ -+ for (dvar = start; dvar != NULL; dvar = dvar->dtdv_next) { -+ struct dtrace_tuple *dtuple = &dvar->dtdv_tuple; -+ struct dtrace_key *dkey = &dtuple->dtt_key[0]; -+ -+ if (dvar->dtdv_hashval != hashval) { -+ if (dvar->dtdv_hashval == DTRACE_DYNHASH_SINK) { -+ /* -+ * We've reached the sink, and therefore the -+ * end of the hash chain; we can kick out of -+ * the loop knowing that we have seen a valid -+ * snapshot of state. -+ */ -+ ASSERT(dvar->dtdv_next == NULL); -+ ASSERT(dvar == &dtrace_dynhash_sink); -+ break; -+ } -+ -+ if (dvar->dtdv_hashval == DTRACE_DYNHASH_FREE) { -+ /* -+ * We've gone off the rails: somewhere along -+ * the line, one of the members of this hash -+ * chain was deleted. Note that we could also -+ * detect this by simply letting this loop run -+ * to completion, as we would eventually hit -+ * the end of the dirty list. However, we -+ * want to avoid running the length of the -+ * dirty list unnecessarily (it might be quite -+ * long), so we catch this as early as -+ * possible by detecting the hash marker. In -+ * this case, we simply set dvar to NULL and -+ * break; the conditional after the loop will -+ * send us back to top. -+ */ -+ dvar = NULL; -+ break; -+ } -+ -+ goto next; -+ } -+ -+ if (dtuple->dtt_nkeys != nkeys) -+ goto next; -+ -+ for (i = 0; i < nkeys; i++, dkey++) { -+ if (dkey->dttk_size != key[i].dttk_size) -+ goto next; /* size or type mismatch */ -+ -+ if (dkey->dttk_size != 0) { -+ if (dtrace_bcmp( -+ (void *)(uintptr_t)key[i].dttk_value, -+ (void *)(uintptr_t)dkey->dttk_value, -+ dkey->dttk_size)) -+ goto next; -+ } else { -+ if (dkey->dttk_value != key[i].dttk_value) -+ goto next; -+ } -+ } -+ -+ if (op != DTRACE_DYNVAR_DEALLOC) -+ return dvar; -+ -+ ASSERT(dvar->dtdv_next == NULL || -+ dvar->dtdv_next->dtdv_hashval != DTRACE_DYNHASH_FREE); -+ -+ if (prev != NULL) { -+ ASSERT(hash[bucket].dtdh_chain != dvar); -+ ASSERT(start != dvar); -+ ASSERT(prev->dtdv_next == dvar); -+ prev->dtdv_next = dvar->dtdv_next; -+ } else { -+ if (cmpxchg(&hash[bucket].dtdh_chain, start, -+ dvar->dtdv_next) != start) { -+ /* -+ * We have failed to atomically swing the -+ * hash table head pointer, presumably because -+ * of a conflicting allocation on another CPU. -+ * We need to reread the hash chain and try -+ * again. -+ */ -+ goto top; -+ } -+ } -+ -+ dtrace_membar_producer(); -+ -+ /* -+ * Now set the hash value to indicate that it's free. -+ */ -+ ASSERT(hash[bucket].dtdh_chain != dvar); -+ dvar->dtdv_hashval = DTRACE_DYNHASH_FREE; -+ -+ dtrace_membar_producer(); -+ -+ /* -+ * Set the next pointer to point at the dirty list, and -+ * atomically swing the dirty pointer to the newly freed dvar. -+ */ -+ do { -+ next = dcpu->dtdsc_dirty; -+ dvar->dtdv_next = next; -+ } while (cmpxchg(&dcpu->dtdsc_dirty, next, dvar) != next); -+ -+ /* -+ * Finally, unlock this hash bucket. -+ */ -+ ASSERT(hash[bucket].dtdh_lock == lock); -+ ASSERT(lock & 1); -+ hash[bucket].dtdh_lock++; -+ -+ return NULL; -+next: -+ prev = dvar; -+ continue; -+ } -+ -+ if (dvar == NULL) { -+ /* -+ * If dvar is NULL, it is because we went off the rails: -+ * one of the elements that we traversed in the hash chain -+ * was deleted while we were traversing it. In this case, -+ * we assert that we aren't doing a dealloc (deallocs lock -+ * the hash bucket to prevent themselves from racing with -+ * one another), and retry the hash chain traversal. -+ */ -+ ASSERT(op != DTRACE_DYNVAR_DEALLOC); -+ goto top; -+ } -+ -+ if (op != DTRACE_DYNVAR_ALLOC) { -+ /* -+ * If we are not to allocate a new variable, we want to -+ * return NULL now. Before we return, check that the value -+ * of the lock word hasn't changed. If it has, we may have -+ * seen an inconsistent snapshot. -+ */ -+ if (op == DTRACE_DYNVAR_NOALLOC) { -+ if (hash[bucket].dtdh_lock != lock) -+ goto top; -+ } else { -+ ASSERT(op == DTRACE_DYNVAR_DEALLOC); -+ ASSERT(hash[bucket].dtdh_lock == lock); -+ ASSERT(lock & 1); -+ hash[bucket].dtdh_lock++; -+ } -+ -+ return NULL; -+ } -+ -+ /* -+ * We need to allocate a new dynamic variable. The size we need is the -+ * size of dtrace_dynvar plus the size of nkeys dtrace_key_t's plus the -+ * size of any auxiliary key data (rounded up to 8-byte alignment) plus -+ * the size of any referred-to data (dsize). We then round the final -+ * size up to the chunksize for allocation. -+ */ -+ for (ksize = 0, i = 0; i < nkeys; i++) -+ ksize += P2ROUNDUP(key[i].dttk_size, sizeof(uint64_t)); -+ -+ /* -+ * This should be pretty much impossible, but could happen if, say, -+ * strange DIF specified the tuple. Ideally, this should be an -+ * assertion and not an error condition -- but that requires that the -+ * chunksize calculation in dtrace_difo_chunksize() be absolutely -+ * bullet-proof. (That is, it must not be able to be fooled by -+ * malicious DIF.) Given the lack of backwards branches in DIF, -+ * solving this would presumably not amount to solving the Halting -+ * Problem -- but it still seems awfully hard. -+ */ -+ if (sizeof(struct dtrace_dynvar) + -+ sizeof(struct dtrace_key) * (nkeys - 1) + -+ ksize + dsize > chunksize) { -+ dcpu->dtdsc_drops++; -+ return NULL; -+ } -+ -+ nstate = DTRACE_DSTATE_EMPTY; -+ -+ do { -+retry: -+ free = dcpu->dtdsc_free; -+ -+ if (free == NULL) { -+ struct dtrace_dynvar *clean = dcpu->dtdsc_clean; -+ void *rval; -+ -+ if (clean == NULL) { -+ /* -+ * We're out of dynamic variable space on -+ * this CPU. Unless we have tried all CPUs, -+ * we'll try to allocate from a different -+ * CPU. -+ */ -+ switch (dstate->dtds_state) { -+ case DTRACE_DSTATE_CLEAN: { -+ enum dtrace_dstate_state *sp = -+ (enum dtrace_dstate_state *) -+ &dstate->dtds_state; -+ -+ if (++cpu >= NR_CPUS) -+ cpu = 0; -+ -+ if (dcpu->dtdsc_dirty != NULL && -+ nstate == DTRACE_DSTATE_EMPTY) -+ nstate = DTRACE_DSTATE_DIRTY; -+ -+ if (dcpu->dtdsc_rinsing != NULL) -+ nstate = DTRACE_DSTATE_RINSING; -+ -+ dcpu = &dstate->dtds_percpu[cpu]; -+ -+ if (cpu != me) -+ goto retry; -+ -+ cmpxchg(sp, DTRACE_DSTATE_CLEAN, -+ nstate); -+ -+ /* -+ * To increment the correct bean -+ * counter, take another lap. -+ */ -+ goto retry; -+ } -+ -+ case DTRACE_DSTATE_DIRTY: -+ dcpu->dtdsc_dirty_drops++; -+ break; -+ -+ case DTRACE_DSTATE_RINSING: -+ dcpu->dtdsc_rinsing_drops++; -+ break; -+ -+ case DTRACE_DSTATE_EMPTY: -+ dcpu->dtdsc_drops++; -+ break; -+ } -+ -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_DROP); -+ return NULL; -+ } -+ -+ /* -+ * The clean list appears to be non-empty. We want to -+ * move the clean list to the free list; we start by -+ * moving the clean pointer aside. -+ */ -+ if (cmpxchg(&dcpu->dtdsc_clean, clean, NULL) != clean) -+ /* -+ * We are in one of two situations: -+ * -+ * (a) The clean list was switched to the -+ * free list by another CPU. -+ * -+ * (b) The clean list was added to by the -+ * cleansing cyclic. -+ * -+ * In either of these situations, we can -+ * just reattempt the free list allocation. -+ */ -+ goto retry; -+ -+ ASSERT(clean->dtdv_hashval == DTRACE_DYNHASH_FREE); -+ -+ /* -+ * Now we'll move the clean list to the free list. -+ * It's impossible for this to fail: the only way -+ * the free list can be updated is through this -+ * code path, and only one CPU can own the clean list. -+ * Thus, it would only be possible for this to fail if -+ * this code were racing with dtrace_dynvar_clean(). -+ * (That is, if dtrace_dynvar_clean() updated the clean -+ * list, and we ended up racing to update the free -+ * list.) This race is prevented by the dtrace_sync() -+ * in dtrace_dynvar_clean() -- which flushes the -+ * owners of the clean lists out before resetting -+ * the clean lists. -+ */ -+ rval = cmpxchg(&dcpu->dtdsc_free, NULL, clean); -+ ASSERT(rval == NULL); -+ -+ goto retry; -+ } -+ -+ dvar = free; -+ new_free = dvar->dtdv_next; -+ } while (cmpxchg(&dcpu->dtdsc_free, free, new_free) != free); -+ -+ /* -+ * We have now allocated a new chunk. We copy the tuple keys into the -+ * tuple array and copy any referenced key data into the data space -+ * following the tuple array. As we do this, we relocate dttk_value -+ * in the final tuple to point to the key data address in the chunk. -+ */ -+ kdata = (uintptr_t)&dvar->dtdv_tuple.dtt_key[nkeys]; -+ dvar->dtdv_data = (void *)(kdata + ksize); -+ dvar->dtdv_tuple.dtt_nkeys = nkeys; -+ -+ for (i = 0; i < nkeys; i++) { -+ struct dtrace_key *dkey = &dvar->dtdv_tuple.dtt_key[i]; -+ size_t kesize = key[i].dttk_size; -+ -+ if (kesize != 0) { -+ dtrace_bcopy( -+ (const void *)(uintptr_t)key[i].dttk_value, -+ (void *)kdata, kesize); -+ dkey->dttk_value = kdata; -+ kdata += P2ROUNDUP(kesize, sizeof(uint64_t)); -+ } else -+ dkey->dttk_value = key[i].dttk_value; -+ -+ dkey->dttk_size = kesize; -+ } -+ -+ ASSERT(dvar->dtdv_hashval == DTRACE_DYNHASH_FREE); -+ dvar->dtdv_hashval = hashval; -+ dvar->dtdv_next = start; -+ -+ if (cmpxchg(&hash[bucket].dtdh_chain, start, dvar) == start) -+ return dvar; -+ -+ /* -+ * The cas has failed. Either another CPU is adding an element to -+ * this hash chain, or another CPU is deleting an element from this -+ * hash chain. The simplest way to deal with both of these cases -+ * (though not necessarily the most efficient) is to free our -+ * allocated block and tail-call ourselves. Note that the free is -+ * to the dirty list and _not_ to the free list. This is to prevent -+ * races with allocators, above. -+ */ -+ dvar->dtdv_hashval = DTRACE_DYNHASH_FREE; -+ -+ dtrace_membar_producer(); -+ -+ do { -+ free = dcpu->dtdsc_dirty; -+ dvar->dtdv_next = free; -+ } while (cmpxchg(&dcpu->dtdsc_dirty, free, dvar) != free); -+ -+ return dtrace_dynvar(dstate, nkeys, key, dsize, op, mstate, vstate); -+} -+ -+/* -+ * Return a string. In the event that the user lacks the privilege to access -+ * arbitrary kernel memory, we copy the string out to scratch memory so that we -+ * don't fail access checking. -+ * -+ * dtrace_dif_variable() uses this routine as a helper for various -+ * builtin values such as 'execname' and 'probefunc.' -+ */ -+static uintptr_t dtrace_dif_varstr(uintptr_t addr, struct dtrace_state *state, -+ struct dtrace_mstate *mstate) -+{ -+ uint64_t size = state->dts_options[DTRACEOPT_STRSIZE]; -+ uintptr_t ret; -+ size_t strsz; -+ -+ /* -+ * The easy case: this probe is allowed to read all of memory, so -+ * we can just return this as a vanilla pointer. -+ */ -+ if ((mstate->dtms_access & DTRACE_ACCESS_KERNEL) != 0) -+ return addr; -+ -+ /* -+ * This is the tougher case: we copy the string in question from -+ * kernel memory into scratch memory and return it that way: this -+ * ensures that we won't trip up when access checking tests the -+ * BYREF return value. -+ */ -+ strsz = dtrace_strlen((char *)addr, size) + 1; -+ -+ if (mstate->dtms_scratch_ptr + strsz > -+ mstate->dtms_scratch_base + mstate->dtms_scratch_size) { -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); -+ return (uintptr_t)NULL; -+ } -+ -+ dtrace_strcpy((const void *)addr, (void *)mstate->dtms_scratch_ptr, -+ strsz); -+ ret = mstate->dtms_scratch_ptr; -+ mstate->dtms_scratch_ptr += strsz; -+ -+ return ret; -+} -+ -+/* -+ * This function implements the DIF emulator's variable lookups. The emulator -+ * passes a reserved variable identifier and optional built-in array index. -+ * -+ * This function is annotated to be always inlined in dtrace_dif_emulate() -+ * because (1) that is the only place where it is called from, and (2) it has -+ * come to our attention that some GCC versions inline it automatically while -+ * others do not and that messes up the number of frames to skip (aframes). -+ */ -+static __always_inline uint64_t dtrace_dif_variable(struct dtrace_mstate *mstate, -+ struct dtrace_state *state, -+ uint64_t v, uint64_t ndx) -+{ -+ /* -+ * If we're accessing one of the uncached arguments, we'll turn this -+ * into a reference in the args array. -+ */ -+ if (v >= DIF_VAR_ARG0 && v <= DIF_VAR_ARG9) { -+ ndx = v - DIF_VAR_ARG0; -+ v = DIF_VAR_ARGS; -+ } -+ -+ switch (v) { -+ case DIF_VAR_ARGS: -+ ASSERT(mstate->dtms_present & DTRACE_MSTATE_ARGS); -+ -+ if (ndx >= DTRACE_MSTATE_ARGS_MAX) { -+ int aframes = -+ mstate->dtms_probe->dtpr_aframes + 1; -+ struct dtrace_provider *pv; -+ uint64_t val; -+ -+ pv = mstate->dtms_probe->dtpr_provider; -+ if (pv->dtpv_pops.dtps_getargval != NULL) -+ val = pv->dtpv_pops.dtps_getargval( -+ pv->dtpv_arg, -+ mstate->dtms_probe->dtpr_id, -+ mstate->dtms_probe->dtpr_arg, -+ ndx, aframes); -+ else -+ val = dtrace_getarg(ndx, aframes); -+ -+ /* -+ * This is regrettably required to keep the compiler -+ * from tail-optimizing the call to dtrace_getarg(). -+ * The condition always evaluates to true, but the -+ * compiler has no way of figuring that out a priori. -+ * (None of this would be necessary if the compiler -+ * could be relied upon to _always_ tail-optimize -+ * the call to dtrace_getarg() -- but it can't.) -+ */ -+ if (mstate->dtms_probe != NULL) -+ return val; -+ -+ ASSERT(0); -+ } -+ -+ return mstate->dtms_arg[ndx]; -+ -+ case DIF_VAR_UREGS: { -+ if (!dtrace_priv_proc(state)) -+ return 0; -+ -+ return dtrace_getreg(current, ndx); -+ } -+ -+ case DIF_VAR_CURTHREAD: -+ if (!dtrace_priv_kernel(state)) -+ return 0; -+ -+ return (uint64_t)(uintptr_t)current; -+ -+ case DIF_VAR_TIMESTAMP: -+ if (!(mstate->dtms_present & DTRACE_MSTATE_TIMESTAMP)) { -+ mstate->dtms_timestamp = dtrace_gethrtime(); -+ mstate->dtms_present |= DTRACE_MSTATE_TIMESTAMP; -+ } -+ -+ return ktime_to_ns(mstate->dtms_timestamp); -+ -+ case DIF_VAR_WALLTIMESTAMP: -+ return ktime_to_ns(dtrace_get_walltime()); -+ -+ case DIF_VAR_VTIMESTAMP: -+ ASSERT(dtrace_vtime_references != 0); -+ -+ if (current->dt_task != NULL) -+ return ktime_to_ns(current->dt_task->dt_vtime); -+ -+ /* -+ * This is not ideal but without any data available -+ * there is no reasonable default value for vtimestamp -+ * variable. -+ */ -+ return ktime_to_ns(0); -+ -+ case DIF_VAR_IPL: -+ if (!dtrace_priv_kernel(state)) -+ return 0; -+ -+ if (!(mstate->dtms_present & DTRACE_MSTATE_IPL)) { -+ mstate->dtms_ipl = dtrace_getipl(); -+ mstate->dtms_present |= DTRACE_MSTATE_IPL; -+ } -+ -+ return mstate->dtms_ipl; -+ -+ case DIF_VAR_EPID: -+ ASSERT(mstate->dtms_present & DTRACE_MSTATE_EPID); -+ ASSERT(mstate->dtms_present & DTRACE_MSTATE_EPID); -+ -+ return mstate->dtms_epid; -+ -+ case DIF_VAR_ID: -+ ASSERT(mstate->dtms_present & DTRACE_MSTATE_PROBE); -+ return mstate->dtms_probe->dtpr_id; -+ -+ case DIF_VAR_STACKDEPTH: -+ if (!dtrace_priv_kernel(state)) -+ return 0; -+ if (!(mstate->dtms_present & DTRACE_MSTATE_STACKDEPTH)) { -+ int aframes = mstate->dtms_probe->dtpr_aframes + 2; -+ -+ mstate->dtms_stackdepth = dtrace_getstackdepth( -+ mstate, aframes); -+ mstate->dtms_present |= DTRACE_MSTATE_STACKDEPTH; -+ } -+ -+ return mstate->dtms_stackdepth; -+ -+ case DIF_VAR_USTACKDEPTH: -+ if (!dtrace_priv_proc(state)) -+ return 0; -+ -+ if (!(mstate->dtms_present & DTRACE_MSTATE_USTACKDEPTH)) { -+ /* -+ * See comment in DIF_VAR_PID. -+ */ -+ if (DTRACE_ANCHORED(mstate->dtms_probe) && -+ in_interrupt()) -+ mstate->dtms_ustackdepth = 0; -+ else -+ mstate->dtms_ustackdepth = -+ dtrace_getustackdepth(); -+ -+ mstate->dtms_present |= DTRACE_MSTATE_USTACKDEPTH; -+ } -+ -+ return mstate->dtms_ustackdepth; -+ -+ case DIF_VAR_CALLER: -+ if (!dtrace_priv_kernel(state)) -+ return 0; -+ -+ if (!(mstate->dtms_present & DTRACE_MSTATE_CALLER)) { -+ int aframes = mstate->dtms_probe->dtpr_aframes + 1; -+ -+ if (!DTRACE_ANCHORED(mstate->dtms_probe)) { -+ /* -+ * If this is an unanchored probe, we are -+ * required to go through the slow path: -+ * dtrace_caller() only guarantees correct -+ * results for anchored probes. -+ */ -+ uint64_t caller[2]; -+ -+ dtrace_getpcstack(caller, 2, aframes, -+ (uint32_t *)(uintptr_t) -+ mstate->dtms_arg[0]); -+ mstate->dtms_caller = caller[1]; -+ } else if ((mstate->dtms_caller = -+ dtrace_caller(aframes, 0)) == -1) { -+ /* -+ * We have failed to do this the quick way; -+ * we must resort to the slower approach of -+ * calling dtrace_getpcstack(). -+ */ -+ uint64_t caller; -+ -+ dtrace_getpcstack(&caller, 1, aframes, NULL); -+ mstate->dtms_caller = caller; -+ } -+ -+ mstate->dtms_present |= DTRACE_MSTATE_CALLER; -+ } -+ -+ return mstate->dtms_caller; -+ -+ case DIF_VAR_UCALLER: -+ if (!dtrace_priv_proc(state)) -+ return 0; -+ -+ if (!(mstate->dtms_present & DTRACE_MSTATE_UCALLER)) { -+ uint64_t ustack[4]; -+ -+ /* -+ * dtrace_getupcstack() fills in the first uint64_t with -+ * the current PID, and the second uint64_t with the -+ * current TGID. The third uint64_t will be the -+ * program counter at user-level. The fourth uint64_t -+ * will contain the caller, which is what we're after. -+ */ -+ ustack[3] = 0; -+ dtrace_getupcstack(ustack, 4); -+ -+ mstate->dtms_ucaller = ustack[3]; -+ mstate->dtms_present |= DTRACE_MSTATE_UCALLER; -+ } -+ -+ return mstate->dtms_ucaller; -+ -+ case DIF_VAR_PROBEPROV: -+ ASSERT(mstate->dtms_present & DTRACE_MSTATE_PROBE); -+ -+ return dtrace_dif_varstr( -+ (uintptr_t)mstate->dtms_probe->dtpr_provider->dtpv_name, -+ state, mstate); -+ -+ case DIF_VAR_PROBEMOD: -+ ASSERT(mstate->dtms_present & DTRACE_MSTATE_PROBE); -+ return dtrace_dif_varstr( -+ (uintptr_t)mstate->dtms_probe->dtpr_mod, state, -+ mstate); -+ -+ case DIF_VAR_PROBEFUNC: -+ ASSERT(mstate->dtms_present & DTRACE_MSTATE_PROBE); -+ -+ return dtrace_dif_varstr( -+ (uintptr_t)mstate->dtms_probe->dtpr_func, state, -+ mstate); -+ -+ case DIF_VAR_PROBENAME: -+ ASSERT(mstate->dtms_present & DTRACE_MSTATE_PROBE); -+ -+ return dtrace_dif_varstr( -+ (uintptr_t)mstate->dtms_probe->dtpr_name, state, -+ mstate); -+ -+ case DIF_VAR_PID: -+ if (!dtrace_priv_proc(state)) -+ return 0; -+ -+ /* -+ * It is always safe to dereference current, it always points -+ * to a valid task_struct. -+ */ -+ return (uint64_t)current->tgid; -+ -+ case DIF_VAR_PPID: -+ if (!dtrace_priv_proc(state)) -+ return 0; -+ -+ /* -+ * It is always safe to dereference current, it always points -+ * to a valid task_struct. -+ * -+ * Additionally, it is safe to dereference one's parent, since -+ * it is never NULL after process birth. -+ */ -+ return (uint64_t)current->real_parent->tgid; -+ -+ case DIF_VAR_TID: -+ return (uint64_t)current->pid; -+ -+ case DIF_VAR_EXECNAME: -+ if (!dtrace_priv_proc(state)) -+ return 0; -+ -+ /* -+ * It is always safe to dereference current, it always points -+ * to a valid task_struct. -+ */ -+ return dtrace_dif_varstr((uintptr_t)current->comm, state, -+ mstate); -+ -+ case DIF_VAR_ZONENAME: -+ return 0; -+ -+ case DIF_VAR_UID: -+ if (!dtrace_priv_proc(state)) -+ return 0; -+ -+ /* -+ * It is always safe to dereference current, it always points -+ * to a valid task_struct. -+ * -+ * Additionally, it is safe to dereference one's own process -+ * credential, since this is never NULL after process birth. -+ */ -+ return (uint64_t)from_kuid(current_user_ns(), -+ current_real_cred()->uid); -+ -+ case DIF_VAR_GID: -+ if (!dtrace_priv_proc(state)) -+ return 0; -+ -+ /* -+ * It is always safe to dereference current, it always points -+ * to a valid task_struct. -+ * -+ * Additionally, it is safe to dereference one's own process -+ * credential, since this is never NULL after process birth. -+ */ -+ return (uint64_t)from_kgid(current_user_ns(), -+ current_real_cred()->gid); -+ -+ case DIF_VAR_ERRNO: { -+ int64_t arg0; -+ -+ ASSERT(mstate->dtms_present & DTRACE_MSTATE_PROBE); -+ -+ if (!dtrace_priv_proc(state)) -+ return 0; -+ -+ /* -+ * We need to do some magic here to get the correct semantics -+ * for the 'errno' variable. It can only have a non-zero value -+ * when executing a system call, and for Linux, only after the -+ * actual system call implementation has completed, indicating -+ * in its return value either an error code (-2048 < errno < 0) -+ * or a valid result. So, the only time we can expect a valid -+ * value in errno is during the processing of any return probe -+ * in the syscall provider. In all other cases, it should have -+ * the value 0. -+ * -+ * So, we only look at probes that match: syscall:::return -+ */ -+ if (strncmp(mstate->dtms_probe->dtpr_provider->dtpv_name, -+ "syscall", 7) != 0) -+ return 0; -+ if (strncmp(mstate->dtms_probe->dtpr_name, "return", 6) != 0) -+ return 0; -+ -+ /* -+ * Error number is present if arg0 lies between 0 and -2048, -+ * exclusive. -+ */ -+ arg0 = (int64_t)mstate->dtms_arg[ndx]; -+ if (arg0 < 0 && arg0 > -2048) -+ return (uint64_t)-arg0; -+ -+ return 0; -+ } -+ -+ case DIF_VAR_CURCPU: -+ return (uint64_t)(uintptr_t)this_cpu_info; -+ -+ default: -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); -+ return 0; -+ } -+} -+ -+#define DTRACE_V4MAPPED_OFFSET (sizeof(uint32_t) * 3) -+ -+/* -+ * Emulate the execution of DTrace ID subroutines invoked by the call opcode. -+ * Notice that we don't bother validating the proper number of arguments or -+ * their types in the tuple stack. This isn't needed because all argument -+ * interpretation is safe because of our load safety -- the worst that can -+ * happen is that a bogus program can obtain bogus results. -+ */ -+static void dtrace_dif_subr(uint_t subr, uint_t rd, uint64_t *regs, -+ struct dtrace_key *tupregs, int nargs, -+ struct dtrace_mstate *mstate, -+ struct dtrace_state *state) -+{ -+ volatile uint16_t *flags = &this_cpu_core->cpuc_dtrace_flags; -+ volatile uintptr_t *illval = &this_cpu_core->cpuc_dtrace_illval; -+ struct dtrace_vstate *vstate = &state->dts_vstate; -+ struct mutex mtx; -+ -+ union { -+ rwlock_t ri; -+ uintptr_t rw; -+ } r; -+ -+ dt_dbg_dif(" Subroutine %d\n", subr); -+ -+ switch (subr) { -+ case DIF_SUBR_RAND: -+ regs[rd] = ktime_to_ns(dtrace_gethrtime()) * 2416 + 374441; -+ regs[rd] = do_div(regs[rd], 1771875); -+ break; -+ -+ case DIF_SUBR_MUTEX_OWNED: -+ if (!dtrace_canload(tupregs[0].dttk_value, -+ sizeof(struct mutex), mstate, vstate)) -+ break; -+ -+ dtrace_bcopy((const void *)(uintptr_t)tupregs[0].dttk_value, -+ &mtx, sizeof(struct mutex)); -+ if (*flags & CPU_DTRACE_FAULT) -+ break; -+ -+ regs[rd] = mutex_owned(&mtx); -+ break; -+ -+ case DIF_SUBR_MUTEX_OWNER: -+ regs[rd] = 0; -+ if (!dtrace_canload(tupregs[0].dttk_value, -+ sizeof(struct mutex), mstate, vstate)) -+ break; -+ -+ dtrace_bcopy((const void *)(uintptr_t)tupregs[0].dttk_value, -+ &mtx, sizeof(struct mutex)); -+ if (*flags & CPU_DTRACE_FAULT) -+ break; -+ -+#ifdef CONFIG_SMP -+ regs[rd] = (uintptr_t)__mutex_owner(&mtx); -+#else -+ regs[rd] = 0; -+#endif -+ break; -+ -+ case DIF_SUBR_MUTEX_TYPE_ADAPTIVE: -+ if (!dtrace_canload(tupregs[0].dttk_value, -+ sizeof(struct mutex), mstate, vstate)) { -+ regs[rd] = 0; -+ break; -+ } -+ -+ /* -+ * On Linux, all mutexes are adaptive. -+ */ -+ regs[rd] = 1; -+ break; -+ -+ case DIF_SUBR_MUTEX_TYPE_SPIN: -+ if (!dtrace_canload(tupregs[0].dttk_value, -+ sizeof(struct mutex), mstate, vstate)) { -+ regs[rd] = 0; -+ break; -+ } -+ -+ /* -+ * On Linux, all mutexes are adaptive. -+ */ -+ regs[rd] = 0; -+ break; -+ -+ case DIF_SUBR_RW_READ_HELD: { -+ if (!dtrace_canload(tupregs[0].dttk_value, sizeof(rwlock_t), -+ mstate, vstate)) { -+ regs[rd] = 0; -+ break; -+ } -+ -+ r.rw = dtrace_loadptr(tupregs[0].dttk_value); -+ regs[rd] = !peek_write_can_lock(&r.ri) && -+ peek_read_can_lock(&r.ri); -+ break; -+ } -+ -+ case DIF_SUBR_RW_WRITE_HELD: -+ if (!dtrace_canload(tupregs[0].dttk_value, sizeof(rwlock_t), -+ mstate, vstate)) { -+ regs[rd] = 0; -+ break; -+ } -+ -+ r.rw = dtrace_loadptr(tupregs[0].dttk_value); -+ regs[rd] = !peek_write_can_lock(&r.ri); -+ break; -+ -+ case DIF_SUBR_RW_ISWRITER: -+ if (!dtrace_canload(tupregs[0].dttk_value, sizeof(rwlock_t), -+ mstate, vstate)) { -+ regs[rd] = 0; -+ break; -+ } -+ -+ r.rw = dtrace_loadptr(tupregs[0].dttk_value); -+ /* -+ * On Linux there is no way to determine whether someone is -+ * trying to acquire a write lock. -+ */ -+ regs[rd] = !peek_write_can_lock(&r.ri); -+ break; -+ -+ case DIF_SUBR_BCOPY: { -+ /* -+ * We need to be sure that the destination is in the scratch -+ * region -- no other region is allowed. -+ */ -+ uintptr_t src = tupregs[0].dttk_value; -+ uintptr_t dest = tupregs[1].dttk_value; -+ size_t size = tupregs[2].dttk_value; -+ -+ if (!dtrace_inscratch(dest, size, mstate)) { -+ *flags |= CPU_DTRACE_BADADDR; -+ *illval = regs[rd]; -+ break; -+ } -+ -+ if (!dtrace_canload(src, size, mstate, vstate)) { -+ regs[rd] = 0; -+ break; -+ } -+ -+ dtrace_bcopy((void *)src, (void *)dest, size); -+ break; -+ } -+ -+ case DIF_SUBR_ALLOCA: -+ case DIF_SUBR_COPYIN: { -+ uintptr_t dest = P2ROUNDUP(mstate->dtms_scratch_ptr, 8); -+ uint64_t size; -+ size_t scratch_size; -+ -+ size = tupregs[subr == DIF_SUBR_ALLOCA ? 0 : 1].dttk_value; -+ scratch_size = (dest - mstate->dtms_scratch_ptr) + size; -+ -+ /* -+ * This action doesn't require any credential checks since -+ * probes will not activate in user contexts to which the -+ * enabling user does not have permissions. -+ */ -+ -+ /* -+ * Rounding up the user allocation size could have overflowed -+ * a large, bogus allocation (like -1ULL) to 0. -+ */ -+ if (scratch_size < size || -+ !DTRACE_INSCRATCH(mstate, scratch_size)) { -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); -+ regs[rd] = 0; -+ break; -+ } -+ -+ if (subr == DIF_SUBR_COPYIN) { -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); -+ dtrace_copyin(tupregs[0].dttk_value, dest, size, flags); -+ DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); -+ } -+ -+ mstate->dtms_scratch_ptr += scratch_size; -+ regs[rd] = dest; -+ break; -+ } -+ -+ case DIF_SUBR_COPYINTO: { -+ uint64_t size = tupregs[1].dttk_value; -+ uintptr_t dest = tupregs[2].dttk_value; -+ -+ /* -+ * This action doesn't require any credential checks since -+ * probes will not activate in user contexts to which the -+ * enabling user does not have permissions. -+ */ -+ if (!dtrace_inscratch(dest, size, mstate)) { -+ *flags |= CPU_DTRACE_BADADDR; -+ *illval = regs[rd]; -+ break; -+ } -+ -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); -+ dtrace_copyin(tupregs[0].dttk_value, dest, size, flags); -+ DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); -+ break; -+ } -+ -+ case DIF_SUBR_COPYINSTR: { -+ uintptr_t dest = mstate->dtms_scratch_ptr; -+ uint64_t size = state->dts_options[DTRACEOPT_STRSIZE]; -+ -+ if (nargs > 1 && tupregs[1].dttk_value < size) -+ size = tupregs[1].dttk_value + 1; -+ -+ /* -+ * This action doesn't require any credential checks since -+ * probes will not activate in user contexts to which the -+ * enabling user does not have permissions. -+ */ -+ if (!DTRACE_INSCRATCH(mstate, size)) { -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); -+ regs[rd] = 0; -+ break; -+ } -+ -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); -+ dtrace_copyinstr(tupregs[0].dttk_value, dest, size, flags); -+ DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); -+ -+ ((char *)dest)[size - 1] = '\0'; -+ mstate->dtms_scratch_ptr += size; -+ regs[rd] = dest; -+ break; -+ } -+ -+#if 0 /* FIXME */ -+ case DIF_SUBR_MSGSIZE: -+ case DIF_SUBR_MSGDSIZE: { -+ uintptr_t baddr = tupregs[0].dttk_value, daddr; -+ uintptr_t wptr, rptr; -+ size_t count = 0; -+ int cont = 0; -+ -+ while (baddr != NULL && !(*flags & CPU_DTRACE_FAULT)) { -+ -+ if (!dtrace_canload(baddr, sizeof(mblk_t), mstate, -+ vstate)) { -+ regs[rd] = 0; -+ break; -+ } -+ -+ wptr = dtrace_loadptr(baddr + -+ offsetof(mblk_t, b_wptr)); -+ -+ rptr = dtrace_loadptr(baddr + -+ offsetof(mblk_t, b_rptr)); -+ -+ if (wptr < rptr) { -+ *flags |= CPU_DTRACE_BADADDR; -+ *illval = tupregs[0].dttk_value; -+ break; -+ } -+ -+ daddr = dtrace_loadptr(baddr + -+ offsetof(mblk_t, b_datap)); -+ -+ baddr = dtrace_loadptr(baddr + -+ offsetof(mblk_t, b_cont)); -+ -+ /* -+ * We want to prevent against denial-of-service here, -+ * so we're only going to search the list for -+ * dtrace_msgdsize_max mblks. -+ */ -+ if (cont++ > dtrace_msgdsize_max) { -+ *flags |= CPU_DTRACE_ILLOP; -+ break; -+ } -+ -+ if (subr == DIF_SUBR_MSGDSIZE) { -+ if (dtrace_load8(daddr + -+ offsetof(dblk_t, db_type)) != M_DATA) -+ continue; -+ } -+ -+ count += wptr - rptr; -+ } -+ -+ if (!(*flags & CPU_DTRACE_FAULT)) -+ regs[rd] = count; -+ -+ break; -+ } -+#endif -+ -+ case DIF_SUBR_PROGENYOF: { -+ pid_t pid = tupregs[0].dttk_value; -+ struct task_struct *p; -+ int rval = 0; -+ -+ for (p = current; p != NULL; p = p->real_parent) { -+ if (p->pid == pid) { -+ rval = 1; -+ break; -+ } -+ -+ if (p == p->real_parent) -+ break; -+ } -+ -+ regs[rd] = rval; -+ break; -+ } -+ -+ case DIF_SUBR_SPECULATION: -+ regs[rd] = dtrace_speculation(state); -+ break; -+ -+ case DIF_SUBR_COPYOUT: { -+ uintptr_t kaddr = tupregs[0].dttk_value; -+ uintptr_t uaddr = tupregs[1].dttk_value; -+ uint64_t size = tupregs[2].dttk_value; -+ -+ if (!dtrace_destructive_disallow && -+ dtrace_priv_proc_control(state) && -+ !dtrace_istoxic(kaddr, size) && -+ dtrace_canload(kaddr, size, mstate, vstate)) { -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); -+ dtrace_copyout(kaddr, uaddr, size, flags); -+ DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); -+ } -+ break; -+ } -+ -+ case DIF_SUBR_COPYOUTSTR: { -+ uintptr_t kaddr = tupregs[0].dttk_value; -+ uintptr_t uaddr = tupregs[1].dttk_value; -+ uint64_t size = tupregs[2].dttk_value; -+ -+ if (!dtrace_destructive_disallow && -+ dtrace_priv_proc_control(state) && -+ !dtrace_istoxic(kaddr, size) && -+ dtrace_strcanload(kaddr, size, mstate, vstate)) { -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); -+ dtrace_copyoutstr(kaddr, uaddr, size, flags); -+ DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); -+ } -+ break; -+ } -+ -+ case DIF_SUBR_STRLEN: { -+ size_t sz; -+ uintptr_t addr = (uintptr_t)tupregs[0].dttk_value; -+ -+ sz = dtrace_strlen((char *)addr, -+ state->dts_options[DTRACEOPT_STRSIZE]); -+ -+ if (!dtrace_canload(addr, sz + 1, mstate, vstate)) { -+ regs[rd] = 0; -+ break; -+ } -+ -+ regs[rd] = sz; -+ -+ break; -+ } -+ -+ case DIF_SUBR_STRCHR: -+ case DIF_SUBR_STRRCHR: { -+ /* -+ * We're going to iterate over the string looking for the -+ * specified character. We will iterate until we have reached -+ * the string length or we have found the character. If this -+ * is DIF_SUBR_STRRCHR, we will look for the last occurrence -+ * of the specified character instead of the first. -+ */ -+ uintptr_t saddr = tupregs[0].dttk_value; -+ uintptr_t addr = tupregs[0].dttk_value; -+ uintptr_t limit = addr + -+ state->dts_options[DTRACEOPT_STRSIZE]; -+ char c, target = (char)tupregs[1].dttk_value; -+ -+ for (regs[rd] = 0; addr < limit; addr++) { -+ c = dtrace_load8(addr); -+ if (c == target) { -+ regs[rd] = addr; -+ -+ if (subr == DIF_SUBR_STRCHR) -+ break; -+ } -+ -+ if (c == '\0') -+ break; -+ } -+ -+ if (!dtrace_canload(saddr, addr - saddr, mstate, vstate)) { -+ regs[rd] = 0; -+ break; -+ } -+ -+ break; -+ } -+ -+ case DIF_SUBR_STRSTR: -+ case DIF_SUBR_INDEX: -+ case DIF_SUBR_RINDEX: { -+ /* -+ * We're going to iterate over the string looking for the -+ * specified string. We will iterate until we have reached -+ * the string length or we have found the string. (Yes, this -+ * is done in the most naive way possible -- but considering -+ * that the string we're searching for is likely to be -+ * relatively short, the complexity of Rabin-Karp or similar -+ * hardly seems merited.) -+ */ -+ char *addr = (char *)(uintptr_t) -+ tupregs[0].dttk_value; -+ char *substr = (char *)(uintptr_t) -+ tupregs[1].dttk_value; -+ uint64_t size = state->dts_options[DTRACEOPT_STRSIZE]; -+ size_t len = dtrace_strlen(addr, size); -+ size_t sublen = dtrace_strlen(substr, size); -+ char *limit = addr + len, *orig = addr; -+ int notfound = subr == DIF_SUBR_STRSTR ? 0 : -1; -+ int inc = 1; -+ -+ regs[rd] = notfound; -+ -+ if (!dtrace_canload((uintptr_t)addr, len + 1, mstate, vstate)) { -+ regs[rd] = 0; -+ break; -+ } -+ -+ if (!dtrace_canload((uintptr_t)substr, sublen + 1, mstate, -+ vstate)) { -+ regs[rd] = 0; -+ break; -+ } -+ -+ /* -+ * strstr() and index()/rindex() have similar semantics if -+ * both strings are the empty string: strstr() returns a -+ * pointer to the (empty) string, and index() and rindex() -+ * both return index 0 (regardless of any position argument). -+ */ -+ if (sublen == 0 && len == 0) { -+ if (subr == DIF_SUBR_STRSTR) -+ regs[rd] = (uintptr_t)addr; -+ else -+ regs[rd] = 0; -+ break; -+ } -+ -+ if (subr != DIF_SUBR_STRSTR) { -+ if (subr == DIF_SUBR_RINDEX) { -+ limit = orig - 1; -+ addr += len; -+ inc = -1; -+ } -+ -+ /* -+ * Both index() and rindex() take an optional position -+ * argument that denotes the starting position. -+ */ -+ if (nargs == 3) { -+ int64_t pos = (int64_t)tupregs[2].dttk_value; -+ -+ /* -+ * If the position argument to index() is -+ * negative, Perl implicitly clamps it at -+ * zero. This semantic is a little surprising -+ * given the special meaning of negative -+ * positions to similar Perl functions like -+ * substr(), but it appears to reflect a -+ * notion that index() can start from a -+ * negative index and increment its way up to -+ * the string. Given this notion, Perl's -+ * rindex() is at least self-consistent in -+ * that it implicitly clamps positions greater -+ * than the string length to be the string -+ * length. Where Perl completely loses -+ * coherence, however, is when the specified -+ * substring is the empty string (""). In -+ * this case, even if the position is -+ * negative, rindex() returns 0 -- and even if -+ * the position is greater than the length, -+ * index() returns the string length. These -+ * semantics violate the notion that index() -+ * should never return a value less than the -+ * specified position and that rindex() should -+ * never return a value greater than the -+ * specified position. (One assumes that -+ * these semantics are artifacts of Perl's -+ * implementation and not the results of -+ * deliberate design -- it beggars belief that -+ * even Larry Wall could desire such oddness.) -+ * While in the abstract one would wish for -+ * consistent position semantics across -+ * substr(), index() and rindex() -- or at the -+ * very least self-consistent position -+ * semantics for index() and rindex() -- we -+ * instead opt to keep with the extant Perl -+ * semantics, in all their broken glory. (Do -+ * we have more desire to maintain Perl's -+ * semantics than Perl does? Probably.) -+ */ -+ if (subr == DIF_SUBR_RINDEX) { -+ if (pos < 0) { -+ if (sublen == 0) -+ regs[rd] = 0; -+ break; -+ } -+ -+ if (pos > len) -+ pos = len; -+ } else { -+ if (pos < 0) -+ pos = 0; -+ -+ if (pos >= len) { -+ if (sublen == 0) -+ regs[rd] = len; -+ break; -+ } -+ } -+ -+ addr = orig + pos; -+ } -+ } -+ -+ for (regs[rd] = notfound; addr != limit; addr += inc) { -+ if (dtrace_strncmp(addr, substr, sublen) == 0) { -+ if (subr != DIF_SUBR_STRSTR) { -+ /* -+ * As D index() and rindex() are -+ * modeled on Perl (and not on awk), -+ * we return a zero-based (and not a -+ * one-based) index. (For you Perl -+ * weenies: no, we're not going to add -+ * $[ -- and shouldn't you be at a con -+ * or something?) -+ */ -+ regs[rd] = (uintptr_t)(addr - orig); -+ break; -+ } -+ -+ ASSERT(subr == DIF_SUBR_STRSTR); -+ regs[rd] = (uintptr_t)addr; -+ break; -+ } -+ } -+ -+ break; -+ } -+ -+ case DIF_SUBR_STRTOK: { -+ uintptr_t addr = tupregs[0].dttk_value; -+ uintptr_t tokaddr = tupregs[1].dttk_value; -+ uint64_t size = state->dts_options[DTRACEOPT_STRSIZE]; -+ uintptr_t limit, toklimit = tokaddr + size; -+ uint8_t c = 0, tokmap[32]; /* 256 / 8 */ -+ char *dest = (char *)mstate->dtms_scratch_ptr; -+ int i; -+ -+ /* -+ * Check both the token buffer and (later) the input buffer, -+ * since both could be non-scratch addresses. -+ */ -+ if (!dtrace_strcanload(tokaddr, size, mstate, vstate)) { -+ regs[rd] = 0; -+ break; -+ } -+ -+ if (!DTRACE_INSCRATCH(mstate, size)) { -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); -+ regs[rd] = 0; -+ break; -+ } -+ -+ if (addr == (uintptr_t)NULL) { -+ /* -+ * If the address specified is NULL, we use our saved -+ * strtok pointer from the mstate. Note that this -+ * means that the saved strtok pointer is _only_ -+ * valid within multiple enablings of the same probe -- -+ * it behaves like an implicit clause-local variable. -+ */ -+ addr = mstate->dtms_strtok; -+ } else { -+ /* -+ * If the user-specified address is non-NULL we must -+ * access check it. This is the only time we have -+ * a chance to do so, since this address may reside -+ * in the string table of this clause-- future calls -+ * (when we fetch addr from mstate->dtms_strtok) -+ * would fail this access check. -+ */ -+ if (!dtrace_strcanload(addr, size, mstate, vstate)) { -+ regs[rd] = 0; -+ break; -+ } -+ } -+ -+ /* -+ * First, zero the token map, and then process the token -+ * string -- setting a bit in the map for every character -+ * found in the token string. -+ */ -+ for (i = 0; i < sizeof(tokmap); i++) -+ tokmap[i] = 0; -+ -+ for (; tokaddr < toklimit; tokaddr++) { -+ c = dtrace_load8(tokaddr); -+ if (c == '\0') -+ break; -+ -+ ASSERT((c >> 3) < sizeof(tokmap)); -+ tokmap[c >> 3] |= (1 << (c & 0x7)); -+ } -+ -+ for (limit = addr + size; addr < limit; addr++) { -+ /* -+ * We're looking for a character that is _not_ contained -+ * in the token string. -+ */ -+ c = dtrace_load8(addr); -+ if (c == '\0') -+ break; -+ -+ if (!(tokmap[c >> 3] & (1 << (c & 0x7)))) -+ break; -+ } -+ -+ if (c == '\0') { -+ /* -+ * We reached the end of the string without finding -+ * any character that was not in the token string. -+ * We return NULL in this case, and we set the saved -+ * address to NULL as well. -+ */ -+ regs[rd] = 0; -+ mstate->dtms_strtok = (uintptr_t)NULL; -+ break; -+ } -+ -+ /* -+ * From here on, we're copying into the destination string. -+ */ -+ for (i = 0; addr < limit && i < size - 1; addr++) { -+ c = dtrace_load8(addr); -+ if (c == '\0') -+ break; -+ -+ if (tokmap[c >> 3] & (1 << (c & 0x7))) -+ break; -+ -+ ASSERT(i < size); -+ dest[i++] = c; -+ } -+ -+ ASSERT(i < size); -+ dest[i] = '\0'; -+ regs[rd] = (uintptr_t)dest; -+ mstate->dtms_scratch_ptr += size; -+ mstate->dtms_strtok = addr; -+ break; -+ } -+ -+ case DIF_SUBR_SUBSTR: { -+ uintptr_t s = tupregs[0].dttk_value; -+ uint64_t size = state->dts_options[DTRACEOPT_STRSIZE]; -+ char *d = (char *)mstate->dtms_scratch_ptr; -+ int64_t index = (int64_t)tupregs[1].dttk_value; -+ int64_t remaining = (int64_t)tupregs[2].dttk_value; -+ size_t len = dtrace_strlen((char *)s, size); -+ int64_t i = 0; -+ -+ if (!dtrace_canload(s, len + 1, mstate, vstate)) { -+ regs[rd] = 0; -+ break; -+ } -+ -+ if (!DTRACE_INSCRATCH(mstate, size)) { -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); -+ regs[rd] = 0; -+ break; -+ } -+ -+ if (nargs <= 2) -+ remaining = (int64_t)size; -+ -+ if (index < 0) { -+ index += len; -+ -+ if (index < 0 && index + remaining > 0) { -+ remaining += index; -+ index = 0; -+ } -+ } -+ -+ if (index >= len || index < 0) -+ remaining = 0; -+ else if (remaining < 0) -+ remaining += len - index; -+ else if (index + remaining > size) -+ remaining = size - index; -+ -+ for (i = 0; i < remaining; i++) { -+ d[i] = dtrace_load8(s + index + i); -+ if (d[i] == '\0') -+ break; -+ } -+ -+ d[i] = '\0'; -+ -+ mstate->dtms_scratch_ptr += size; -+ regs[rd] = (uintptr_t)d; -+ break; -+ } -+ -+ case DIF_SUBR_GETMAJOR: -+ regs[rd] = MAJOR(tupregs[0].dttk_value); -+ break; -+ -+ case DIF_SUBR_GETMINOR: -+ regs[rd] = MINOR(tupregs[0].dttk_value); -+ break; -+ -+#if 0 /* FIXME */ -+ case DIF_SUBR_DDI_PATHNAME: { -+ /* -+ * This one is a galactic mess. We are going to roughly -+ * emulate ddi_pathname(), but it's made more complicated -+ * by the fact that we (a) want to include the minor name and -+ * (b) must proceed iteratively instead of recursively. -+ */ -+ uintptr_t dest = mstate->dtms_scratch_ptr; -+ uint64_t size = state->dts_options[DTRACEOPT_STRSIZE]; -+ char *start = (char *)dest, *end = start + size - 1; -+ uintptr_t daddr = tupregs[0].dttk_value; -+ int64_t minor = (int64_t)tupregs[1].dttk_value; -+ char *s; -+ int i, len, depth = 0; -+ -+ /* -+ * Due to all the pointer jumping we do and context we must -+ * rely upon, we just mandate that the user must have kernel -+ * read privileges to use this routine. -+ */ -+ if ((mstate->dtms_access & DTRACE_ACCESS_KERNEL) == 0) { -+ *flags |= CPU_DTRACE_KPRIV; -+ *illval = daddr; -+ regs[rd] = 0; -+ } -+ -+ if (!DTRACE_INSCRATCH(mstate, size)) { -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); -+ regs[rd] = 0; -+ break; -+ } -+ -+ *end = '\0'; -+ -+ /* -+ * We want to have a name for the minor. In order to do this, -+ * we need to walk the minor list from the devinfo. We want -+ * to be sure that we don't infinitely walk a circular list, -+ * so we check for circularity by sending a scout pointer -+ * ahead two elements for every element that we iterate over; -+ * if the list is circular, these will ultimately point to the -+ * same element. You may recognize this little trick as the -+ * answer to a stupid interview question -- one that always -+ * seems to be asked by those who had to have it laboriously -+ * explained to them, and who can't even concisely describe -+ * the conditions under which one would be forced to resort to -+ * this technique. Needless to say, those conditions are -+ * found here -- and probably only here. Is this the only use -+ * of this infamous trick in shipping, production code? If it -+ * isn't, it probably should be... -+ */ -+ if (minor != -1) { -+ uintptr_t maddr = dtrace_loadptr(daddr + -+ offsetof(struct dev_info, devi_minor)); -+ -+ uintptr_t next = offsetof(struct ddi_minor_data, next); -+ uintptr_t name = offsetof(struct ddi_minor_data, -+ d_minor) + offsetof(struct ddi_minor, name); -+ uintptr_t dev = offsetof(struct ddi_minor_data, -+ d_minor) + offsetof(struct ddi_minor, dev); -+ uintptr_t scout; -+ -+ if (maddr != NULL) -+ scout = dtrace_loadptr(maddr + next); -+ -+ while (maddr != NULL && !(*flags & CPU_DTRACE_FAULT)) { -+ uint64_t m; -+#ifdef _LP64 -+ m = dtrace_load64(maddr + dev) & MAXMIN64; -+#else -+ m = dtrace_load32(maddr + dev) & MAXMIN; -+#endif -+ if (m != minor) { -+ maddr = dtrace_loadptr(maddr + next); -+ -+ if (scout == NULL) -+ continue; -+ -+ scout = dtrace_loadptr(scout + next); -+ -+ if (scout == NULL) -+ continue; -+ -+ scout = dtrace_loadptr(scout + next); -+ -+ if (scout == NULL) -+ continue; -+ -+ if (scout == maddr) { -+ *flags |= CPU_DTRACE_ILLOP; -+ break; -+ } -+ -+ continue; -+ } -+ -+ /* -+ * We have the minor data. Now we need to -+ * copy the minor's name into the end of the -+ * pathname. -+ */ -+ s = (char *)dtrace_loadptr(maddr + name); -+ len = dtrace_strlen(s, size); -+ -+ if (*flags & CPU_DTRACE_FAULT) -+ break; -+ -+ if (len != 0) { -+ end -= len + 1; -+ if (end < start) -+ break; -+ -+ *end = ':'; -+ } -+ -+ for (i = 1; i <= len; i++) -+ end[i] = dtrace_load8((uintptr_t)s++); -+ break; -+ } -+ } -+ -+ while (daddr != NULL && !(*flags & CPU_DTRACE_FAULT)) { -+ ddi_node_state_t devi_state; -+ -+ devi_state = dtrace_load32(daddr + -+ offsetof(struct dev_info, devi_node_state)); -+ -+ if (*flags & CPU_DTRACE_FAULT) -+ break; -+ -+ if (devi_state >= DS_INITIALIZED) { -+ s = (char *)dtrace_loadptr(daddr + -+ offsetof(struct dev_info, devi_addr)); -+ len = dtrace_strlen(s, size); -+ -+ if (*flags & CPU_DTRACE_FAULT) -+ break; -+ -+ if (len != 0) { -+ end -= len + 1; -+ if (end < start) -+ break; -+ -+ *end = '@'; -+ } -+ -+ for (i = 1; i <= len; i++) -+ end[i] = dtrace_load8((uintptr_t)s++); -+ } -+ -+ /* -+ * Now for the node name... -+ */ -+ s = (char *)dtrace_loadptr(daddr + -+ offsetof(struct dev_info, devi_node_name)); -+ -+ daddr = dtrace_loadptr(daddr + -+ offsetof(struct dev_info, devi_parent)); -+ -+ /* -+ * If our parent is NULL (that is, if we're the root -+ * node), we're going to use the special path -+ * "devices". -+ */ -+ if (daddr == NULL) -+ s = "devices"; -+ -+ len = dtrace_strlen(s, size); -+ if (*flags & CPU_DTRACE_FAULT) -+ break; -+ -+ end -= len + 1; -+ if (end < start) -+ break; -+ -+ for (i = 1; i <= len; i++) -+ end[i] = dtrace_load8((uintptr_t)s++); -+ *end = '/'; -+ -+ if (depth++ > dtrace_devdepth_max) { -+ *flags |= CPU_DTRACE_ILLOP; -+ break; -+ } -+ } -+ -+ if (end < start) -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); -+ -+ if (daddr == NULL) { -+ regs[rd] = (uintptr_t)end; -+ mstate->dtms_scratch_ptr += size; -+ } -+ -+ break; -+ } -+#endif -+ -+ case DIF_SUBR_STRJOIN: { -+ char *d = (char *)mstate->dtms_scratch_ptr; -+ uint64_t size = state->dts_options[DTRACEOPT_STRSIZE]; -+ uintptr_t s1 = tupregs[0].dttk_value; -+ uintptr_t s2 = tupregs[1].dttk_value; -+ int i = 0; -+ -+ if (!dtrace_strcanload(s1, size, mstate, vstate) || -+ !dtrace_strcanload(s2, size, mstate, vstate)) { -+ regs[rd] = 0; -+ break; -+ } -+ -+ if (!DTRACE_INSCRATCH(mstate, size)) { -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); -+ regs[rd] = 0; -+ break; -+ } -+ -+ for (;;) { -+ if (i >= size) { -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); -+ regs[rd] = 0; -+ break; -+ } -+ -+ d[i] = dtrace_load8(s1++); -+ if ((d[i++]) == '\0') { -+ i--; -+ break; -+ } -+ } -+ -+ for (;;) { -+ if (i >= size) { -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); -+ regs[rd] = 0; -+ break; -+ } -+ -+ d[i] = dtrace_load8(s2++); -+ if ((d[i++]) == '\0') -+ break; -+ } -+ -+ if (i < size) { -+ mstate->dtms_scratch_ptr += i; -+ regs[rd] = (uintptr_t)d; -+ } -+ -+ break; -+ } -+ -+ case DIF_SUBR_LLTOSTR: { -+ int64_t i = (int64_t)tupregs[0].dttk_value; -+ int64_t val = i < 0 ? i * -1 : i; -+ uint64_t size = 22; /* room for 2^64 in dec */ -+ char *end = (char *)mstate->dtms_scratch_ptr + size -+ - 1; -+ -+ if (!DTRACE_INSCRATCH(mstate, size)) { -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); -+ regs[rd] = 0; -+ break; -+ } -+ -+ /* -+ * GCC on Linux introduces calls to functions that are not -+ * linked into the kernel image, so we need to use the do_div() -+ * function instead. It modifies the first argument in place -+ * (replaces it with the quotient), and returns the remainder. -+ * -+ * Was: -+ * for (*end-- = '\0'; val; val /= 10) -+ * *end-- = '0' + (val % 10); -+ */ -+ for (*end-- = '\0'; val; ) -+ *end-- = '0' + do_div(val, 10); -+ -+ if (i == 0) -+ *end-- = '0'; -+ -+ if (i < 0) -+ *end-- = '-'; -+ -+ regs[rd] = (uintptr_t)end + 1; -+ mstate->dtms_scratch_ptr += size; -+ break; -+ } -+ -+ case DIF_SUBR_HTONS: -+ case DIF_SUBR_NTOHS: -+#ifdef __BIG_ENDIAN -+ regs[rd] = (uint16_t)tupregs[0].dttk_value; -+#else -+ regs[rd] = DT_BSWAP_16((uint16_t)tupregs[0].dttk_value); -+#endif -+ break; -+ -+ -+ case DIF_SUBR_HTONL: -+ case DIF_SUBR_NTOHL: -+#ifdef __BIG_ENDIAN -+ regs[rd] = (uint32_t)tupregs[0].dttk_value; -+#else -+ regs[rd] = DT_BSWAP_32((uint32_t)tupregs[0].dttk_value); -+#endif -+ break; -+ -+ -+ case DIF_SUBR_HTONLL: -+ case DIF_SUBR_NTOHLL: -+#ifdef __BIG_ENDIAN -+ regs[rd] = (uint64_t)tupregs[0].dttk_value; -+#else -+ regs[rd] = DT_BSWAP_64((uint64_t)tupregs[0].dttk_value); -+#endif -+ break; -+ -+ -+ case DIF_SUBR_DIRNAME: -+ case DIF_SUBR_BASENAME: { -+ char *dest = (char *)mstate->dtms_scratch_ptr; -+ uint64_t size = state->dts_options[DTRACEOPT_STRSIZE]; -+ uintptr_t src = tupregs[0].dttk_value; -+ int i, j, len = dtrace_strlen((char *)src, size); -+ int lastbase = -1, firstbase = -1, lastdir = -1; -+ int start, end; -+ -+ if (!dtrace_canload(src, len + 1, mstate, vstate)) { -+ regs[rd] = 0; -+ break; -+ } -+ -+ if (!DTRACE_INSCRATCH(mstate, size)) { -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); -+ regs[rd] = 0; -+ break; -+ } -+ -+ /* -+ * The basename and dirname for a zero-length string is -+ * defined to be "." -+ */ -+ if (len == 0) { -+ len = 1; -+ src = (uintptr_t)"."; -+ } -+ -+ /* -+ * Start from the back of the string, moving back toward the -+ * front until we see a character that isn't a slash. That -+ * character is the last character in the basename. -+ */ -+ for (i = len - 1; i >= 0; i--) { -+ if (dtrace_load8(src + i) != '/') -+ break; -+ } -+ -+ if (i >= 0) -+ lastbase = i; -+ -+ /* -+ * Starting from the last character in the basename, move -+ * towards the front until we find a slash. The character -+ * that we processed immediately before that is the first -+ * character in the basename. -+ */ -+ for (; i >= 0; i--) { -+ if (dtrace_load8(src + i) == '/') -+ break; -+ } -+ -+ if (i >= 0) -+ firstbase = i + 1; -+ -+ /* -+ * Now keep going until we find a non-slash character. That -+ * character is the last character in the dirname. -+ */ -+ for (; i >= 0; i--) { -+ if (dtrace_load8(src + i) != '/') -+ break; -+ } -+ -+ if (i >= 0) -+ lastdir = i; -+ -+ ASSERT(!(lastbase == -1 && firstbase != -1)); -+ ASSERT(!(firstbase == -1 && lastdir != -1)); -+ -+ if (lastbase == -1) { -+ /* -+ * We didn't find a non-slash character. We know that -+ * the length is non-zero, so the whole string must be -+ * slashes. In either the dirname or the basename -+ * case, we return '/'. -+ */ -+ ASSERT(firstbase == -1); -+ firstbase = lastbase = lastdir = 0; -+ } -+ -+ if (firstbase == -1) { -+ /* -+ * The entire string consists only of a basename -+ * component. If we're looking for dirname, we need -+ * to change our string to be just "."; if we're -+ * looking for a basename, we'll just set the first -+ * character of the basename to be 0. -+ */ -+ if (subr == DIF_SUBR_DIRNAME) { -+ ASSERT(lastdir == -1); -+ src = (uintptr_t)"."; -+ lastdir = 0; -+ } else { -+ firstbase = 0; -+ } -+ } -+ -+ if (subr == DIF_SUBR_DIRNAME) { -+ if (lastdir == -1) { -+ /* -+ * We know that we have a slash in the name -- -+ * or lastdir would be set to 0, above. And -+ * because lastdir is -1, we know that this -+ * slash must be the first character. (That -+ * is, the full string must be of the form -+ * "/basename".) In this case, the last -+ * character of the directory name is 0. -+ */ -+ lastdir = 0; -+ } -+ -+ start = 0; -+ end = lastdir; -+ } else { -+ ASSERT(subr == DIF_SUBR_BASENAME); -+ ASSERT(firstbase != -1 && lastbase != -1); -+ start = firstbase; -+ end = lastbase; -+ } -+ -+ for (i = start, j = 0; i <= end && j < size - 1; i++, j++) -+ dest[j] = dtrace_load8(src + i); -+ -+ dest[j] = '\0'; -+ regs[rd] = (uintptr_t)dest; -+ mstate->dtms_scratch_ptr += size; -+ break; -+ } -+ -+ case DIF_SUBR_CLEANPATH: { -+ char *dest = (char *)mstate->dtms_scratch_ptr, c; -+ uint64_t size = state->dts_options[DTRACEOPT_STRSIZE]; -+ uintptr_t src = tupregs[0].dttk_value; -+ int i = 0, j = 0; -+ -+ if (!dtrace_strcanload(src, size, mstate, vstate)) { -+ regs[rd] = 0; -+ break; -+ } -+ -+ if (!DTRACE_INSCRATCH(mstate, size)) { -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); -+ regs[rd] = 0; -+ break; -+ } -+ -+ /* -+ * Move forward, loading each character. -+ */ -+ do { -+ c = dtrace_load8(src + i++); -+next: -+ if (j + 5 >= size) /* 5 = strlen("/..c\0") */ -+ break; -+ -+ if (c != '/') { -+ dest[j++] = c; -+ continue; -+ } -+ -+ c = dtrace_load8(src + i++); -+ -+ if (c == '/') { -+ /* -+ * We have two slashes -- we can just advance -+ * to the next character. -+ */ -+ goto next; -+ } -+ -+ if (c != '.') { -+ /* -+ * This is not "." and it's not ".." -- we can -+ * just store the "/" and this character and -+ * drive on. -+ */ -+ dest[j++] = '/'; -+ dest[j++] = c; -+ continue; -+ } -+ -+ c = dtrace_load8(src + i++); -+ -+ if (c == '/') { -+ /* -+ * This is a "/./" component. We're not going -+ * to store anything in the destination buffer; -+ * we're just going to go to the next component. -+ */ -+ goto next; -+ } -+ -+ if (c != '.') { -+ /* -+ * This is not ".." -- we can just store the -+ * "/." and this character and continue -+ * processing. -+ */ -+ dest[j++] = '/'; -+ dest[j++] = '.'; -+ dest[j++] = c; -+ continue; -+ } -+ -+ c = dtrace_load8(src + i++); -+ -+ if (c != '/' && c != '\0') { -+ /* -+ * This is not ".." -- it's "..[mumble]". -+ * We'll store the "/.." and this character -+ * and continue processing. -+ */ -+ dest[j++] = '/'; -+ dest[j++] = '.'; -+ dest[j++] = '.'; -+ dest[j++] = c; -+ continue; -+ } -+ -+ /* -+ * This is "/../" or "/..\0". We need to back up -+ * our destination pointer until we find a "/". -+ */ -+ i--; -+ while (j != 0 && dest[--j] != '/') -+ continue; -+ -+ if (c == '\0') -+ dest[++j] = '/'; -+ } while (c != '\0'); -+ -+ dest[j] = '\0'; -+ regs[rd] = (uintptr_t)dest; -+ mstate->dtms_scratch_ptr += size; -+ break; -+ } -+ -+ case DIF_SUBR_LINK_NTOP: { -+ struct dtrace_hwtype_alen { -+ int dhwa_hwtype; -+ size_t dhwa_hwalen; -+ } hwinfo[] = { -+ { ARPHRD_ETHER, ETH_ALEN }, -+ { ARPHRD_INFINIBAND, INFINIBAND_ALEN }, -+ { -1, 0 } -+ }; -+/* -+ * Captures the maximum hardware address length among all the supported -+ * hardware types. Please update this macro when adding a new hardware type. -+ */ -+#define DTRACE_MAX_HWTYPE_ALEN (ETH_ALEN > INFINIBAND_ALEN ? \ -+ ETH_ALEN : INFINIBAND_ALEN) -+ uintptr_t src = tupregs[1].dttk_value; -+ int hwtype = tupregs[0].dttk_value; -+ uint8_t hwaddr[DTRACE_MAX_HWTYPE_ALEN]; -+ char *base; -+ size_t size, len; -+ int i; -+ -+ for (i = 0; hwinfo[i].dhwa_hwtype != -1; i++) { -+ if (hwtype == hwinfo[i].dhwa_hwtype) -+ break; -+ } -+ if (hwinfo[i].dhwa_hwtype == -1) { -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); -+ regs[rd] = 0; -+ break; -+ } -+ len = hwinfo[i].dhwa_hwalen; -+ -+ /* -+ * Safely load the hardware address. -+ */ -+ if (!dtrace_canload(src, len, mstate, vstate)) { -+ regs[rd] = 0; -+ break; -+ } -+ dtrace_bcopy((void *)src, hwaddr, len); -+ -+ /* -+ * Check if a hardware address string will fit in scratch. -+ * For every byte we need 3 characters (including ':'). -+ */ -+ size = len * 3; -+ if (!DTRACE_INSCRATCH(mstate, size)) { -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); -+ regs[rd] = 0; -+ break; -+ } -+ base = (char *)mstate->dtms_scratch_ptr; -+ -+ /* -+ * Build the Hardware address string by working through the -+ * address from the beginning. Given a hardware address -+ * {0xa0, 0xaa, 0xff, 0xc, 0, 1, 2} of length 6, it will build -+ * a0:aa:ff:0c:00:01:02. -+ */ -+ for (i = 0; i < len; i++) { -+ if (hwaddr[i] < 16) { -+ *base++ = '0'; -+ *base++ = hexdigits[hwaddr[i]]; -+ } else { -+ *base++ = hexdigits[hwaddr[i] / 16]; -+ *base++ = hexdigits[hwaddr[i] % 16]; -+ } -+ -+ if (i < len - 1) -+ *base++ = ':'; -+ } -+ *base++ = '\0'; -+ regs[rd] = mstate->dtms_scratch_ptr; -+ mstate->dtms_scratch_ptr += size; -+#undef DTRACE_MAX_HWTYPE_ALEN -+ break; -+ } -+ -+ case DIF_SUBR_INET_NTOA: -+ case DIF_SUBR_INET_NTOA6: -+ case DIF_SUBR_INET_NTOP: { -+ uintptr_t src; -+ size_t size; -+ int af, argi, i; -+ char *base, *end; -+ -+ if (subr == DIF_SUBR_INET_NTOP) { -+ af = (int)tupregs[0].dttk_value; -+ argi = 1; -+ } else { -+ af = subr == DIF_SUBR_INET_NTOA ? AF_INET : AF_INET6; -+ argi = 0; -+ } -+ -+ src = tupregs[argi].dttk_value; -+ if (af == AF_INET) { -+ ipaddr_t ip4; -+ ipaddr_t_p ptr4; -+ uint8_t *ptr8, val; -+ -+ /* -+ * Safely load the IPv4 address. -+ */ -+ if (!dtrace_canload(src, 4, mstate, vstate)) { -+ regs[rd] = 0; -+ break; -+ } -+ ip4 = dtrace_load32(src); -+ -+ /* -+ * Check an IPv4 string will fit in scratch. -+ */ -+ size = INET_ADDRSTRLEN; -+ if (!DTRACE_INSCRATCH(mstate, size)) { -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); -+ regs[rd] = 0; -+ break; -+ } -+ base = (char *)mstate->dtms_scratch_ptr; -+ end = (char *)mstate->dtms_scratch_ptr + size - 1; -+ -+ /* -+ * Stringify as a dotted decimal quad. -+ */ -+ *end-- = '\0'; -+ ptr4 = &ip4; -+ ptr8 = (uint8_t *)ptr4; -+ for (i = 3; i >= 0; i--) { -+ val = ptr8[i]; -+ -+ if (val == 0) { -+ *end-- = '0'; -+ } else { -+ for (; val; val /= 10) -+ *end-- = '0' + (val % 10); -+ } -+ -+ if (i > 0) -+ *end-- = '.'; -+ } -+ ASSERT(end + 1 >= base); -+#if IS_ENABLED(CONFIG_IPV6) -+ } else if (af == AF_INET6) { -+ in6_addr_t ip6; -+ int firstzero, tryzero, numzero, v6end; -+ uint16_t val; -+ -+ /* -+ * Stringify using RFC 1884 convention 2 - 16 bit -+ * hexadecimal values with a zero-run compression. -+ * Lower case hexadecimal digits are used. -+ * eg, fe80::214:4fff:fe0b:76c8. -+ * The IPv4 embedded form is returned for inet_ntop, -+ * just the IPv4 string is returned for inet_ntoa6. -+ */ -+ -+ /* -+ * Safely load the IPv6 address. -+ */ -+ if (!dtrace_canload(src, sizeof(in6_addr_t), mstate, -+ vstate)) { -+ regs[rd] = 0; -+ break; -+ } -+ dtrace_bcopy((void *)src, (void *)(uintptr_t)&ip6, -+ sizeof(in6_addr_t)); -+ -+ /* -+ * Check an IPv6 string will fit in scratch. -+ */ -+ size = INET6_ADDRSTRLEN; -+ if (!DTRACE_INSCRATCH(mstate, size)) { -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); -+ regs[rd] = 0; -+ break; -+ } -+ base = (char *)mstate->dtms_scratch_ptr; -+ end = (char *)mstate->dtms_scratch_ptr + size - 1; -+ *end-- = '\0'; -+ -+ /* -+ * Find the longest run of 16 bit zero values -+ * for the single allowed zero compression - "::". -+ */ -+ firstzero = -1; -+ tryzero = -1; -+ numzero = 1; -+ for (i = 0; i < sizeof(in6_addr_t); i++) { -+ if (ip6.s6_addr[i] == 0 && -+ tryzero == -1 && i % 2 == 0) { -+ tryzero = i; -+ continue; -+ } -+ -+ if (tryzero != -1 && -+ (ip6.s6_addr[i] != 0 || -+ i == sizeof(in6_addr_t) - 1)) { -+ -+ if (i - tryzero <= numzero) { -+ tryzero = -1; -+ continue; -+ } -+ -+ firstzero = tryzero; -+ numzero = i - i % 2 - tryzero; -+ tryzero = -1; -+ -+ if (ip6.s6_addr[i] == 0 && -+ i == sizeof(in6_addr_t) - 1) -+ numzero += 2; -+ } -+ } -+ ASSERT(firstzero + numzero <= sizeof(in6_addr_t)); -+ -+ /* -+ * Check for an IPv4 embedded address. -+ */ -+ v6end = sizeof(in6_addr_t) - 2; -+ if (ipv6_addr_type(&ip6) & -+ (IPV6_ADDR_COMPATv4 | IPV6_ADDR_MAPPED)) { -+ for (i = sizeof(in6_addr_t) - 1; -+ i >= DTRACE_V4MAPPED_OFFSET; i--) { -+ ASSERT(end >= base); -+ -+ val = ip6.s6_addr[i]; -+ -+ if (val == 0) { -+ *end-- = '0'; -+ } else { -+ for (; val; val /= 10) -+ *end-- = '0' + val % 10; -+ } -+ -+ if (i > DTRACE_V4MAPPED_OFFSET) -+ *end-- = '.'; -+ } -+ -+ if (subr == DIF_SUBR_INET_NTOA6) -+ goto inetout; -+ -+ /* -+ * Set v6end to skip the IPv4 address that -+ * we have already stringified. -+ */ -+ v6end = 10; -+ } -+ -+ /* -+ * Build the IPv6 string by working through the -+ * address in reverse. -+ */ -+ for (i = v6end; i >= 0; i -= 2) { -+ ASSERT(end >= base); -+ -+ if (i == firstzero + numzero - 2) { -+ *end-- = ':'; -+ *end-- = ':'; -+ i -= numzero - 2; -+ continue; -+ } -+ -+ if (i < 14 && i != firstzero - 2) -+ *end-- = ':'; -+ -+ val = (ip6.s6_addr[i] << 8) + -+ ip6.s6_addr[i + 1]; -+ -+ if (val == 0) { -+ *end-- = '0'; -+ } else { -+ for (; val; val /= 16) -+ *end-- = hexdigits[val % 16]; -+ } -+ } -+ ASSERT(end + 1 >= base); -+#endif -+ } else { -+ /* -+ * The user didn't use AH_INET or AH_INET6. -+ */ -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); -+ regs[rd] = 0; -+ break; -+ } -+ -+#if IS_ENABLED(CONFIG_IPV6) -+inetout: -+#endif -+ regs[rd] = (uintptr_t)end + 1; -+ mstate->dtms_scratch_ptr += size; -+ break; -+ } -+ -+ case DIF_SUBR_D_PATH: { -+ struct path *path = (struct path *)tupregs[0].dttk_value; -+ char *dest = (char *)mstate->dtms_scratch_ptr; -+ char *ptr; -+ uint64_t size = state->dts_options[DTRACEOPT_STRSIZE]; -+ unsigned int fd; -+ struct files_struct -+ *files = current->files; -+ struct fdtable *fdt; -+ -+ if (!dtrace_canload((uintptr_t)path, sizeof(struct path), -+ mstate, vstate)) { -+ regs[rd] = 0; -+ break; -+ } -+ -+ if (!DTRACE_INSCRATCH(mstate, size)) { -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); -+ regs[rd] = 0; -+ break; -+ } -+ -+ if (spin_is_locked(&files->file_lock) || -+ !spin_trylock(&files->file_lock)) { -+ regs[rd] = 0; -+ break; -+ } -+ -+ fdt = files->fdt; -+ -+ /* -+ * We (currently) limit the d_path() subroutine to paths that -+ * relate to open files in the current task. -+ */ -+ for (fd = 0; fd < fdt->max_fds; fd++) { -+ if (fdt->fd[fd] && &fdt->fd[fd]->f_path == path) -+ break; -+ } -+ -+ spin_unlock(&files->file_lock); -+ -+ if (fd >= fdt->max_fds) { -+ *flags |= CPU_DTRACE_BADADDR; -+ *illval = (uintptr_t)path; -+ regs[rd] = 0; -+ break; -+ } -+ -+ ptr = d_path(path, dest, size); -+ if (ptr < 0) { -+ regs[rd] = 0; -+ break; -+ } -+ -+ regs[rd] = (uintptr_t)ptr; -+ mstate->dtms_scratch_ptr += size; -+ break; -+ } -+ -+ } -+} -+ -+/* -+ * Emulate the execution of DTrace IR instructions specified by the given DIF -+ * object. This function is deliberately void fo assertions as all of the -+ * necessary checks are handled by a call to dtrace_difo_validate(). -+ */ -+uint64_t dtrace_dif_emulate(struct dtrace_difo *difo, -+ struct dtrace_mstate *mstate, -+ struct dtrace_vstate *vstate, -+ struct dtrace_state *state) -+{ -+ const dif_instr_t *text = difo->dtdo_buf; -+ const uint_t textlen = difo->dtdo_len; -+ const char *strtab = difo->dtdo_strtab; -+ const uint64_t *inttab = difo->dtdo_inttab; -+ -+ uint64_t rval = 0; -+ struct dtrace_statvar *svar; -+ struct dtrace_dstate *dstate = &vstate->dtvs_dynvars; -+ struct dtrace_difv *v; -+ volatile uint16_t *flags = &this_cpu_core->cpuc_dtrace_flags; -+ volatile uintptr_t *illval = &this_cpu_core->cpuc_dtrace_illval; -+ -+ struct dtrace_key tupregs[DIF_DTR_NREGS + 2]; -+ /* +2 for thread and id */ -+ uint64_t regs[DIF_DIR_NREGS]; -+ uint64_t *tmp; -+ -+ uint8_t cc_n = 0, cc_z = 0, cc_v = 0, cc_c = 0; -+ int64_t cc_r; -+ uint_t pc = 0, id, opc = 0; -+ uint8_t ttop = 0; -+ dif_instr_t instr; -+ uint_t r1, r2, rd; -+ -+ dt_dbg_dif(" DIF %p emulation (text %p, %d instructions)...\n", -+ difo, text, textlen); -+ -+ /* -+ * We stash the current DIF object into the machine state: we need it -+ * for subsequent access checking. -+ */ -+ mstate->dtms_difo = difo; -+ -+ regs[DIF_REG_R0] = 0; /* %r0 is fixed at zero */ -+ -+ while (pc < textlen && !(*flags & CPU_DTRACE_FAULT)) { -+ opc = pc; -+ -+ instr = text[pc++]; -+ r1 = DIF_INSTR_R1(instr); -+ r2 = DIF_INSTR_R2(instr); -+ rd = DIF_INSTR_RD(instr); -+ -+ dt_dbg_dif(" Executing opcode %02x (%02x, %02x, %02x)\n", -+ DIF_INSTR_OP(instr), r1, r2, rd); -+ -+ switch (DIF_INSTR_OP(instr)) { -+ case DIF_OP_OR: -+ regs[rd] = regs[r1] | regs[r2]; -+ break; -+ case DIF_OP_XOR: -+ regs[rd] = regs[r1] ^ regs[r2]; -+ break; -+ case DIF_OP_AND: -+ regs[rd] = regs[r1] & regs[r2]; -+ break; -+ case DIF_OP_SLL: -+ regs[rd] = regs[r1] << regs[r2]; -+ break; -+ case DIF_OP_SRL: -+ regs[rd] = regs[r1] >> regs[r2]; -+ break; -+ case DIF_OP_SUB: -+ regs[rd] = regs[r1] - regs[r2]; -+ break; -+ case DIF_OP_ADD: -+ regs[rd] = regs[r1] + regs[r2]; -+ break; -+ case DIF_OP_MUL: -+ regs[rd] = regs[r1] * regs[r2]; -+ break; -+ case DIF_OP_SDIV: -+ if (regs[r2] == 0) { -+ regs[rd] = 0; -+ *flags |= CPU_DTRACE_DIVZERO; -+ } else { -+ int neg = 0; -+ -+ /* -+ * We cannot simply do a 64-bit division, since -+ * gcc translates it into a call to a function -+ * that is not linked into the kernel. -+ * -+ * regs[rd] = (int64_t)regs[r1] / -+ * (int64_t)regs[r2]; -+ */ -+ if ((int64_t)regs[r1] < 0) { -+ neg = !neg; -+ regs[r1] = -(int64_t)regs[r1]; -+ } -+ if ((int64_t)regs[r2] < 0) { -+ neg = !neg; -+ regs[r2] = -(int64_t)regs[r2]; -+ } -+ regs[rd] = regs[r1]; -+ do_div(regs[rd], regs[r2]); -+ -+ if (neg) -+ regs[rd] = -(int64_t)regs[rd]; -+ } -+ break; -+ -+ case DIF_OP_UDIV: -+ if (regs[r2] == 0) { -+ regs[rd] = 0; -+ *flags |= CPU_DTRACE_DIVZERO; -+ } else { -+ /* -+ * We cannot simply do a 64-bit division, since -+ * gcc translates it into a call to a function -+ * that is not linked into the kernel. -+ * -+ * regs[rd] = regs[r1] / regs[r2]; -+ */ -+ regs[rd] = regs[r1]; -+ do_div(regs[rd], regs[r2]); -+ } -+ break; -+ -+ case DIF_OP_SREM: -+ if (regs[r2] == 0) { -+ regs[rd] = 0; -+ *flags |= CPU_DTRACE_DIVZERO; -+ } else { -+ int neg = 0; -+ -+ /* -+ * We cannot simply do a 64-bit division, since -+ * gcc translates it into a call to a function -+ * that is not linked into the kernel. -+ * -+ * regs[rd] = (int64_t)regs[r1] % -+ * (int64_t)regs[r2]; -+ */ -+ if ((int64_t)regs[r1] < 0) { -+ neg = !neg; -+ regs[r1] = -(int64_t)regs[r1]; -+ } -+ if ((int64_t)regs[r2] < 0) { -+ neg = !neg; -+ regs[r2] = -(int64_t)regs[r2]; -+ } -+ regs[rd] = regs[r1]; -+ regs[rd] = do_div(regs[rd], regs[r2]); -+ -+ if (neg) -+ regs[rd] = -(int64_t)regs[rd]; -+ } -+ break; -+ -+ case DIF_OP_UREM: -+ if (regs[r2] == 0) { -+ regs[rd] = 0; -+ *flags |= CPU_DTRACE_DIVZERO; -+ } else { -+ /* -+ * We cannot simply do a 64-bit division, since -+ * gcc translates it into a call to a function -+ * that is not linked into the kernel. -+ * -+ * regs[rd] = regs[r1] % regs[r2]; -+ */ -+ regs[rd] = regs[r1]; -+ regs[rd] = do_div(regs[rd], regs[r2]); -+ } -+ break; -+ -+ case DIF_OP_NOT: -+ regs[rd] = ~regs[r1]; -+ break; -+ case DIF_OP_MOV: -+ regs[rd] = regs[r1]; -+ break; -+ case DIF_OP_CMP: -+ cc_r = regs[r1] - regs[r2]; -+ cc_n = cc_r < 0; -+ cc_z = cc_r == 0; -+ cc_v = 0; -+ cc_c = regs[r1] < regs[r2]; -+ break; -+ case DIF_OP_TST: -+ cc_n = cc_v = cc_c = 0; -+ cc_z = regs[r1] == 0; -+ break; -+ case DIF_OP_BA: -+ pc = DIF_INSTR_LABEL(instr); -+ break; -+ case DIF_OP_BE: -+ if (cc_z) -+ pc = DIF_INSTR_LABEL(instr); -+ break; -+ case DIF_OP_BNE: -+ if (cc_z == 0) -+ pc = DIF_INSTR_LABEL(instr); -+ break; -+ case DIF_OP_BG: -+ if ((cc_z | (cc_n ^ cc_v)) == 0) -+ pc = DIF_INSTR_LABEL(instr); -+ break; -+ case DIF_OP_BGU: -+ if ((cc_c | cc_z) == 0) -+ pc = DIF_INSTR_LABEL(instr); -+ break; -+ case DIF_OP_BGE: -+ if ((cc_n ^ cc_v) == 0) -+ pc = DIF_INSTR_LABEL(instr); -+ break; -+ case DIF_OP_BGEU: -+ if (cc_c == 0) -+ pc = DIF_INSTR_LABEL(instr); -+ break; -+ case DIF_OP_BL: -+ if (cc_n ^ cc_v) -+ pc = DIF_INSTR_LABEL(instr); -+ break; -+ case DIF_OP_BLU: -+ if (cc_c) -+ pc = DIF_INSTR_LABEL(instr); -+ break; -+ case DIF_OP_BLE: -+ if (cc_z | (cc_n ^ cc_v)) -+ pc = DIF_INSTR_LABEL(instr); -+ break; -+ case DIF_OP_BLEU: -+ if (cc_c | cc_z) -+ pc = DIF_INSTR_LABEL(instr); -+ break; -+ case DIF_OP_RLDSB: -+#ifdef FIXME_OPENSOLARIS_BUG -+ if (!dtrace_canstore(regs[r1], 1, mstate, vstate)) { -+#else -+ if (!dtrace_canload(regs[r1], 1, mstate, vstate)) { -+#endif -+ *flags |= CPU_DTRACE_KPRIV; -+ *illval = regs[r1]; -+ break; -+ } -+ /*FALLTHROUGH*/ -+ case DIF_OP_LDSB: -+ regs[rd] = (int8_t)dtrace_load8(regs[r1]); -+ break; -+ case DIF_OP_RLDSH: -+ if (!dtrace_canstore(regs[r1], 2, mstate, vstate)) { -+ *flags |= CPU_DTRACE_KPRIV; -+ *illval = regs[r1]; -+ break; -+ } -+ /*FALLTHROUGH*/ -+ case DIF_OP_LDSH: -+ regs[rd] = (int16_t)dtrace_load16(regs[r1]); -+ break; -+ case DIF_OP_RLDSW: -+ if (!dtrace_canstore(regs[r1], 4, mstate, vstate)) { -+ *flags |= CPU_DTRACE_KPRIV; -+ *illval = regs[r1]; -+ break; -+ } -+ /*FALLTHROUGH*/ -+ case DIF_OP_LDSW: -+ regs[rd] = (int32_t)dtrace_load32(regs[r1]); -+ break; -+ case DIF_OP_RLDUB: -+ if (!dtrace_canstore(regs[r1], 1, mstate, vstate)) { -+ *flags |= CPU_DTRACE_KPRIV; -+ *illval = regs[r1]; -+ break; -+ } -+ /*FALLTHROUGH*/ -+ case DIF_OP_LDUB: -+ regs[rd] = dtrace_load8(regs[r1]); -+ break; -+ case DIF_OP_RLDUH: -+ if (!dtrace_canstore(regs[r1], 2, mstate, vstate)) { -+ *flags |= CPU_DTRACE_KPRIV; -+ *illval = regs[r1]; -+ break; -+ } -+ /*FALLTHROUGH*/ -+ case DIF_OP_LDUH: -+ regs[rd] = dtrace_load16(regs[r1]); -+ break; -+ case DIF_OP_RLDUW: -+ if (!dtrace_canstore(regs[r1], 4, mstate, vstate)) { -+ *flags |= CPU_DTRACE_KPRIV; -+ *illval = regs[r1]; -+ break; -+ } -+ /*FALLTHROUGH*/ -+ case DIF_OP_LDUW: -+ regs[rd] = dtrace_load32(regs[r1]); -+ break; -+ case DIF_OP_RLDX: -+ if (!dtrace_canstore(regs[r1], 8, mstate, vstate)) { -+ *flags |= CPU_DTRACE_KPRIV; -+ *illval = regs[r1]; -+ break; -+ } -+ /*FALLTHROUGH*/ -+ case DIF_OP_LDX: -+ regs[rd] = dtrace_load64(regs[r1]); -+ break; -+ case DIF_OP_ULDSB: -+ regs[rd] = (int8_t)dtrace_fuword8( -+ (void *)(uintptr_t)regs[r1]); -+ break; -+ case DIF_OP_ULDSH: -+ regs[rd] = (int16_t)dtrace_fuword16( -+ (void *)(uintptr_t)regs[r1]); -+ break; -+ case DIF_OP_ULDSW: -+ regs[rd] = (int32_t)dtrace_fuword32( -+ (void *)(uintptr_t)regs[r1]); -+ break; -+ case DIF_OP_ULDUB: -+ regs[rd] = dtrace_fuword8((void *)(uintptr_t)regs[r1]); -+ break; -+ case DIF_OP_ULDUH: -+ regs[rd] = dtrace_fuword16( -+ (void *)(uintptr_t)regs[r1]); -+ break; -+ case DIF_OP_ULDUW: -+ regs[rd] = dtrace_fuword32( -+ (void *)(uintptr_t)regs[r1]); -+ break; -+ case DIF_OP_ULDX: -+ regs[rd] = dtrace_fuword64( -+ (void *)(uintptr_t)regs[r1]); -+ break; -+ case DIF_OP_RET: -+ rval = regs[rd]; -+ pc = textlen; -+ break; -+ case DIF_OP_NOP: -+ break; -+ case DIF_OP_SETX: -+ regs[rd] = inttab[DIF_INSTR_INTEGER(instr)]; -+ break; -+ case DIF_OP_SETS: -+ regs[rd] = (uint64_t)(uintptr_t) -+ (strtab + DIF_INSTR_STRING(instr)); -+ break; -+ case DIF_OP_SCMP: { -+ size_t sz = state->dts_options[ -+ DTRACEOPT_STRSIZE]; -+ uintptr_t s1 = regs[r1]; -+ uintptr_t s2 = regs[r2]; -+ -+ if (s1 != (uintptr_t)NULL && -+ !dtrace_strcanload(s1, sz, mstate, vstate)) -+ break; -+ if (s2 != (uintptr_t)NULL && -+ !dtrace_strcanload(s2, sz, mstate, vstate)) -+ break; -+ -+ cc_r = dtrace_strncmp((char *)s1, (char *)s2, sz); -+ -+ cc_n = cc_r < 0; -+ cc_z = cc_r == 0; -+ cc_v = cc_c = 0; -+ break; -+ } -+ case DIF_OP_LDGA: -+ regs[rd] = dtrace_dif_variable(mstate, state, r1, -+ regs[r2]); -+ break; -+ case DIF_OP_LDGS: -+ id = DIF_INSTR_VAR(instr); -+ -+ if (id >= DIF_VAR_OTHER_UBASE) { -+ uintptr_t a; -+ -+ id -= DIF_VAR_OTHER_UBASE; -+ svar = vstate->dtvs_globals[id]; -+ ASSERT(svar != NULL); -+ v = &svar->dtsv_var; -+ -+ if (!(v->dtdv_type.dtdt_flags & DIF_TF_BYREF)) { -+ regs[rd] = svar->dtsv_data; -+ break; -+ } -+ -+ a = (uintptr_t)svar->dtsv_data; -+ -+ /* -+ * If the 0th byte is set to UINT8_MAX then -+ * this is to be treated as a reference to a -+ * NULL variable. -+ */ -+ if (*(uint8_t *)a == UINT8_MAX) -+ regs[rd] = 0; -+ else -+ regs[rd] = a + sizeof(uint64_t); -+ -+ break; -+ } -+ -+ regs[rd] = dtrace_dif_variable(mstate, state, id, 0); -+ break; -+ -+ case DIF_OP_STGS: -+ id = DIF_INSTR_VAR(instr); -+ -+ ASSERT(id >= DIF_VAR_OTHER_UBASE); -+ id -= DIF_VAR_OTHER_UBASE; -+ -+ svar = vstate->dtvs_globals[id]; -+ ASSERT(svar != NULL); -+ v = &svar->dtsv_var; -+ -+ if (v->dtdv_type.dtdt_flags & DIF_TF_BYREF) { -+ uintptr_t a = (uintptr_t)svar->dtsv_data; -+ -+ ASSERT(a != 0); -+ ASSERT(svar->dtsv_size != 0); -+ -+ if (regs[rd] == 0) { -+ *(uint8_t *)a = UINT8_MAX; -+ break; -+ } else { -+ *(uint8_t *)a = 0; -+ a += sizeof(uint64_t); -+ } -+ -+ if (!dtrace_vcanload( -+ (void *)(uintptr_t)regs[rd], -+ &v->dtdv_type, mstate, vstate)) -+ break; -+ -+ dtrace_vcopy((void *)(uintptr_t)regs[rd], -+ (void *)a, &v->dtdv_type); -+ break; -+ } -+ -+ svar->dtsv_data = regs[rd]; -+ break; -+ -+ case DIF_OP_LDTA: -+ /* -+ * There are no DTrace built-in thread-local arrays at -+ * present. This opcode is saved for future work. -+ */ -+ *flags |= CPU_DTRACE_ILLOP; -+ regs[rd] = 0; -+ break; -+ -+ case DIF_OP_LDLS: -+ id = DIF_INSTR_VAR(instr); -+ -+ if (id < DIF_VAR_OTHER_UBASE) { -+ /* -+ * For now, this has no meaning. -+ */ -+ regs[rd] = 0; -+ break; -+ } -+ -+ id -= DIF_VAR_OTHER_UBASE; -+ -+ ASSERT(id < vstate->dtvs_nlocals); -+ ASSERT(vstate->dtvs_locals != NULL); -+ -+ svar = vstate->dtvs_locals[id]; -+ ASSERT(svar != NULL); -+ v = &svar->dtsv_var; -+ -+ if (v->dtdv_type.dtdt_flags & DIF_TF_BYREF) { -+ uintptr_t a = (uintptr_t)svar->dtsv_data; -+ size_t sz = v->dtdv_type.dtdt_size; -+ -+ sz += sizeof(uint64_t); -+ ASSERT(svar->dtsv_size == NR_CPUS * sz); -+ a += smp_processor_id() * sz; -+ -+ if (*(uint8_t *)a == UINT8_MAX) { -+ /* -+ * If the 0th byte is set to UINT8_MAX -+ * then this is to be treated as a -+ * reference to a NULL variable. -+ */ -+ regs[rd] = 0; -+ } else -+ regs[rd] = a + sizeof(uint64_t); -+ -+ break; -+ } -+ -+ ASSERT(svar->dtsv_size == NR_CPUS * sizeof(uint64_t)); -+ tmp = (uint64_t *)(uintptr_t)svar->dtsv_data; -+ regs[rd] = tmp[smp_processor_id()]; -+ break; -+ -+ case DIF_OP_STLS: -+ id = DIF_INSTR_VAR(instr); -+ -+ ASSERT(id >= DIF_VAR_OTHER_UBASE); -+ id -= DIF_VAR_OTHER_UBASE; -+ ASSERT(id < vstate->dtvs_nlocals); -+ -+ ASSERT(vstate->dtvs_locals != NULL); -+ svar = vstate->dtvs_locals[id]; -+ ASSERT(svar != NULL); -+ v = &svar->dtsv_var; -+ -+ if (v->dtdv_type.dtdt_flags & DIF_TF_BYREF) { -+ uintptr_t a = (uintptr_t)svar->dtsv_data; -+ size_t sz = v->dtdv_type.dtdt_size; -+ -+ sz += sizeof(uint64_t); -+ ASSERT(svar->dtsv_size == NR_CPUS * sz); -+ a += smp_processor_id() * sz; -+ -+ if (regs[rd] == 0) { -+ *(uint8_t *)a = UINT8_MAX; -+ break; -+ } else { -+ *(uint8_t *)a = 0; -+ a += sizeof(uint64_t); -+ } -+ -+ if (!dtrace_vcanload( -+ (void *)(uintptr_t)regs[rd], -+ &v->dtdv_type, mstate, vstate)) -+ break; -+ -+ dtrace_vcopy((void *)(uintptr_t)regs[rd], -+ (void *)a, &v->dtdv_type); -+ break; -+ } -+ -+ ASSERT(svar->dtsv_size == NR_CPUS * sizeof(uint64_t)); -+ tmp = (uint64_t *)(uintptr_t)svar->dtsv_data; -+ tmp[smp_processor_id()] = regs[rd]; -+ break; -+ -+ case DIF_OP_LDTS: { -+ struct dtrace_dynvar *dvar; -+ struct dtrace_key *key; -+ -+ id = DIF_INSTR_VAR(instr); -+ ASSERT(id >= DIF_VAR_OTHER_UBASE); -+ id -= DIF_VAR_OTHER_UBASE; -+ v = &vstate->dtvs_tlocals[id]; -+ -+ key = &tupregs[DIF_DTR_NREGS]; -+ key[0].dttk_value = (uint64_t)id; -+ key[0].dttk_size = 0; -+ DTRACE_TLS_THRKEY(key[1].dttk_value); -+ key[1].dttk_size = 0; -+ -+ dvar = dtrace_dynvar(dstate, 2, key, sizeof(uint64_t), -+ DTRACE_DYNVAR_NOALLOC, mstate, -+ vstate); -+ -+ if (dvar == NULL) { -+ regs[rd] = 0; -+ break; -+ } -+ -+ if (v->dtdv_type.dtdt_flags & DIF_TF_BYREF) -+ regs[rd] = (uint64_t)(uintptr_t)dvar->dtdv_data; -+ else -+ regs[rd] = *((uint64_t *)dvar->dtdv_data); -+ -+ break; -+ } -+ -+ case DIF_OP_STTS: { -+ struct dtrace_dynvar *dvar; -+ struct dtrace_key *key; -+ -+ id = DIF_INSTR_VAR(instr); -+ ASSERT(id >= DIF_VAR_OTHER_UBASE); -+ id -= DIF_VAR_OTHER_UBASE; -+ -+ key = &tupregs[DIF_DTR_NREGS]; -+ key[0].dttk_value = (uint64_t)id; -+ key[0].dttk_size = 0; -+ DTRACE_TLS_THRKEY(key[1].dttk_value); -+ key[1].dttk_size = 0; -+ v = &vstate->dtvs_tlocals[id]; -+ -+ dvar = dtrace_dynvar(dstate, 2, key, -+ v->dtdv_type.dtdt_size > sizeof(uint64_t) -+ ? v->dtdv_type.dtdt_size -+ : sizeof(uint64_t), -+ regs[rd] -+ ? DTRACE_DYNVAR_ALLOC -+ : DTRACE_DYNVAR_DEALLOC, -+ mstate, vstate); -+ -+ /* -+ * Given that we're storing to thread-local data, -+ * we need to flush our predicate cache. -+ */ -+ if (current->dt_task != NULL) -+ current->dt_task->dt_predcache = 0; -+ -+ if (dvar == NULL) -+ break; -+ -+ if (v->dtdv_type.dtdt_flags & DIF_TF_BYREF) { -+ if (!dtrace_vcanload( -+ (void *)(uintptr_t)regs[rd], -+ &v->dtdv_type, mstate, vstate)) -+ break; -+ -+ dtrace_vcopy((void *)(uintptr_t)regs[rd], -+ dvar->dtdv_data, &v->dtdv_type); -+ } else -+ *((uint64_t *)dvar->dtdv_data) = regs[rd]; -+ -+ break; -+ } -+ -+ case DIF_OP_SRA: -+ regs[rd] = (int64_t)regs[r1] >> regs[r2]; -+ break; -+ -+ case DIF_OP_CALL: -+ dtrace_dif_subr(DIF_INSTR_SUBR(instr), rd, regs, -+ tupregs, ttop, mstate, state); -+ break; -+ -+ case DIF_OP_PUSHTR: -+ if (ttop == DIF_DTR_NREGS) { -+ *flags |= CPU_DTRACE_TUPOFLOW; -+ break; -+ } -+ -+ if (r1 == DIF_TYPE_STRING) -+ /* -+ * If this is a string type and the size is 0, -+ * we'll use the system-wide default string -+ * size. Note that we are _not_ looking at -+ * the value of the DTRACEOPT_STRSIZE option; -+ * had this been set, we would expect to have -+ * a non-zero size value in the "pushtr". -+ */ -+ tupregs[ttop].dttk_size = -+ dtrace_strlen( -+ (char *)(uintptr_t)regs[rd], -+ regs[r2] -+ ? regs[r2] -+ : dtrace_strsize_default -+ ) + 1; -+ else -+ tupregs[ttop].dttk_size = regs[r2]; -+ -+ tupregs[ttop++].dttk_value = regs[rd]; -+ break; -+ -+ case DIF_OP_PUSHTV: -+ if (ttop == DIF_DTR_NREGS) { -+ *flags |= CPU_DTRACE_TUPOFLOW; -+ break; -+ } -+ -+ tupregs[ttop].dttk_value = regs[rd]; -+ tupregs[ttop++].dttk_size = 0; -+ break; -+ -+ case DIF_OP_POPTS: -+ if (ttop != 0) -+ ttop--; -+ break; -+ -+ case DIF_OP_FLUSHTS: -+ ttop = 0; -+ break; -+ -+ case DIF_OP_LDGAA: -+ case DIF_OP_LDTAA: { -+ struct dtrace_dynvar *dvar; -+ struct dtrace_key *key = tupregs; -+ uint_t nkeys = ttop; -+ -+ id = DIF_INSTR_VAR(instr); -+ ASSERT(id >= DIF_VAR_OTHER_UBASE); -+ id -= DIF_VAR_OTHER_UBASE; -+ -+ key[nkeys].dttk_value = (uint64_t)id; -+ key[nkeys++].dttk_size = 0; -+ -+ if (DIF_INSTR_OP(instr) == DIF_OP_LDTAA) { -+ DTRACE_TLS_THRKEY(key[nkeys].dttk_value); -+ key[nkeys++].dttk_size = 0; -+ v = &vstate->dtvs_tlocals[id]; -+ } else -+ v = &vstate->dtvs_globals[id]->dtsv_var; -+ -+ dvar = dtrace_dynvar(dstate, nkeys, key, -+ v->dtdv_type.dtdt_size > sizeof(uint64_t) ? -+ v->dtdv_type.dtdt_size : sizeof(uint64_t), -+ DTRACE_DYNVAR_NOALLOC, mstate, vstate); -+ -+ if (dvar == NULL) { -+ regs[rd] = 0; -+ break; -+ } -+ -+ if (v->dtdv_type.dtdt_flags & DIF_TF_BYREF) -+ regs[rd] = (uint64_t)(uintptr_t)dvar->dtdv_data; -+ else -+ regs[rd] = *((uint64_t *)dvar->dtdv_data); -+ -+ break; -+ } -+ -+ case DIF_OP_STGAA: -+ case DIF_OP_STTAA: { -+ struct dtrace_dynvar *dvar; -+ struct dtrace_key *key = tupregs; -+ uint_t nkeys = ttop; -+ -+ id = DIF_INSTR_VAR(instr); -+ ASSERT(id >= DIF_VAR_OTHER_UBASE); -+ id -= DIF_VAR_OTHER_UBASE; -+ -+ key[nkeys].dttk_value = (uint64_t)id; -+ key[nkeys++].dttk_size = 0; -+ -+ if (DIF_INSTR_OP(instr) == DIF_OP_STTAA) { -+ DTRACE_TLS_THRKEY(key[nkeys].dttk_value); -+ key[nkeys++].dttk_size = 0; -+ v = &vstate->dtvs_tlocals[id]; -+ } else -+ v = &vstate->dtvs_globals[id]->dtsv_var; -+ -+ dvar = dtrace_dynvar(dstate, nkeys, key, -+ v->dtdv_type.dtdt_size > sizeof(uint64_t) -+ ? v->dtdv_type.dtdt_size -+ : sizeof(uint64_t), -+ regs[rd] ? DTRACE_DYNVAR_ALLOC -+ : DTRACE_DYNVAR_DEALLOC, -+ mstate, vstate); -+ -+ if (dvar == NULL) -+ break; -+ -+ if (v->dtdv_type.dtdt_flags & DIF_TF_BYREF) { -+ if (!dtrace_vcanload( -+ (void *)(uintptr_t)regs[rd], -+ &v->dtdv_type, mstate, vstate)) -+ break; -+ -+ dtrace_vcopy((void *)(uintptr_t)regs[rd], -+ dvar->dtdv_data, &v->dtdv_type); -+ } else -+ *((uint64_t *)dvar->dtdv_data) = regs[rd]; -+ -+ break; -+ } -+ -+ case DIF_OP_ALLOCS: { -+ uintptr_t ptr = -+ P2ROUNDUP(mstate->dtms_scratch_ptr, 8); -+ size_t size = ptr - mstate->dtms_scratch_ptr + -+ regs[r1]; -+ -+ /* -+ * Rounding up the user allocation size could have -+ * overflowed large, bogus allocations (like -1ULL) to -+ * 0. -+ */ -+ if (size < regs[r1] || -+ !DTRACE_INSCRATCH(mstate, size)) { -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); -+ regs[rd] = 0; -+ break; -+ } -+ -+ dtrace_bzero((void *) mstate->dtms_scratch_ptr, size); -+ mstate->dtms_scratch_ptr += size; -+ regs[rd] = ptr; -+ break; -+ } -+ -+ case DIF_OP_COPYS: -+ if (!dtrace_canstore(regs[rd], regs[r2], mstate, -+ vstate)) { -+ *flags |= CPU_DTRACE_BADADDR; -+ *illval = regs[rd]; -+ break; -+ } -+ -+ if (!dtrace_canload(regs[r1], regs[r2], mstate, vstate)) -+ break; -+ -+ dtrace_bcopy((void *)(uintptr_t)regs[r1], -+ (void *)(uintptr_t)regs[rd], -+ (size_t)regs[r2]); -+ break; -+ -+ case DIF_OP_STB: -+ if (!dtrace_canstore(regs[rd], 1, mstate, vstate)) { -+ *flags |= CPU_DTRACE_BADADDR; -+ *illval = regs[rd]; -+ break; -+ } -+ -+ *((uint8_t *)(uintptr_t)regs[rd]) = (uint8_t)regs[r1]; -+ break; -+ -+ case DIF_OP_STH: -+ if (!dtrace_canstore(regs[rd], 2, mstate, vstate)) { -+ *flags |= CPU_DTRACE_BADADDR; -+ *illval = regs[rd]; -+ break; -+ } -+ -+ if (regs[rd] & 1) { -+ *flags |= CPU_DTRACE_BADALIGN; -+ *illval = regs[rd]; -+ break; -+ } -+ -+ *((uint16_t *)(uintptr_t)regs[rd]) = (uint16_t)regs[r1]; -+ break; -+ -+ case DIF_OP_STW: -+ if (!dtrace_canstore(regs[rd], 4, mstate, vstate)) { -+ *flags |= CPU_DTRACE_BADADDR; -+ *illval = regs[rd]; -+ break; -+ } -+ -+ if (regs[rd] & 3) { -+ *flags |= CPU_DTRACE_BADALIGN; -+ *illval = regs[rd]; -+ break; -+ } -+ -+ *((uint32_t *)(uintptr_t)regs[rd]) = (uint32_t)regs[r1]; -+ break; -+ -+ case DIF_OP_STX: -+ if (!dtrace_canstore(regs[rd], 8, mstate, vstate)) { -+ *flags |= CPU_DTRACE_BADADDR; -+ *illval = regs[rd]; -+ break; -+ } -+ -+ if (regs[rd] & 7) { -+ *flags |= CPU_DTRACE_BADALIGN; -+ *illval = regs[rd]; -+ break; -+ } -+ -+ *((uint64_t *)(uintptr_t)regs[rd]) = regs[r1]; -+ break; -+ } -+ } -+ -+ -+ if (!(*flags & CPU_DTRACE_FAULT)) { -+ dt_dbg_dif(" DIF %p completed, rval = %llx (flags %x)\n", -+ difo, rval, *flags); -+ return rval; -+ } -+ -+ dt_dbg_dif(" DIF %p emulation failed (flags %x)\n", difo, *flags); -+ -+ mstate->dtms_fltoffs = opc * sizeof(dif_instr_t); -+ mstate->dtms_present |= DTRACE_MSTATE_FLTOFFS; -+ -+ return 0; -+} -diff --git a/dtrace/dtrace_dof.c b/dtrace/dtrace_dof.c -new file mode 100644 -index 0000000000000000000000000000000000000000..85ff9b21a205b6c3f87ed5290117ebaefa45a3da ---- /dev/null -+++ b/dtrace/dtrace_dof.c -@@ -0,0 +1,2504 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_dof.c -+ * DESCRIPTION: DTrace - DOF implementation -+ * -+ * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/dtrace_task_impl.h> -+#include <linux/slab.h> -+#include <linux/types.h> -+#include <linux/vmalloc.h> -+#include <linux/uaccess.h> -+ -+#include "dtrace.h" -+ -+size_t dtrace_difo_maxsize = 256 * 1024; -+dtrace_optval_t dtrace_dof_maxsize = 256 * 1024; -+size_t dtrace_actions_max = 16 * 1024; -+dtrace_optval_t dtrace_helper_actions_max = 32; -+dtrace_optval_t dtrace_helper_providers_max = 32; -+ -+static int dtrace_helpers; -+ -+static uint32_t dtrace_helptrace_next; -+static uint32_t dtrace_helptrace_nlocals; -+ -+#ifdef CONFIG_DT_DEBUG -+int dtrace_helptrace_enabled = 1; -+#else -+int dtrace_helptrace_enabled = 0; -+#endif -+int dtrace_helptrace_bufsize = 512 * 1024; -+char *dtrace_helptrace_buffer; -+ -+void dtrace_dof_error(struct dof_hdr *dof, const char *str) -+{ -+ if (dtrace_err_verbose) -+ pr_warn("failed to process DOF: %s", str); -+ else -+ dt_dbg_dof("Failed to process DOF: %s\n", str); -+ -+#ifdef DTRACE_ERRDEBUG -+ dtrace_errdebug(str); -+#endif -+} -+ -+/* -+ * Create DOF out of a currently enabled state. Right now, we only create -+ * DOF containing the run-time options -- but this could be expanded to create -+ * complete DOF representing the enabled state. -+ */ -+struct dof_hdr *dtrace_dof_create(struct dtrace_state *state) -+{ -+ struct dof_hdr *dof; -+ struct dof_sec *sec; -+ struct dof_optdesc *opt; -+ -+ int i, len = sizeof(struct dof_hdr) + -+ roundup(sizeof(struct dof_sec), -+ sizeof(uint64_t)) + -+ sizeof(struct dof_optdesc) * DTRACEOPT_MAX; -+ -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ -+ dof = vmalloc(len); -+ if (dof == NULL) -+ return NULL; -+ -+ dof->dofh_ident[DOF_ID_MAG0] = DOF_MAG_MAG0; -+ dof->dofh_ident[DOF_ID_MAG1] = DOF_MAG_MAG1; -+ dof->dofh_ident[DOF_ID_MAG2] = DOF_MAG_MAG2; -+ dof->dofh_ident[DOF_ID_MAG3] = DOF_MAG_MAG3; -+ -+ dof->dofh_ident[DOF_ID_MODEL] = DOF_MODEL_NATIVE; -+ dof->dofh_ident[DOF_ID_ENCODING] = DOF_ENCODE_NATIVE; -+ dof->dofh_ident[DOF_ID_VERSION] = DOF_VERSION; -+ dof->dofh_ident[DOF_ID_DIFVERS] = DIF_VERSION; -+ dof->dofh_ident[DOF_ID_DIFIREG] = DIF_DIR_NREGS; -+ dof->dofh_ident[DOF_ID_DIFTREG] = DIF_DTR_NREGS; -+ -+ dof->dofh_flags = 0; -+ dof->dofh_hdrsize = sizeof(struct dof_hdr); -+ dof->dofh_secsize = sizeof(struct dof_sec); -+ dof->dofh_secnum = 1; /* only DOF_SECT_OPTDESC */ -+ dof->dofh_secoff = sizeof(struct dof_hdr); -+ dof->dofh_loadsz = len; -+ dof->dofh_filesz = len; -+ dof->dofh_pad = 0; -+ -+ /* -+ * Fill in the option section header... -+ */ -+ sec = (struct dof_sec *)((uintptr_t)dof + sizeof(struct dof_hdr)); -+ sec->dofs_type = DOF_SECT_OPTDESC; -+ sec->dofs_align = sizeof(uint64_t); -+ sec->dofs_flags = DOF_SECF_LOAD; -+ sec->dofs_entsize = sizeof(struct dof_optdesc); -+ -+ opt = (struct dof_optdesc *)((uintptr_t)sec + -+ roundup(sizeof(struct dof_sec), -+ sizeof(uint64_t))); -+ -+ sec->dofs_offset = (uintptr_t)opt - (uintptr_t)dof; -+ sec->dofs_size = sizeof(struct dof_optdesc) * DTRACEOPT_MAX; -+ -+ for (i = 0; i < DTRACEOPT_MAX; i++) { -+ opt[i].dofo_option = i; -+ opt[i].dofo_strtab = DOF_SECIDX_NONE; -+ opt[i].dofo_value = state->dts_options[i]; -+ } -+ -+ return dof; -+} -+ -+struct dof_hdr *dtrace_dof_copyin(void __user *argp, int *errp) -+{ -+ struct dof_hdr hdr, *dof; -+ -+ ASSERT(!MUTEX_HELD(&dtrace_lock)); -+ -+ /* -+ * First, we're going to copyin() the sizeof(dof_hdr_t). -+ */ -+ if (copy_from_user(&hdr, argp, sizeof(hdr)) != 0) { -+ dtrace_dof_error(NULL, "failed to copyin DOF header"); -+ *errp = -EFAULT; -+ return NULL; -+ } -+ -+ /* -+ * Now we'll allocate the entire DOF and copy it in -- provided -+ * that the length isn't outrageous. -+ */ -+ if (hdr.dofh_loadsz >= dtrace_dof_maxsize) { -+ dtrace_dof_error(&hdr, "load size exceeds maximum"); -+ *errp = -E2BIG; -+ return NULL; -+ } -+ -+ if (hdr.dofh_loadsz < sizeof(hdr)) { -+ dtrace_dof_error(&hdr, "invalid load size"); -+ *errp = -EINVAL; -+ return NULL; -+ } -+ -+ dof = vmalloc(hdr.dofh_loadsz); -+ if (dof == NULL) { -+ *errp = -ENOMEM; -+ return NULL; -+ } -+ -+ if (copy_from_user(dof, argp, hdr.dofh_loadsz) != 0 || -+ dof->dofh_loadsz != hdr.dofh_loadsz) { -+ vfree(dof); -+ *errp = -EFAULT; -+ return NULL; -+ } -+ -+ return dof; -+} -+ -+struct dof_hdr *dtrace_dof_property(const char *name) -+{ -+ uchar_t *buf; -+ uint64_t loadsz; -+ unsigned int len, i; -+ struct dof_hdr *dof; -+ -+ /* -+ * Unfortunately, array of values in .conf files are always (and -+ * only) interpreted to be integer arrays. We must read our DOF -+ * as an integer array, and then squeeze it into a byte array. -+ */ -+#ifdef FIXME -+ if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dtrace_devi, 0, -+ (char *)name, (int **)&buf, &len) != -+ DDI_PROP_SUCCESS) -+ return NULL; -+#else -+ return NULL; -+#endif -+ -+ for (i = 0; i < len; i++) -+ buf[i] = (uchar_t)(((int *)buf)[i]); -+ -+ if (len < sizeof(struct dof_hdr)) { -+#ifdef FIXME -+ ddi_prop_free(buf); -+#endif -+ dtrace_dof_error(NULL, "truncated header"); -+ return NULL; -+ } -+ -+ loadsz = ((struct dof_hdr *)buf)->dofh_loadsz; -+ if (len < loadsz) { -+#ifdef FIXME -+ ddi_prop_free(buf); -+#endif -+ dtrace_dof_error(NULL, "truncated DOF"); -+ return NULL; -+ } -+ -+ if (loadsz >= dtrace_dof_maxsize) { -+#ifdef FIXME -+ ddi_prop_free(buf); -+#endif -+ dtrace_dof_error(NULL, "oversized DOF"); -+ return NULL; -+ } -+ -+ dof = vmalloc(loadsz); -+ if (dof == NULL) { -+ dtrace_dof_error(NULL, "out-of-memory"); -+ return NULL; -+ } -+ memcpy(dof, buf, loadsz); -+#ifdef FIXME -+ ddi_prop_free(buf); -+#endif -+ -+ return dof; -+} -+ -+void dtrace_dof_destroy(struct dof_hdr *dof) -+{ -+ vfree(dof); -+} -+ -+/* -+ * Return the dof_sec_t pointer corresponding to a given section index. If the -+ * index is not valid, dtrace_dof_error() is called and NULL is returned. If -+ * a type other than DOF_SECT_NONE is specified, the header is checked against -+ * this type and NULL is returned if the types do not match. -+ */ -+static struct dof_sec *dtrace_dof_sect(struct dof_hdr *dof, uint32_t doftype, -+ dof_secidx_t i) -+{ -+ struct dof_sec *sec; -+ -+ sec = (struct dof_sec *)(uintptr_t) ((uintptr_t)dof + -+ dof->dofh_secoff + -+ i * dof->dofh_secsize); -+ -+ if (i >= dof->dofh_secnum) { -+ dtrace_dof_error(dof, "referenced section index is invalid"); -+ return NULL; -+ } -+ -+ if (!(sec->dofs_flags & DOF_SECF_LOAD)) { -+ dtrace_dof_error(dof, "referenced section is not loadable"); -+ return NULL; -+ } -+ -+ if (doftype != DOF_SECT_NONE && doftype != sec->dofs_type) { -+ dtrace_dof_error(dof, "referenced section is the wrong type"); -+ return NULL; -+ } -+ -+ return sec; -+} -+ -+static struct dtrace_probedesc *dtrace_dof_probedesc(struct dof_hdr *dof, -+ struct dof_sec *sec, -+ struct dtrace_probedesc *desc) -+{ -+ struct dof_probedesc *probe; -+ struct dof_sec *strtab; -+ uintptr_t daddr = (uintptr_t)dof; -+ uintptr_t str; -+ size_t size; -+ -+ if (sec->dofs_type != DOF_SECT_PROBEDESC) { -+ dtrace_dof_error(dof, "invalid probe section"); -+ return NULL; -+ } -+ -+ if (sec->dofs_align != sizeof(dof_secidx_t)) { -+ dtrace_dof_error(dof, "bad alignment in probe description"); -+ return NULL; -+ } -+ -+ if (sec->dofs_offset + sizeof(struct dof_probedesc) > -+ dof->dofh_loadsz) { -+ dtrace_dof_error(dof, "truncated probe description"); -+ return NULL; -+ } -+ -+ probe = (struct dof_probedesc *)(uintptr_t)(daddr + sec->dofs_offset); -+ strtab = dtrace_dof_sect(dof, DOF_SECT_STRTAB, probe->dofp_strtab); -+ -+ if (strtab == NULL) -+ return NULL; -+ -+ str = daddr + strtab->dofs_offset; -+ size = strtab->dofs_size; -+ -+ if (probe->dofp_provider >= strtab->dofs_size) { -+ dtrace_dof_error(dof, "corrupt probe provider"); -+ return NULL; -+ } -+ -+ strncpy(desc->dtpd_provider, (char *)(str + probe->dofp_provider), -+ min((size_t)DTRACE_PROVNAMELEN - 1, -+ size - probe->dofp_provider)); -+ -+ if (probe->dofp_mod >= strtab->dofs_size) { -+ dtrace_dof_error(dof, "corrupt probe module"); -+ return NULL; -+ } -+ -+ strncpy(desc->dtpd_mod, (char *)(str + probe->dofp_mod), -+ min((size_t)DTRACE_MODNAMELEN - 1, size - probe->dofp_mod)); -+ -+ if (probe->dofp_func >= strtab->dofs_size) { -+ dtrace_dof_error(dof, "corrupt probe function"); -+ return NULL; -+ } -+ -+ strncpy(desc->dtpd_func, (char *)(str + probe->dofp_func), -+ min((size_t)DTRACE_FUNCNAMELEN - 1, size - probe->dofp_func)); -+ -+ if (probe->dofp_name >= strtab->dofs_size) { -+ dtrace_dof_error(dof, "corrupt probe name"); -+ return NULL; -+ } -+ -+ strncpy(desc->dtpd_name, (char *)(str + probe->dofp_name), -+ min((size_t)DTRACE_NAMELEN - 1, size - probe->dofp_name)); -+ -+ dt_dbg_dof(" ECB Probe %s:%s:%s:%s\n", -+ desc->dtpd_provider, desc->dtpd_mod, desc->dtpd_func, -+ desc->dtpd_name); -+ -+ return desc; -+} -+ -+static struct dtrace_difo *dtrace_dof_difo(struct dof_hdr *dof, -+ struct dof_sec *sec, -+ struct dtrace_vstate *vstate, -+ const struct cred *cr) -+{ -+ struct dtrace_difo *dp; -+ size_t ttl = 0; -+ struct dof_difohdr *dofd; -+ uintptr_t daddr = (uintptr_t)dof; -+ size_t max = dtrace_difo_maxsize; -+ int i, l, n; -+ -+ static const struct { -+ int section; -+ int bufoffs; -+ int lenoffs; -+ int entsize; -+ int align; -+ const char *msg; -+ } difo[] = { -+ { -+ DOF_SECT_DIF, -+ offsetof(struct dtrace_difo, dtdo_buf), -+ offsetof(struct dtrace_difo, dtdo_len), -+ sizeof(dif_instr_t), -+ sizeof(dif_instr_t), -+ "multiple DIF sections" -+ }, -+ { -+ DOF_SECT_INTTAB, -+ offsetof(struct dtrace_difo, dtdo_inttab), -+ offsetof(struct dtrace_difo, dtdo_intlen), -+ sizeof(uint64_t), -+ sizeof(uint64_t), -+ "multiple integer tables" -+ }, -+ { -+ DOF_SECT_STRTAB, -+ offsetof(struct dtrace_difo, dtdo_strtab), -+ offsetof(struct dtrace_difo, dtdo_strlen), -+ 0, -+ sizeof(char), -+ "multiple string tables" -+ }, -+ { -+ DOF_SECT_VARTAB, -+ offsetof(struct dtrace_difo, dtdo_vartab), -+ offsetof(struct dtrace_difo, dtdo_varlen), -+ sizeof(struct dtrace_difv), -+ sizeof(uint_t), -+ "multiple variable tables" -+ }, -+ { -+ DOF_SECT_NONE, -+ 0, -+ 0, -+ 0, -+ 0, -+ NULL -+ } -+ }; -+ -+ if (sec->dofs_type != DOF_SECT_DIFOHDR) { -+ dtrace_dof_error(dof, "invalid DIFO header section"); -+ return NULL; -+ } -+ -+ if (sec->dofs_align != sizeof(dof_secidx_t)) { -+ dtrace_dof_error(dof, "bad alignment in DIFO header"); -+ return NULL; -+ } -+ -+ if (sec->dofs_size < sizeof(struct dof_difohdr) || -+ sec->dofs_size % sizeof(dof_secidx_t)) { -+ dtrace_dof_error(dof, "bad size in DIFO header"); -+ return NULL; -+ } -+ -+ dofd = (struct dof_difohdr *)(uintptr_t)(daddr + sec->dofs_offset); -+ n = (sec->dofs_size - sizeof(*dofd)) / sizeof(dof_secidx_t) + 1; -+ -+ dp = kzalloc(sizeof(struct dtrace_difo), GFP_KERNEL); -+ if (dp == NULL) { -+ dtrace_dof_error(dof, "out-of-memory"); -+ return NULL; -+ } -+ dp->dtdo_rtype = dofd->dofd_rtype; -+ -+ for (l = 0; l < n; l++) { -+ struct dof_sec *subsec; -+ void **bufp; -+ uint32_t *lenp; -+ -+ subsec = dtrace_dof_sect(dof, DOF_SECT_NONE, -+ dofd->dofd_links[l]); -+ if (subsec == NULL) -+ goto err; /* invalid section link */ -+ -+ if (ttl + subsec->dofs_size > max) { -+ dtrace_dof_error(dof, "exceeds maximum size"); -+ goto err; -+ } -+ -+ ttl += subsec->dofs_size; -+ -+ for (i = 0; difo[i].section != DOF_SECT_NONE; i++) { -+ if (subsec->dofs_type != difo[i].section) -+ continue; -+ -+ if (!(subsec->dofs_flags & DOF_SECF_LOAD)) { -+ dtrace_dof_error(dof, "section not loaded"); -+ goto err; -+ } -+ -+ if (subsec->dofs_align != difo[i].align) { -+ dtrace_dof_error(dof, "bad alignment"); -+ goto err; -+ } -+ -+ bufp = (void **)((uintptr_t)dp + difo[i].bufoffs); -+ lenp = (uint32_t *)((uintptr_t)dp + difo[i].lenoffs); -+ -+ if (*bufp != NULL) { -+ dtrace_dof_error(dof, difo[i].msg); -+ goto err; -+ } -+ -+ if (difo[i].entsize != subsec->dofs_entsize) { -+ dtrace_dof_error(dof, "entry size mismatch"); -+ goto err; -+ } -+ -+ if (subsec->dofs_entsize != 0) { -+ uint64_t n = subsec->dofs_size; -+ -+ if (do_div(n, subsec->dofs_entsize) != 0) { -+ dtrace_dof_error(dof, -+ "corrupt entry size"); -+ goto err; -+ } -+ } -+ -+ *lenp = subsec->dofs_size; -+ *bufp = vmalloc(subsec->dofs_size); -+ if (*bufp == NULL) { -+ dtrace_dof_error(dof, "out-of-memory"); -+ goto err; -+ } -+ memcpy(*bufp, -+ (char *)(uintptr_t)(daddr + subsec->dofs_offset), -+ subsec->dofs_size); -+ -+ if (subsec->dofs_entsize != 0) -+ *lenp /= subsec->dofs_entsize; -+ -+ break; -+ } -+ -+ /* -+ * If we encounter a loadable DIFO sub-section that is not -+ * known to us, assume this is a broken program and fail. -+ */ -+ if (difo[i].section == DOF_SECT_NONE && -+ (subsec->dofs_flags & DOF_SECF_LOAD)) { -+ dtrace_dof_error(dof, "unrecognized DIFO subsection"); -+ goto err; -+ } -+ } -+ -+ if (dp->dtdo_buf == NULL) { -+ /* -+ * We can't have a DIF object without DIF text. -+ */ -+ dtrace_dof_error(dof, "missing DIF text"); -+ goto err; -+ } -+ -+ /* -+ * Before we validate the DIF object, run through the variable table -+ * looking for the strings -- if any of their size are under, we'll set -+ * their size to be the system-wide default string size. Note that -+ * this should _not_ happen if the "strsize" option has been set -- -+ * in this case, the compiler should have set the size to reflect the -+ * setting of the option. -+ */ -+ for (i = 0; i < dp->dtdo_varlen; i++) { -+ struct dtrace_difv *v = &dp->dtdo_vartab[i]; -+ struct dtrace_diftype *t = &v->dtdv_type; -+ -+ if (v->dtdv_id < DIF_VAR_OTHER_UBASE) -+ continue; -+ -+ if (t->dtdt_kind == DIF_TYPE_STRING && t->dtdt_size == 0) -+ t->dtdt_size = dtrace_strsize_default; -+ } -+ -+ if (dtrace_difo_validate(dp, vstate, DIF_DIR_NREGS, cr) != 0) -+ goto err; -+ -+ dtrace_difo_init(dp, vstate); -+ return dp; -+ -+err: -+ if (dp->dtdo_buf != NULL) -+ vfree(dp->dtdo_buf); -+ if (dp->dtdo_inttab != NULL) -+ vfree(dp->dtdo_inttab); -+ if (dp->dtdo_strtab != NULL) -+ vfree(dp->dtdo_strtab); -+ if (dp->dtdo_vartab != NULL) -+ vfree(dp->dtdo_vartab); -+ -+ kfree(dp); -+ -+ return NULL; -+} -+ -+static struct dtrace_predicate *dtrace_dof_predicate(struct dof_hdr *dof, -+ struct dof_sec *sec, -+ struct dtrace_vstate *vstate, -+ const struct cred *cr) -+{ -+ struct dtrace_difo *dp; -+ -+ if ((dp = dtrace_dof_difo(dof, sec, vstate, cr)) == NULL) -+ return NULL; -+ -+ return dtrace_predicate_create(dp); -+} -+ -+static struct dtrace_actdesc *dtrace_dof_actdesc(struct dof_hdr *dof, -+ struct dof_sec *sec, -+ struct dtrace_vstate *vstate, -+ const struct cred *cr) -+{ -+ struct dtrace_actdesc *act, *first = NULL, *last = NULL, *next; -+ struct dof_actdesc *desc; -+ struct dof_sec *difosec; -+ size_t offs; -+ uintptr_t daddr = (uintptr_t)dof; -+ uint64_t arg; -+ dtrace_actkind_t kind; -+ -+ if (sec->dofs_type != DOF_SECT_ACTDESC) { -+ dtrace_dof_error(dof, "invalid action section"); -+ return NULL; -+ } -+ -+ if (sec->dofs_offset + sizeof(struct dof_actdesc) > dof->dofh_loadsz) { -+ dtrace_dof_error(dof, "truncated action description"); -+ return NULL; -+ } -+ -+ if (sec->dofs_align != sizeof(uint64_t)) { -+ dtrace_dof_error(dof, "bad alignment in action description"); -+ return NULL; -+ } -+ -+ if (sec->dofs_size < sec->dofs_entsize) { -+ dtrace_dof_error(dof, "section entry size exceeds total size"); -+ return NULL; -+ } -+ -+ if (sec->dofs_entsize != sizeof(struct dof_actdesc)) { -+ dtrace_dof_error(dof, "bad entry size in action description"); -+ return NULL; -+ } -+ -+ /* -+ * Was: sec->dofs_size / sec->dofs_entsize > dtrace_actions_max -+ * but it is safer to simply avoid the division (it requires use of -+ * a macro in Linux to cover 64-bit division in a 32-bit kernel. -+ */ -+ if (sec->dofs_size > sec->dofs_entsize * dtrace_actions_max) { -+ dtrace_dof_error(dof, "actions exceed dtrace_actions_max"); -+ return NULL; -+ } -+ -+ for (offs = 0; offs < sec->dofs_size; offs += sec->dofs_entsize) { -+ desc = (struct dof_actdesc *)(daddr + -+ (uintptr_t)sec->dofs_offset + offs); -+ kind = (dtrace_actkind_t)desc->dofa_kind; -+ -+ if (DTRACEACT_ISPRINTFLIKE(kind) && -+ (kind != DTRACEACT_PRINTA || -+ desc->dofa_strtab != DOF_SECIDX_NONE)) { -+ struct dof_sec *strtab; -+ char *str, *fmt; -+ uint64_t i; -+ -+ /* -+ * The printf()-like actions must have a format string. -+ */ -+ strtab = dtrace_dof_sect(dof, DOF_SECT_STRTAB, -+ desc->dofa_strtab); -+ if (strtab == NULL) -+ goto err; -+ -+ str = (char *)((uintptr_t)dof + -+ (uintptr_t)strtab->dofs_offset); -+ -+ for (i = desc->dofa_arg; i < strtab->dofs_size; i++) { -+ if (str[i] == '\0') -+ break; -+ } -+ -+ if (i >= strtab->dofs_size) { -+ dtrace_dof_error(dof, "bogus format string"); -+ goto err; -+ } -+ -+ if (i == desc->dofa_arg) { -+ dtrace_dof_error(dof, "empty format string"); -+ goto err; -+ } -+ -+ i -= desc->dofa_arg; -+ fmt = vmalloc(i + 1); -+ if (fmt == NULL) { -+ dtrace_dof_error(dof, "out-of-memory"); -+ goto err; -+ } -+ memcpy(fmt, &str[desc->dofa_arg], i + 1); -+ arg = (uint64_t)(uintptr_t)fmt; -+ } else { -+ if (kind == DTRACEACT_PRINTA) { -+ ASSERT(desc->dofa_strtab == DOF_SECIDX_NONE); -+ arg = 0; -+ } else -+ arg = desc->dofa_arg; -+ } -+ -+ act = dtrace_actdesc_create(kind, desc->dofa_ntuple, -+ desc->dofa_uarg, arg); -+ if (act == NULL) -+ goto err; -+ -+ if (last != NULL) -+ last->dtad_next = act; -+ else -+ first = act; -+ -+ last = act; -+ -+ if (desc->dofa_difo == DOF_SECIDX_NONE) -+ continue; -+ -+ difosec = dtrace_dof_sect(dof, DOF_SECT_DIFOHDR, -+ desc->dofa_difo); -+ if (difosec == NULL) -+ goto err; -+ -+ act->dtad_difo = dtrace_dof_difo(dof, difosec, vstate, cr); -+ -+ if (act->dtad_difo == NULL) -+ goto err; -+ } -+ -+ ASSERT(first != NULL); -+ return first; -+ -+err: -+ for (act = first; act != NULL; act = next) { -+ next = act->dtad_next; -+ dtrace_actdesc_release(act, vstate); -+ } -+ -+ return NULL; -+} -+ -+static struct dtrace_ecbdesc *dtrace_dof_ecbdesc(struct dof_hdr *dof, -+ struct dof_sec *sec, -+ struct dtrace_vstate *vstate, -+ const struct cred *cr) -+{ -+ struct dtrace_ecbdesc *ep; -+ struct dof_ecbdesc *ecb; -+ struct dtrace_probedesc *desc; -+ struct dtrace_predicate *pred = NULL; -+ -+ if (sec->dofs_size < sizeof(struct dof_ecbdesc)) { -+ dtrace_dof_error(dof, "truncated ECB description"); -+ return NULL; -+ } -+ -+ if (sec->dofs_align != sizeof(uint64_t)) { -+ dtrace_dof_error(dof, "bad alignment in ECB description"); -+ return NULL; -+ } -+ -+ ecb = (struct dof_ecbdesc *) -+ ((uintptr_t)dof + (uintptr_t)sec->dofs_offset); -+ sec = dtrace_dof_sect(dof, DOF_SECT_PROBEDESC, ecb->dofe_probes); -+ -+ if (sec == NULL) -+ return NULL; -+ -+ ep = kzalloc(sizeof(struct dtrace_ecbdesc), GFP_KERNEL); -+ if (ep == NULL) -+ return NULL; -+ ep->dted_uarg = ecb->dofe_uarg; -+ desc = &ep->dted_probe; -+ -+ if (dtrace_dof_probedesc(dof, sec, desc) == NULL) -+ goto err; -+ -+ if (ecb->dofe_pred != DOF_SECIDX_NONE) { -+ sec = dtrace_dof_sect(dof, DOF_SECT_DIFOHDR, ecb->dofe_pred); -+ if (sec == NULL) -+ goto err; -+ -+ pred = dtrace_dof_predicate(dof, sec, vstate, cr); -+ if (pred == NULL) -+ goto err; -+ -+ ep->dted_pred.dtpdd_predicate = pred; -+ } -+ -+ if (ecb->dofe_actions != DOF_SECIDX_NONE) { -+ sec = dtrace_dof_sect(dof, DOF_SECT_ACTDESC, ecb->dofe_actions); -+ if (sec == NULL) -+ goto err; -+ -+ ep->dted_action = dtrace_dof_actdesc(dof, sec, vstate, cr); -+ -+ if (ep->dted_action == NULL) -+ goto err; -+ } -+ -+ return ep; -+ -+err: -+ if (pred != NULL) -+ dtrace_predicate_release(pred, vstate); -+ kfree(ep); -+ return NULL; -+} -+ -+/* -+ * Apply the relocations from the specified 'sec' (a DOF_SECT_URELHDR) to the -+ * specified DOF. At present, this amounts to simply adding 'ubase' to the -+ * site of any user SETX relocations to account for load object base address. -+ * In the future, if we need other relocations, this function can be extended. -+ */ -+static int dtrace_dof_relocate(struct dof_hdr *dof, struct dof_sec *sec, -+ uint64_t ubase) -+{ -+ uintptr_t daddr = (uintptr_t)dof; -+ struct dof_relohdr *dofr; -+ struct dof_sec *ss, *rs, *ts; -+ struct dof_relodesc *r; -+ uint_t i, n; -+ -+ dofr = (struct dof_relohdr *)(uintptr_t) (daddr + sec->dofs_offset); -+ -+ if (sec->dofs_size < sizeof(struct dof_relohdr) || -+ sec->dofs_align != sizeof(dof_secidx_t)) { -+ dtrace_dof_error(dof, "invalid relocation header"); -+ return -1; -+ } -+ -+ ss = dtrace_dof_sect(dof, DOF_SECT_STRTAB, dofr->dofr_strtab); -+ rs = dtrace_dof_sect(dof, DOF_SECT_RELTAB, dofr->dofr_relsec); -+ ts = dtrace_dof_sect(dof, DOF_SECT_NONE, dofr->dofr_tgtsec); -+ -+ if (ss == NULL || rs == NULL || ts == NULL) -+ return -1; /* dtrace_dof_error() has been called already */ -+ -+ if (rs->dofs_entsize < sizeof(struct dof_relodesc) || -+ rs->dofs_align != sizeof(uint64_t)) { -+ dtrace_dof_error(dof, "invalid relocation section"); -+ return -1; -+ } -+ -+ r = (struct dof_relodesc *)(uintptr_t)(daddr + rs->dofs_offset); -+ /* -+ * Was: n = rs->dofs_size / rs->dofs_entsize; -+ * but on Linux we need to use a macro for the division to handle the -+ * possible case of 64-bit division on a 32-bit kernel. -+ */ -+ n = rs->dofs_size; -+ do_div(n, rs->dofs_entsize); -+ -+ for (i = 0; i < n; i++) { -+ uintptr_t taddr = daddr + ts->dofs_offset + r->dofr_offset; -+ -+ switch (r->dofr_type) { -+ case DOF_RELO_NONE: -+ break; -+ case DOF_RELO_SETX: -+ if (r->dofr_offset >= ts->dofs_size || -+ r->dofr_offset + sizeof(uint64_t) > -+ ts->dofs_size) { -+ dtrace_dof_error(dof, "bad relocation offset"); -+ return -1; -+ } -+ -+ if (!IS_ALIGNED(taddr, sizeof(uint64_t))) { -+ dtrace_dof_error(dof, "misaligned setx relo"); -+ return -1; -+ } -+ -+ /* -+ * This is a bit ugly but it is necessary for arm64, -+ * where the linking of shared libraries retains the -+ * relocation records for the .SUNW_dof section. In -+ * that case, the runtime loader already performed the -+ * relocation, so we do not have to do anything here. -+ * -+ * We check for this situation by comparing the target -+ * address against the base address (ubase). If it is -+ * larger, we assume the relocation already took place. -+ */ -+ if (*(uint64_t *)taddr > ubase) -+ dt_dbg_dof(" Relocation by runtime " \ -+ "loader: 0x%llx (base 0x%llx)\n", -+ *(uint64_t *)taddr, ubase); -+ else { -+ dt_dbg_dof(" Relocate 0x%llx + 0x%llx " \ -+ "= 0x%llx\n", -+ *(uint64_t *)taddr, ubase, -+ *(uint64_t *)taddr + ubase); -+ -+ *(uint64_t *)taddr += ubase; -+ } -+ -+ break; -+ default: -+ dtrace_dof_error(dof, "invalid relocation type"); -+ return -1; -+ } -+ -+ r = (struct dof_relodesc *)((uintptr_t)r + rs->dofs_entsize); -+ } -+ -+ return 0; -+} -+ -+/* -+ * The dof_hdr_t passed to dtrace_dof_slurp() should be a partially validated -+ * header: it should be at the front of a memory region that is at least -+ * sizeof(dof_hdr_t) in size -- and then at least dof_hdr.dofh_loadsz in -+ * size. It need not be validated in any other way. -+ */ -+int dtrace_dof_slurp(struct dof_hdr *dof, struct dtrace_vstate *vstate, -+ const struct cred *cr, struct dtrace_enabling **enabp, -+ uint64_t ubase, int noprobes) -+{ -+ uint64_t len = dof->dofh_loadsz, seclen; -+ uintptr_t daddr = (uintptr_t)dof; -+ struct dtrace_ecbdesc *ep; -+ struct dtrace_enabling *enab; -+ uint_t i; -+ -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ ASSERT(dof->dofh_loadsz >= sizeof(struct dof_hdr)); -+ -+ dt_dbg_dof(" DOF 0x%p Slurping...\n", dof); -+ -+ dt_dbg_dof(" DOF 0x%p Validating...\n", dof); -+ -+ /* -+ * Check the DOF header identification bytes. In addition to checking -+ * valid settings, we also verify that unused bits/bytes are zeroed so -+ * we can use them later without fear of regressing existing binaries. -+ */ -+ if (memcmp(&dof->dofh_ident[DOF_ID_MAG0], DOF_MAG_STRING, -+ DOF_MAG_STRLEN) != 0) { -+ dtrace_dof_error(dof, "DOF magic string mismatch"); -+ return -1; -+ } -+ -+ if (dof->dofh_ident[DOF_ID_MODEL] != DOF_MODEL_ILP32 && -+ dof->dofh_ident[DOF_ID_MODEL] != DOF_MODEL_LP64) { -+ dtrace_dof_error(dof, "DOF has invalid data model"); -+ return -1; -+ } -+ -+ if (dof->dofh_ident[DOF_ID_ENCODING] != DOF_ENCODE_NATIVE) { -+ dtrace_dof_error(dof, "DOF encoding mismatch"); -+ return -1; -+ } -+ -+ if (dof->dofh_ident[DOF_ID_VERSION] != DOF_VERSION_1 && -+ dof->dofh_ident[DOF_ID_VERSION] != DOF_VERSION_2) { -+ dtrace_dof_error(dof, "DOF version mismatch"); -+ return -1; -+ } -+ -+ if (dof->dofh_ident[DOF_ID_DIFVERS] != DIF_VERSION_2) { -+ dtrace_dof_error(dof, "DOF uses unsupported instruction set"); -+ return -1; -+ } -+ -+ if (dof->dofh_ident[DOF_ID_DIFIREG] > DIF_DIR_NREGS) { -+ dtrace_dof_error(dof, "DOF uses too many integer registers"); -+ return -1; -+ } -+ -+ if (dof->dofh_ident[DOF_ID_DIFTREG] > DIF_DTR_NREGS) { -+ dtrace_dof_error(dof, "DOF uses too many tuple registers"); -+ return -1; -+ } -+ -+ for (i = DOF_ID_PAD; i < DOF_ID_SIZE; i++) { -+ if (dof->dofh_ident[i] != 0) { -+ dtrace_dof_error(dof, "DOF has invalid ident byte set"); -+ return -1; -+ } -+ } -+ -+ if (dof->dofh_flags & ~DOF_FL_VALID) { -+ dtrace_dof_error(dof, "DOF has invalid flag bits set"); -+ return -1; -+ } -+ -+ if (dof->dofh_secsize == 0) { -+ dtrace_dof_error(dof, "zero section header size"); -+ return -1; -+ } -+ -+ /* -+ * Check that the section headers don't exceed the amount of DOF -+ * data. Note that we cast the section size and number of sections -+ * to uint64_t's to prevent possible overflow in the multiplication. -+ */ -+ seclen = (uint64_t)dof->dofh_secnum * (uint64_t)dof->dofh_secsize; -+ -+ if (dof->dofh_secoff > len || seclen > len || -+ dof->dofh_secoff + seclen > len) { -+ dtrace_dof_error(dof, "truncated section headers"); -+ return -1; -+ } -+ -+ if (!IS_ALIGNED(dof->dofh_secoff, sizeof(uint64_t))) { -+ dtrace_dof_error(dof, "misaligned section headers"); -+ return -1; -+ } -+ -+ if (!IS_ALIGNED(dof->dofh_secsize, sizeof(uint64_t))) { -+ dtrace_dof_error(dof, "misaligned section size"); -+ return -1; -+ } -+ -+ /* -+ * Take an initial pass through the section headers to be sure that -+ * the headers don't have stray offsets. If the 'noprobes' flag is -+ * set, do not permit sections relating to providers, probes, or args. -+ */ -+ dt_dbg_dof(" DOF 0x%p Checking section offsets...\n", dof); -+ -+ for (i = 0; i < dof->dofh_secnum; i++) { -+ struct dof_sec *sec; -+ -+ sec = (struct dof_sec *)(daddr + (uintptr_t)dof->dofh_secoff + -+ i * dof->dofh_secsize); -+ -+ if (noprobes) { -+ switch (sec->dofs_type) { -+ case DOF_SECT_PROVIDER: -+ case DOF_SECT_PROBES: -+ case DOF_SECT_PRARGS: -+ case DOF_SECT_PROFFS: -+ dtrace_dof_error( -+ dof, "illegal sections for enabling"); -+ return -1; -+ } -+ } -+ -+ if (DOF_SEC_ISLOADABLE(sec->dofs_type) && -+ !(sec->dofs_flags & DOF_SECF_LOAD)) { -+ dtrace_dof_error( -+ dof, "loadable section with load flag unset"); -+ return -1; -+ } -+ -+ /* -+ * Just ignore non-loadable sections. -+ */ -+ if (!(sec->dofs_flags & DOF_SECF_LOAD)) -+ continue; -+ -+ if (sec->dofs_align & (sec->dofs_align - 1)) { -+ dtrace_dof_error(dof, "bad section alignment"); -+ return -1; -+ } -+ -+ if (sec->dofs_offset & (sec->dofs_align - 1)) { -+ dtrace_dof_error(dof, "misaligned section"); -+ return -1; -+ } -+ -+ if (sec->dofs_offset > len || sec->dofs_size > len || -+ sec->dofs_offset + sec->dofs_size > len) { -+ dtrace_dof_error(dof, "corrupt section header"); -+ return -1; -+ } -+ -+ if (sec->dofs_type == DOF_SECT_STRTAB && *((char *)daddr + -+ sec->dofs_offset + sec->dofs_size - 1) != '\0') { -+ dtrace_dof_error(dof, "non-terminating string table"); -+ return -1; -+ } -+ } -+ -+ /* -+ * Take a second pass through the sections and locate and perform any -+ * relocations that are present. We do this after the first pass to -+ * be sure that all sections have had their headers validated. -+ */ -+ dt_dbg_dof(" DOF 0x%p Performing relocations...\n", dof); -+ -+ for (i = 0; i < dof->dofh_secnum; i++) { -+ struct dof_sec *sec; -+ -+ sec = (struct dof_sec *)(daddr + (uintptr_t)dof->dofh_secoff + -+ i * dof->dofh_secsize); -+ -+ /* -+ * Skip sections that are not loadable. -+ */ -+ if (!(sec->dofs_flags & DOF_SECF_LOAD)) -+ continue; -+ -+ switch (sec->dofs_type) { -+ case DOF_SECT_URELHDR: -+ if (dtrace_dof_relocate(dof, sec, ubase) != 0) -+ return -1; -+ break; -+ } -+ } -+ -+ dt_dbg_dof(" DOF 0x%p Processing enablings...\n", dof); -+ -+ enab = *enabp; -+ if (enab == NULL) -+ enab = *enabp = dtrace_enabling_create(vstate); -+ -+ if (enab == NULL) { -+ dt_dbg_dof(" DOF 0x%p Done slurping - no enablings\n", dof); -+ return -1; -+ } -+ -+ for (i = 0; i < dof->dofh_secnum; i++) { -+ struct dof_sec *sec; -+ -+ sec = (struct dof_sec *)(daddr + (uintptr_t)dof->dofh_secoff + -+ i * dof->dofh_secsize); -+ -+ if (sec->dofs_type != DOF_SECT_ECBDESC) -+ continue; -+ -+ ep = dtrace_dof_ecbdesc(dof, sec, vstate, cr); -+ if (ep == NULL) { -+ dt_dbg_dof(" DOF 0x%p Done slurping - ECB problem\n", -+ dof); -+ dtrace_enabling_destroy(enab); -+ *enabp = NULL; -+ return -1; -+ } -+ -+ dtrace_enabling_add(enab, ep); -+ } -+ -+ dt_dbg_dof(" DOF 0x%p Enablings processed\n", dof); -+ dt_dbg_dof(" DOF 0x%p Done slurping\n", dof); -+ -+ return 0; -+} -+ -+/* -+ * Process DOF for any options. This should be called after the DOF has been -+ * processed by dtrace_dof_slurp(). -+ */ -+int dtrace_dof_options(struct dof_hdr *dof, struct dtrace_state *state) -+{ -+ int i, rval; -+ uint32_t entsize; -+ size_t offs; -+ struct dof_optdesc *desc; -+ -+ for (i = 0; i < dof->dofh_secnum; i++) { -+ struct dof_sec *sec; -+ -+ sec = (struct dof_sec *)((uintptr_t)dof + -+ (uintptr_t)dof->dofh_secoff + -+ i * dof->dofh_secsize); -+ -+ if (sec->dofs_type != DOF_SECT_OPTDESC) -+ continue; -+ -+ if (sec->dofs_align != sizeof(uint64_t)) { -+ dtrace_dof_error( -+ dof, "bad alignment in option description"); -+ return -EINVAL; -+ } -+ -+ entsize = sec->dofs_entsize; -+ if (entsize == 0) { -+ dtrace_dof_error(dof, "zeroed option entry size"); -+ return -EINVAL; -+ } -+ -+ if (entsize < sizeof(struct dof_optdesc)) { -+ dtrace_dof_error(dof, "bad option entry size"); -+ return -EINVAL; -+ } -+ -+ for (offs = 0; offs < sec->dofs_size; offs += entsize) { -+ desc = (struct dof_optdesc *)((uintptr_t)dof + -+ (uintptr_t)sec->dofs_offset + -+ offs); -+ -+ if (desc->dofo_strtab != DOF_SECIDX_NONE) { -+ dtrace_dof_error( -+ dof, "non-zero option string"); -+ return -EINVAL; -+ } -+ -+ if (desc->dofo_value == DTRACEOPT_UNSET) { -+ dtrace_dof_error(dof, "unset option"); -+ return -EINVAL; -+ } -+ -+ rval = dtrace_state_option(state, desc->dofo_option, -+ desc->dofo_value); -+ if (rval != 0) { -+ dtrace_dof_error(dof, "rejected option"); -+ return rval; -+ } -+ } -+ } -+ -+ return 0; -+} -+ -+static struct dtrace_helpers *dtrace_helpers_create(struct task_struct *curr) -+{ -+ struct dtrace_helpers *dth; -+ -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ -+ if (curr->dt_task == NULL) -+ return NULL; -+ -+ ASSERT(curr->dt_task->dt_helpers == NULL); -+ -+ dth = kzalloc(sizeof(struct dtrace_helpers), GFP_KERNEL); -+ if (dth == NULL) -+ return NULL; -+ -+ dth->dthps_actions = vzalloc(sizeof(struct dtrace_helper_action *) * -+ DTRACE_NHELPER_ACTIONS); -+ if (dth->dthps_actions == NULL) { -+ kfree(dth); -+ return NULL; -+ } -+ -+ curr->dt_task->dt_helpers = dth; -+ dtrace_helpers++; -+ -+ dt_dbg_dof(" Helpers allocated for task 0x%p (%d system-wide)\n", -+ curr, dtrace_helpers); -+ -+ return dth; -+} -+ -+static int dtrace_helper_validate(struct dtrace_helper_action *helper) -+{ -+ int err = 0, i; -+ struct dtrace_difo *dp; -+ -+ dp = helper->dtha_predicate; -+ if (dp != NULL) -+ err += dtrace_difo_validate_helper(dp); -+ -+ for (i = 0; i < helper->dtha_nactions; i++) -+ err += dtrace_difo_validate_helper(helper->dtha_actions[i]); -+ -+ return (err == 0); -+} -+ -+static int dtrace_helper_provider_validate(struct dof_hdr *dof, -+ struct dof_sec *sec) -+{ -+ uintptr_t daddr = (uintptr_t)dof; -+ struct dof_sec *str_sec, *prb_sec, *arg_sec, *off_sec, -+ *enoff_sec; -+ struct dof_provider *prov; -+ struct dof_probe *prb; -+ uint8_t *arg; -+ char *strtab, *typestr; -+ dof_stridx_t typeidx; -+ size_t typesz; -+ uint_t nprobes, j, k; -+ -+ ASSERT(sec->dofs_type == DOF_SECT_PROVIDER); -+ -+ if (sec->dofs_offset & (sizeof(uint_t) - 1)) { -+ dtrace_dof_error(dof, "misaligned section offset"); -+ return -1; -+ } -+ -+ /* -+ * The section needs to be large enough to contain the DOF provider -+ * structure appropriate for the given version. -+ */ -+ if (sec->dofs_size < -+ ((dof->dofh_ident[DOF_ID_VERSION] == DOF_VERSION_1) -+ ? offsetof(struct dof_provider, dofpv_prenoffs) -+ : sizeof(struct dof_provider))) { -+ dtrace_dof_error(dof, "provider section too small"); -+ return -1; -+ } -+ -+ prov = (struct dof_provider *)(uintptr_t)(daddr + sec->dofs_offset); -+ str_sec = dtrace_dof_sect(dof, DOF_SECT_STRTAB, prov->dofpv_strtab); -+ prb_sec = dtrace_dof_sect(dof, DOF_SECT_PROBES, prov->dofpv_probes); -+ arg_sec = dtrace_dof_sect(dof, DOF_SECT_PRARGS, prov->dofpv_prargs); -+ off_sec = dtrace_dof_sect(dof, DOF_SECT_PROFFS, prov->dofpv_proffs); -+ -+ if (str_sec == NULL || prb_sec == NULL || -+ arg_sec == NULL || off_sec == NULL) -+ return -1; -+ -+ enoff_sec = NULL; -+ -+ if (dof->dofh_ident[DOF_ID_VERSION] != DOF_VERSION_1 && -+ prov->dofpv_prenoffs != DOF_SECT_NONE) { -+ enoff_sec = dtrace_dof_sect(dof, DOF_SECT_PRENOFFS, -+ prov->dofpv_prenoffs); -+ -+ if (enoff_sec == NULL) -+ return -1; -+ } -+ -+ strtab = (char *)(uintptr_t)(daddr + str_sec->dofs_offset); -+ -+ if (prov->dofpv_name >= str_sec->dofs_size || -+ strlen(strtab + prov->dofpv_name) >= DTRACE_PROVNAMELEN) { -+ dtrace_dof_error(dof, "invalid provider name"); -+ return -1; -+ } -+ -+ if (prb_sec->dofs_entsize == 0 || -+ prb_sec->dofs_entsize > prb_sec->dofs_size) { -+ dtrace_dof_error(dof, "invalid entry size"); -+ return -1; -+ } -+ -+ if (prb_sec->dofs_entsize & (sizeof(uintptr_t) - 1)) { -+ dtrace_dof_error(dof, "misaligned entry size"); -+ return -1; -+ } -+ -+ if (off_sec->dofs_entsize != sizeof(uint32_t)) { -+ dtrace_dof_error(dof, "invalid entry size"); -+ return -1; -+ } -+ -+ if (off_sec->dofs_offset & (sizeof(uint32_t) - 1)) { -+ dtrace_dof_error(dof, "misaligned section offset"); -+ return -1; -+ } -+ -+ if (arg_sec->dofs_entsize != sizeof(uint8_t)) { -+ dtrace_dof_error(dof, "invalid entry size"); -+ return -1; -+ } -+ -+ arg = (uint8_t *)(uintptr_t)(daddr + arg_sec->dofs_offset); -+ nprobes = prb_sec->dofs_size / prb_sec->dofs_entsize; -+ -+ dt_dbg_dof(" DOF 0x%p %s::: with %d probes\n", -+ dof, strtab + prov->dofpv_name, nprobes); -+ -+ /* -+ * Take a pass through the probes to check for errors. -+ */ -+ for (j = 0; j < nprobes; j++) { -+ prb = (struct dof_probe *)(uintptr_t) -+ (daddr + prb_sec->dofs_offset + -+ j * prb_sec->dofs_entsize); -+ -+ if (prb->dofpr_func >= str_sec->dofs_size) { -+ dtrace_dof_error(dof, "invalid function name"); -+ return -1; -+ } -+ -+ if (strlen(strtab + prb->dofpr_func) >= DTRACE_FUNCNAMELEN) { -+ dtrace_dof_error(dof, "function name too long"); -+ return -1; -+ } -+ -+ if (prb->dofpr_name >= str_sec->dofs_size || -+ strlen(strtab + prb->dofpr_name) >= DTRACE_NAMELEN) { -+ dtrace_dof_error(dof, "invalid probe name"); -+ return -1; -+ } -+ -+ /* -+ * The offset count must not wrap the index, and the offsets -+ * must also not overflow the section's data. -+ */ -+ if (prb->dofpr_offidx + prb->dofpr_noffs < prb->dofpr_offidx || -+ (prb->dofpr_offidx + prb->dofpr_noffs) * -+ off_sec->dofs_entsize > off_sec->dofs_size) { -+ dtrace_dof_error(dof, "invalid probe offset"); -+ return -1; -+ } -+ -+ if (dof->dofh_ident[DOF_ID_VERSION] != DOF_VERSION_1) { -+ /* -+ * If there's no is-enabled offset section, make sure -+ * there aren't any is-enabled offsets. Otherwise -+ * perform the same checks as for probe offsets -+ * (immediately above). -+ */ -+ if (enoff_sec == NULL) { -+ if (prb->dofpr_enoffidx != 0 || -+ prb->dofpr_nenoffs != 0) { -+ dtrace_dof_error(dof, -+ "is-enabled offsets " -+ "with null section"); -+ return -1; -+ } -+ } else if (prb->dofpr_enoffidx + prb->dofpr_nenoffs < -+ prb->dofpr_enoffidx || -+ (prb->dofpr_enoffidx + prb->dofpr_nenoffs) * -+ enoff_sec->dofs_entsize > -+ enoff_sec->dofs_size) { -+ dtrace_dof_error(dof, "invalid is-enabled " -+ "offset"); -+ return -1; -+ } -+ -+ if (prb->dofpr_noffs + prb->dofpr_nenoffs == 0) { -+ dtrace_dof_error(dof, "zero probe and " -+ "is-enabled offsets"); -+ return -1; -+ } -+ } else if (prb->dofpr_noffs == 0) { -+ dtrace_dof_error(dof, "zero probe offsets"); -+ return -1; -+ } -+ -+ if (prb->dofpr_argidx + prb->dofpr_xargc < prb->dofpr_argidx || -+ (prb->dofpr_argidx + prb->dofpr_xargc) * -+ arg_sec->dofs_entsize > arg_sec->dofs_size) { -+ dtrace_dof_error(dof, "invalid args"); -+ return -1; -+ } -+ -+ typeidx = prb->dofpr_nargv; -+ typestr = strtab + prb->dofpr_nargv; -+ for (k = 0; k < prb->dofpr_nargc; k++) { -+ if (typeidx >= str_sec->dofs_size) { -+ dtrace_dof_error(dof, "bad native argument " -+ "type"); -+ return -1; -+ } -+ -+ typesz = strlen(typestr) + 1; -+ if (typesz > DTRACE_ARGTYPELEN) { -+ dtrace_dof_error(dof, "native argument type " -+ "too long"); -+ return -1; -+ } -+ -+ typeidx += typesz; -+ typestr += typesz; -+ } -+ -+ typeidx = prb->dofpr_xargv; -+ typestr = strtab + prb->dofpr_xargv; -+ for (k = 0; k < prb->dofpr_xargc; k++) { -+ if (arg[prb->dofpr_argidx + k] > prb->dofpr_nargc) { -+ dtrace_dof_error(dof, "bad native argument " -+ "index"); -+ return -1; -+ } -+ -+ if (typeidx >= str_sec->dofs_size) { -+ dtrace_dof_error(dof, "bad translated " -+ "argument type"); -+ return -1; -+ } -+ -+ typesz = strlen(typestr) + 1; -+ if (typesz > DTRACE_ARGTYPELEN) { -+ dtrace_dof_error(dof, "translated argument " -+ "type too long"); -+ return -1; -+ } -+ -+ typeidx += typesz; -+ typestr += typesz; -+ } -+ -+ dt_dbg_dof(" Probe %d %s:%s:%s:%s with %d offsets, " -+ "%d is-enabled offsets\n", j, -+ strtab + prov->dofpv_name, "", -+ strtab + prb->dofpr_func, strtab + prb->dofpr_name, -+ prb->dofpr_noffs, prb->dofpr_nenoffs); -+ } -+ -+ return 0; -+} -+ -+static void dtrace_helper_action_destroy(struct dtrace_helper_action *helper, -+ struct dtrace_vstate *vstate) -+{ -+ int i; -+ -+ if (helper->dtha_predicate != NULL) -+ dtrace_difo_release(helper->dtha_predicate, vstate); -+ -+ for (i = 0; i < helper->dtha_nactions; i++) { -+ ASSERT(helper->dtha_actions[i] != NULL); -+ dtrace_difo_release(helper->dtha_actions[i], vstate); -+ } -+ -+ vfree(helper->dtha_actions); -+ kfree(helper); -+} -+ -+static int dtrace_helper_action_add(int which, struct dtrace_ecbdesc *ep) -+{ -+ struct dtrace_helpers *dth; -+ struct dtrace_helper_action *helper, *last; -+ struct dtrace_actdesc *act; -+ struct dtrace_vstate *vstate; -+ struct dtrace_predicate *pred; -+ int count = 0, nactions = 0, i; -+ -+ if (which < 0 || which >= DTRACE_NHELPER_ACTIONS) -+ return -EINVAL; -+ -+ if (current->dt_task == NULL) -+ return -ENOMEM; -+ -+ dth = current->dt_task->dt_helpers; -+ last = dth->dthps_actions[which]; -+ vstate = &dth->dthps_vstate; -+ -+ for (count = 0; last != NULL; last = last->dtha_next) { -+ count++; -+ if (last->dtha_next == NULL) -+ break; -+ } -+ -+ /* -+ * If we already have dtrace_helper_actions_max helper actions for this -+ * helper action type, we'll refuse to add a new one. -+ */ -+ if (count >= dtrace_helper_actions_max) -+ return -ENOSPC; -+ -+ helper = kzalloc(sizeof(struct dtrace_helper_action), GFP_KERNEL); -+ if (helper == NULL) -+ return -ENOMEM; -+ -+ helper->dtha_generation = dth->dthps_generation; -+ -+ pred = ep->dted_pred.dtpdd_predicate; -+ if (pred != NULL) { -+ ASSERT(pred->dtp_difo != NULL); -+ dtrace_difo_hold(pred->dtp_difo); -+ helper->dtha_predicate = pred->dtp_difo; -+ } -+ -+ for (act = ep->dted_action; act != NULL; act = act->dtad_next) { -+ if (act->dtad_kind != DTRACEACT_DIFEXPR) -+ goto err; -+ -+ if (act->dtad_difo == NULL) -+ goto err; -+ -+ nactions++; -+ } -+ -+ helper->dtha_actions = vzalloc(sizeof(struct dtrace_difo *) * -+ (helper->dtha_nactions = nactions)); -+ if (helper->dtha_actions == NULL) -+ goto err; -+ -+ for (act = ep->dted_action, i = 0; act != NULL; act = act->dtad_next) { -+ dtrace_difo_hold(act->dtad_difo); -+ helper->dtha_actions[i++] = act->dtad_difo; -+ } -+ -+ if (!dtrace_helper_validate(helper)) -+ goto err; -+ -+ if (last == NULL) -+ dth->dthps_actions[which] = helper; -+ else -+ last->dtha_next = helper; -+ -+ if (vstate->dtvs_nlocals > dtrace_helptrace_nlocals) { -+ dtrace_helptrace_nlocals = vstate->dtvs_nlocals; -+ dtrace_helptrace_next = 0; -+ } -+ -+ return 0; -+ -+err: -+ dtrace_helper_action_destroy(helper, vstate); -+ if (helper->dtha_actions != NULL) -+ vfree(helper->dtha_actions); -+ else -+ return -ENOMEM; -+ -+ return -EINVAL; -+} -+ -+static int dtrace_helper_provider_add(struct dof_helper *dofhp, int gen) -+{ -+ struct dtrace_helpers *dth; -+ struct dtrace_helper_provider *hprov, **tmp_provs; -+ uint_t tmp_maxprovs, i; -+ -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ -+ if (current->dt_task == NULL) -+ return -ENOMEM; -+ -+ dth = current->dt_task->dt_helpers; -+ ASSERT(dth != NULL); -+ -+ /* -+ * If we already have dtrace_helper_providers_max helper providers, -+ * we're refuse to add a new one. -+ */ -+ if (dth->dthps_nprovs >= dtrace_helper_providers_max) -+ return -ENOSPC; -+ -+ /* -+ * Check to make sure this isn't a duplicate. -+ */ -+ for (i = 0; i < dth->dthps_nprovs; i++) { -+ if (dofhp->dofhp_addr == -+ dth->dthps_provs[i]->dthp_prov.dofhp_addr) -+ return -EALREADY; -+ } -+ -+ hprov = kzalloc(sizeof(struct dtrace_helper_provider), GFP_KERNEL); -+ if (hprov == NULL) -+ return -ENOMEM; -+ hprov->dthp_prov = *dofhp; -+ hprov->dthp_ref = 1; -+ hprov->dthp_generation = gen; -+ -+ /* -+ * Allocate a bigger table for helper providers if it's already full. -+ */ -+ if (dth->dthps_maxprovs == dth->dthps_nprovs) { -+ tmp_maxprovs = dth->dthps_maxprovs; -+ tmp_provs = dth->dthps_provs; -+ -+ if (dth->dthps_maxprovs == 0) -+ dth->dthps_maxprovs = 2; -+ else -+ dth->dthps_maxprovs *= 2; -+ -+ if (dth->dthps_maxprovs > dtrace_helper_providers_max) -+ dth->dthps_maxprovs = dtrace_helper_providers_max; -+ -+ ASSERT(tmp_maxprovs < dth->dthps_maxprovs); -+ -+ dth->dthps_provs = -+ vzalloc(dth->dthps_maxprovs * -+ sizeof(struct dtrace_helper_provider *)); -+ -+ if (dth->dthps_provs == NULL) { -+ kfree(hprov); -+ return -ENOMEM; -+ } -+ -+ if (tmp_provs != NULL) { -+ memcpy(dth->dthps_provs, tmp_provs, -+ tmp_maxprovs * -+ sizeof(struct dtrace_helper_provider *)); -+ vfree(tmp_provs); -+ } -+ } -+ -+ dth->dthps_provs[dth->dthps_nprovs] = hprov; -+ dth->dthps_nprovs++; -+ -+ return 0; -+} -+ -+static void dtrace_helper_provider_destroy(struct dtrace_helper_provider *hprov) -+{ -+ mutex_lock(&dtrace_lock); -+ -+ if (--hprov->dthp_ref == 0) { -+ struct dof_hdr *dof; -+ -+ mutex_unlock(&dtrace_lock); -+ -+ dof = (struct dof_hdr *)(uintptr_t)hprov->dthp_prov.dofhp_dof; -+ dtrace_dof_destroy(dof); -+ kfree(hprov); -+ } else -+ mutex_unlock(&dtrace_lock); -+} -+ -+static void dtrace_dofattr2attr(struct dtrace_attribute *attr, -+ const dof_attr_t dofattr) -+{ -+ attr->dtat_name = DOF_ATTR_NAME(dofattr); -+ attr->dtat_data = DOF_ATTR_DATA(dofattr); -+ attr->dtat_class = DOF_ATTR_CLASS(dofattr); -+} -+ -+static void dtrace_dofprov2hprov(struct dtrace_helper_provdesc *hprov, -+ const struct dof_provider *dofprov, -+ char *strtab) -+{ -+ hprov->dthpv_provname = strtab + dofprov->dofpv_name; -+ dtrace_dofattr2attr(&hprov->dthpv_pattr.dtpa_provider, -+ dofprov->dofpv_provattr); -+ dtrace_dofattr2attr(&hprov->dthpv_pattr.dtpa_mod, -+ dofprov->dofpv_modattr); -+ dtrace_dofattr2attr(&hprov->dthpv_pattr.dtpa_func, -+ dofprov->dofpv_funcattr); -+ dtrace_dofattr2attr(&hprov->dthpv_pattr.dtpa_name, -+ dofprov->dofpv_nameattr); -+ dtrace_dofattr2attr(&hprov->dthpv_pattr.dtpa_args, -+ dofprov->dofpv_argsattr); -+} -+ -+static void dtrace_helper_provider_remove_one(struct dof_helper *dhp, -+ struct dof_sec *sec, pid_t pid) -+{ -+ uintptr_t daddr = (uintptr_t)dhp->dofhp_dof; -+ struct dof_hdr *dof = (struct dof_hdr *)daddr; -+ struct dof_sec *str_sec; -+ struct dof_provider *prov; -+ char *strtab; -+ struct dtrace_helper_provdesc dhpv; -+ struct dtrace_meta *meta = dtrace_meta_pid; -+ struct dtrace_mops *mops = &meta->dtm_mops; -+ -+ prov = (struct dof_provider *)(uintptr_t)(daddr + sec->dofs_offset); -+ str_sec = (struct dof_sec *)(uintptr_t)(daddr + dof->dofh_secoff + -+ prov->dofpv_strtab * -+ dof->dofh_secsize); -+ -+ strtab = (char *)(uintptr_t)(daddr + str_sec->dofs_offset); -+ -+ /* -+ * Create the provider. -+ */ -+ dtrace_dofprov2hprov(&dhpv, prov, strtab); -+ -+ dt_dbg_dof(" Removing provider %s for PID %d\n", -+ dhpv.dthpv_provname, pid); -+ -+ mops->dtms_remove_pid(meta->dtm_arg, &dhpv, pid); -+ -+ meta->dtm_count--; -+} -+ -+static void dtrace_helper_provider_remove(struct dof_helper *dhp, pid_t pid) -+{ -+ uintptr_t daddr = (uintptr_t)dhp->dofhp_dof; -+ struct dof_hdr *dof = (struct dof_hdr *)daddr; -+ int i; -+ -+ ASSERT(MUTEX_HELD(&dtrace_meta_lock)); -+ -+ for (i = 0; i < dof->dofh_secnum; i++) { -+ struct dof_sec *sec; -+ -+ sec = (struct dof_sec *)(uintptr_t) (daddr + dof->dofh_secoff + -+ i * dof->dofh_secsize); -+ -+ if (sec->dofs_type != DOF_SECT_PROVIDER) -+ continue; -+ -+ dtrace_helper_provider_remove_one(dhp, sec, pid); -+ } -+} -+ -+static void dtrace_helper_provide_one(struct dof_helper *dhp, -+ struct dof_sec *sec, -+ pid_t pid) -+{ -+ uintptr_t daddr = (uintptr_t)dhp->dofhp_dof; -+ uint32_t *off, *enoff; -+ uint8_t *arg; -+ char *strtab; -+ uint_t i, nprobes; -+ void *parg; -+ -+ struct dof_hdr *dof = (struct dof_hdr *)daddr; -+ struct dof_sec *str_sec, *prb_sec, *arg_sec, *off_sec, -+ *enoff_sec; -+ struct dof_provider *prov; -+ struct dof_probe *probe; -+ struct dtrace_helper_provdesc dhpv; -+ struct dtrace_helper_probedesc dhpb; -+ struct dtrace_meta *meta = dtrace_meta_pid; -+ struct dtrace_mops *mops = &meta->dtm_mops; -+ -+ prov = (struct dof_provider *)(uintptr_t)(daddr + sec->dofs_offset); -+ str_sec = (struct dof_sec *)(uintptr_t)(daddr + dof->dofh_secoff + -+ prov->dofpv_strtab * -+ dof->dofh_secsize); -+ prb_sec = (struct dof_sec *)(uintptr_t)(daddr + dof->dofh_secoff + -+ prov->dofpv_probes * -+ dof->dofh_secsize); -+ arg_sec = (struct dof_sec *)(uintptr_t)(daddr + dof->dofh_secoff + -+ prov->dofpv_prargs * -+ dof->dofh_secsize); -+ off_sec = (struct dof_sec *)(uintptr_t)(daddr + dof->dofh_secoff + -+ prov->dofpv_proffs * -+ dof->dofh_secsize); -+ -+ strtab = (char *)(uintptr_t)(daddr + str_sec->dofs_offset); -+ off = (uint32_t *)(uintptr_t)(daddr + off_sec->dofs_offset); -+ arg = (uint8_t *)(uintptr_t)(daddr + arg_sec->dofs_offset); -+ enoff = NULL; -+ -+ /* -+ * See dtrace_helper_provider_validate(). -+ */ -+ if (dof->dofh_ident[DOF_ID_VERSION] != DOF_VERSION_1 && -+ prov->dofpv_prenoffs != DOF_SECT_NONE) { -+ enoff_sec = (struct dof_sec *)(uintptr_t) -+ (daddr + dof->dofh_secoff + -+ prov->dofpv_prenoffs * dof->dofh_secsize); -+ enoff = (uint32_t *)(uintptr_t) -+ (daddr + enoff_sec->dofs_offset); -+ } -+ -+ nprobes = prb_sec->dofs_size / prb_sec->dofs_entsize; -+ -+ /* -+ * Create the provider. -+ */ -+ dtrace_dofprov2hprov(&dhpv, prov, strtab); -+ -+ dt_dbg_dof(" Creating provider %s for PID %d\n", -+ strtab + prov->dofpv_name, pid); -+ -+ /* -+ * This used to just 'return;' when parg is NULL, but that causes the -+ * cleanup code (dtrace_helper_provider_remove[_one]) to make a call -+ * to dtms_remove_pid() for a provider that never got created. -+ * -+ * If we fail to provide this provider, mark it as something to ignore, -+ * so we don't try to process it during cleanup. -+ */ -+ parg = mops->dtms_provide_pid(meta->dtm_arg, &dhpv, pid); -+ if (parg == NULL) { -+ sec->dofs_type = DOF_SECT_NONE; -+ return; -+ } -+ -+ meta->dtm_count++; -+ -+ /* -+ * Create the probes. -+ */ -+ for (i = 0; i < nprobes; i++) { -+ probe = (struct dof_probe *)(uintptr_t)(daddr + -+ prb_sec->dofs_offset + -+ i * prb_sec->dofs_entsize); -+ -+ dhpb.dthpb_mod = dhp->dofhp_mod; -+ dhpb.dthpb_func = strtab + probe->dofpr_func; -+ dhpb.dthpb_name = strtab + probe->dofpr_name; -+ dhpb.dthpb_base = probe->dofpr_addr; -+ dhpb.dthpb_offs = off + probe->dofpr_offidx; -+ dhpb.dthpb_noffs = probe->dofpr_noffs; -+ -+ if (enoff != NULL) { -+ dhpb.dthpb_enoffs = enoff + probe->dofpr_enoffidx; -+ dhpb.dthpb_nenoffs = probe->dofpr_nenoffs; -+ } else { -+ dhpb.dthpb_enoffs = NULL; -+ dhpb.dthpb_nenoffs = 0; -+ } -+ -+ dhpb.dthpb_args = arg + probe->dofpr_argidx; -+ dhpb.dthpb_nargc = probe->dofpr_nargc; -+ dhpb.dthpb_xargc = probe->dofpr_xargc; -+ dhpb.dthpb_ntypes = strtab + probe->dofpr_nargv; -+ dhpb.dthpb_xtypes = strtab + probe->dofpr_xargv; -+ -+ dt_dbg_dof(" Creating probe %s:%s:%s:%s\n", -+ strtab + prov->dofpv_name, "", dhpb.dthpb_func, -+ dhpb.dthpb_name); -+ -+ mops->dtms_create_probe(meta->dtm_arg, parg, &dhpb); -+ } -+} -+ -+void dtrace_helper_provide(struct dof_helper *dhp, pid_t pid) -+{ -+ uintptr_t daddr = (uintptr_t)dhp->dofhp_dof; -+ struct dof_hdr *dof = (struct dof_hdr *)daddr; -+ int i; -+ -+ ASSERT(MUTEX_HELD(&dtrace_meta_lock)); -+ -+ for (i = 0; i < dof->dofh_secnum; i++) { -+ struct dof_sec *sec; -+ -+ sec = (struct dof_sec *)(uintptr_t) (daddr + dof->dofh_secoff + -+ i * dof->dofh_secsize); -+ -+ if (sec->dofs_type != DOF_SECT_PROVIDER) -+ continue; -+ -+ dtrace_helper_provide_one(dhp, sec, pid); -+ } -+ -+ /* -+ * We may have just created probes, so we must now rematch against any -+ * retained enablings. Note that this call will acquire both cpu_lock -+ * and dtrace_lock; the fact that we are holding dtrace_meta_lock now -+ * is what defines the ordering with respect to these three locks. -+ */ -+ dt_dbg_dof(" Re-matching against any retained enablings\n"); -+ dtrace_enabling_matchall(); -+} -+ -+static void dtrace_helper_provider_register(struct task_struct *tsk, -+ struct dtrace_helpers *dth, -+ struct dof_helper *dofhp) -+{ -+ ASSERT(!MUTEX_HELD(&dtrace_lock)); -+ -+ mutex_lock(&dtrace_meta_lock); -+ mutex_lock(&dtrace_lock); -+ -+ if (!dtrace_attached() || dtrace_meta_pid == NULL) { -+ dt_dbg_dof(" No meta provider registered -- deferred\n"); -+ -+ /* -+ * If the dtrace module is loaded but not attached, or if there -+ * isn't a meta provider registered to deal with these provider -+ * descriptions, we need to postpone creating the actual -+ * providers until later. -+ */ -+ if (dth->dthps_next == NULL && dth->dthps_prev == NULL && -+ dtrace_deferred_pid != dth) { -+ dth->dthps_deferred = 1; -+ dth->dthps_pid = tsk->pid; -+ dth->dthps_next = dtrace_deferred_pid; -+ dth->dthps_prev = NULL; -+ if (dtrace_deferred_pid != NULL) -+ dtrace_deferred_pid->dthps_prev = dth; -+ dtrace_deferred_pid = dth; -+ } -+ -+ mutex_unlock(&dtrace_lock); -+ } else if (dofhp != NULL) { -+ /* -+ * If the dtrace module is loaded and we have a particular -+ * helper provider description, pass that off to the meta -+ * provider. -+ */ -+ mutex_unlock(&dtrace_lock); -+ -+ dtrace_helper_provide(dofhp, tsk->pid); -+ } else { -+ /* -+ * Otherwise, just pass all the helper provider descriptions -+ * off to the meta provider. -+ */ -+ int i; -+ -+ mutex_unlock(&dtrace_lock); -+ -+ for (i = 0; i < dth->dthps_nprovs; i++) { -+ dtrace_helper_provide(&dth->dthps_provs[i]->dthp_prov, -+ tsk->pid); -+ } -+ } -+ -+ mutex_unlock(&dtrace_meta_lock); -+} -+ -+int dtrace_helper_slurp(struct dof_hdr *dof, struct dof_helper *dhp) -+{ -+ struct dtrace_helpers *dth; -+ struct dtrace_vstate *vstate; -+ struct dtrace_enabling *enab = NULL; -+ int i, gen, rv; -+ int nhelpers = 0, nprovs = 0, destroy = 1; -+ uintptr_t daddr = (uintptr_t)dof; -+ -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ -+ if (current->dt_task == NULL) -+ return -1; -+ -+ dth = current->dt_task->dt_helpers; -+ if (dth == NULL) -+ dth = dtrace_helpers_create(current); -+ -+ if (dth == NULL) { -+ dtrace_dof_destroy(dof); -+ return -1; -+ } -+ -+ dt_dbg_dof("DOF 0x%p from helper {'%s', %p, %p}...\n", -+ dof, dhp ? dhp->dofhp_mod : "<none>", -+ dhp ? (void *)(dhp->dofhp_addr) : NULL, -+ dhp ? (void *)(dhp->dofhp_dof) : NULL); -+ -+ vstate = &dth->dthps_vstate; -+ -+ rv = dtrace_dof_slurp(dof, vstate, NULL, &enab, -+ dhp != NULL ? dhp->dofhp_addr : 0, FALSE); -+ if (rv != 0) { -+ dtrace_dof_destroy(dof); -+ return rv; -+ } -+ -+ /* -+ * Look for helper providers and validate their descriptions. -+ */ -+ if (dhp != NULL) { -+ dt_dbg_dof(" DOF 0x%p Validating providers...\n", dof); -+ -+ for (i = 0; i < dof->dofh_secnum; i++) { -+ struct dof_sec *sec; -+ -+ sec = (struct dof_sec *)(uintptr_t) -+ (daddr + dof->dofh_secoff + -+ i * dof->dofh_secsize); -+ -+ if (sec->dofs_type != DOF_SECT_PROVIDER) -+ continue; -+ -+ if (dtrace_helper_provider_validate(dof, sec) != 0) { -+ dtrace_enabling_destroy(enab); -+ dtrace_dof_destroy(dof); -+ return -1; -+ } -+ -+ nprovs++; -+ } -+ } -+ -+ /* -+ * Now we need to walk through the ECB descriptions in the enabling. -+ */ -+ for (i = 0; i < enab->dten_ndesc; i++) { -+ struct dtrace_ecbdesc *ep = enab->dten_desc[i]; -+ struct dtrace_probedesc *desc = &ep->dted_probe; -+ -+ dt_dbg_dof(" ECB Desc %s:%s:%s:%s\n", -+ desc->dtpd_provider, desc->dtpd_mod, -+ desc->dtpd_func, desc->dtpd_name); -+ if (strcmp(desc->dtpd_provider, "dtrace") != 0) -+ continue; -+ -+ if (strcmp(desc->dtpd_mod, "helper") != 0) -+ continue; -+ -+ if (strcmp(desc->dtpd_func, "ustack") != 0) -+ continue; -+ -+ rv = dtrace_helper_action_add(DTRACE_HELPER_ACTION_USTACK, ep); -+ if (rv != 0) { -+ /* -+ * Adding this helper action failed -- we are now going -+ * to rip out the entire generation and return failure. -+ */ -+ dtrace_helper_destroygen(dth->dthps_generation); -+ dtrace_enabling_destroy(enab); -+ dtrace_dof_destroy(dof); -+ return -1; -+ } -+ -+ nhelpers++; -+ } -+ -+ if (nhelpers < enab->dten_ndesc) -+ dtrace_dof_error(dof, "unmatched helpers"); -+ -+ gen = dth->dthps_generation++; -+ dtrace_enabling_destroy(enab); -+ -+ if (dhp != NULL && nprovs > 0) { -+ dt_dbg_dof(" DOF 0x%p Adding and registering providers\n", -+ dof); -+ -+ dhp->dofhp_dof = (uint64_t)(uintptr_t)dof; -+ if (dtrace_helper_provider_add(dhp, gen) == 0) { -+ mutex_unlock(&dtrace_lock); -+ dtrace_helper_provider_register(current, dth, dhp); -+ mutex_lock(&dtrace_lock); -+ -+ destroy = 0; -+ } -+ } -+ -+ if (destroy) -+ dtrace_dof_destroy(dof); -+ -+ return gen; -+} -+ -+void dtrace_helpers_destroy(struct task_struct *tsk) -+{ -+ struct dtrace_helpers *help; -+ struct dtrace_vstate *vstate; -+ int i; -+ -+ if (tsk->dt_task == NULL) -+ return; -+ -+ mutex_lock(&dtrace_lock); -+ -+ ASSERT(tsk->dt_task->dt_helpers != NULL); -+ ASSERT(dtrace_helpers > 0); -+ -+ dt_dbg_dof("Helper cleanup: PID %d\n", tsk->pid); -+ -+ help = tsk->dt_task->dt_helpers; -+ vstate = &help->dthps_vstate; -+ -+ /* -+ * We're now going to lose the help from this process. -+ */ -+ tsk->dt_task->dt_helpers = NULL; -+ dtrace_sync(); -+ -+ /* -+ * Destroy the helper actions. -+ */ -+ for (i = 0; i < DTRACE_NHELPER_ACTIONS; i++) { -+ struct dtrace_helper_action *h, *next; -+ -+ for (h = help->dthps_actions[i]; h != NULL; h = next) { -+ next = h->dtha_next; -+ dtrace_helper_action_destroy(h, vstate); -+ h = next; -+ } -+ } -+ -+ mutex_unlock(&dtrace_lock); -+ -+ /* -+ * Destroy the helper providers. -+ */ -+ if (help->dthps_maxprovs > 0) { -+ mutex_lock(&dtrace_meta_lock); -+ if (dtrace_meta_pid != NULL) { -+ ASSERT(dtrace_deferred_pid == NULL); -+ -+ for (i = 0; i < help->dthps_nprovs; i++) { -+ dtrace_helper_provider_remove( -+ &help->dthps_provs[i]->dthp_prov, -+ tsk->pid); -+ } -+ } else { -+ mutex_lock(&dtrace_lock); -+ ASSERT(help->dthps_deferred == 0 || -+ help->dthps_next != NULL || -+ help->dthps_prev != NULL || -+ help == dtrace_deferred_pid); -+ -+ /* -+ * Remove the helper from the deferred list. -+ */ -+ if (help->dthps_next != NULL) -+ help->dthps_next->dthps_prev = help->dthps_prev; -+ if (help->dthps_prev != NULL) -+ help->dthps_prev->dthps_next = help->dthps_next; -+ if (dtrace_deferred_pid == help) { -+ dtrace_deferred_pid = help->dthps_next; -+ ASSERT(help->dthps_prev == NULL); -+ } -+ -+ mutex_unlock(&dtrace_lock); -+ } -+ -+ mutex_unlock(&dtrace_meta_lock); -+ -+ for (i = 0; i < help->dthps_nprovs; i++) -+ dtrace_helper_provider_destroy(help->dthps_provs[i]); -+ -+ vfree(help->dthps_provs); -+ } -+ -+ mutex_lock(&dtrace_lock); -+ -+ dtrace_vstate_fini(&help->dthps_vstate); -+ vfree(help->dthps_actions); -+ kfree(help); -+ -+ --dtrace_helpers; -+ mutex_unlock(&dtrace_lock); -+} -+ -+void dtrace_helpers_duplicate(struct task_struct *from, struct task_struct *to) -+{ -+ struct dtrace_task *dfrom = from->dt_task; -+ struct dtrace_task *dto = to->dt_task; -+ struct dtrace_helpers *help, *newhelp; -+ struct dtrace_helper_action *helper, *new, *last; -+ struct dtrace_difo *dp; -+ struct dtrace_vstate *vstate; -+ -+ int i, j, sz, hasprovs = 0; -+ -+ if (dfrom == NULL || dto == NULL) -+ return; -+ -+ mutex_lock(&dtrace_lock); -+ -+ ASSERT(dfrom->dt_helpers != NULL); -+ ASSERT(dtrace_helpers > 0); -+ -+ help = dfrom->dt_helpers; -+ newhelp = dtrace_helpers_create(to); -+ -+ ASSERT(dto->dt_helpers != NULL); -+ -+ newhelp->dthps_generation = help->dthps_generation; -+ vstate = &newhelp->dthps_vstate; -+ -+ /* -+ * Duplicate the helper actions. -+ */ -+ for (i = 0; i < DTRACE_NHELPER_ACTIONS; i++) { -+ helper = help->dthps_actions[i]; -+ if (helper == NULL) -+ continue; -+ -+ for (last = NULL; helper != NULL; helper = helper->dtha_next) { -+ new = kzalloc(sizeof(struct dtrace_helper_action), -+ GFP_KERNEL); -+ new->dtha_generation = helper->dtha_generation; -+ -+ dp = helper->dtha_predicate; -+ if (dp != NULL) { -+ dp = dtrace_difo_duplicate(dp, vstate); -+ new->dtha_predicate = dp; -+ } -+ -+ new->dtha_nactions = helper->dtha_nactions; -+ sz = sizeof(struct dtrace_difo *) * new->dtha_nactions; -+ new->dtha_actions = vmalloc(sz); -+ -+ for (j = 0; j < new->dtha_nactions; j++) { -+ struct dtrace_difo *dp; -+ -+ dp = helper->dtha_actions[j]; -+ ASSERT(dp != NULL); -+ -+ dp = dtrace_difo_duplicate(dp, vstate); -+ new->dtha_actions[j] = dp; -+ } -+ -+ if (last != NULL) -+ last->dtha_next = new; -+ else -+ newhelp->dthps_actions[i] = new; -+ -+ last = new; -+ } -+ } -+ -+ /* -+ * Duplicate the helper providers and register them with the -+ * DTrace framework. -+ */ -+ if (help->dthps_nprovs > 0) { -+ newhelp->dthps_nprovs = help->dthps_nprovs; -+ newhelp->dthps_maxprovs = help->dthps_nprovs; -+ newhelp->dthps_provs = vmalloc( -+ newhelp->dthps_nprovs * -+ sizeof(struct dtrace_helper_provider *)); -+ -+ for (i = 0; i < newhelp->dthps_nprovs; i++) { -+ newhelp->dthps_provs[i] = help->dthps_provs[i]; -+ newhelp->dthps_provs[i]->dthp_ref++; -+ } -+ -+ hasprovs = 1; -+ } -+ -+ mutex_unlock(&dtrace_lock); -+ -+ if (hasprovs) -+ dtrace_helper_provider_register(to, newhelp, NULL); -+} -+ -+int dtrace_helper_destroygen(int gen) -+{ -+ struct task_struct *p = current; -+ struct dtrace_helpers *dth; -+ struct dtrace_vstate *vstate; -+ int i; -+ -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ -+ if (current->dt_task == NULL) -+ return -ENOMEM; -+ -+ dth = current->dt_task->dt_helpers; -+ -+ if (dth == NULL || gen > dth->dthps_generation) -+ return -EINVAL; -+ -+ vstate = &dth->dthps_vstate; -+ -+ for (i = 0; i < DTRACE_NHELPER_ACTIONS; i++) { -+ struct dtrace_helper_action *last = NULL, *h, *next; -+ -+ for (h = dth->dthps_actions[i]; h != NULL; h = next) { -+ next = h->dtha_next; -+ -+ dt_dbg_dof(" Comparing action (agen %d vs rgen %d)\n", -+ h->dtha_generation, gen); -+ -+ if (h->dtha_generation == gen) { -+ if (last != NULL) -+ last->dtha_next = next; -+ else -+ dth->dthps_actions[i] = next; -+ -+ dtrace_helper_action_destroy(h, vstate); -+ } else -+ last = h; -+ } -+ } -+ -+ /* -+ * Iterate until we've cleared out all helper providers with the given -+ * generation number. -+ */ -+ for (;;) { -+ struct dtrace_helper_provider *prov = NULL; -+ -+ /* -+ * Look for a helper provider with the right generation. We -+ * have to start back at the beginning of the list each time -+ * because we drop dtrace_lock. It's unlikely that we'll make -+ * more than two passes. -+ */ -+ for (i = 0; i < dth->dthps_nprovs; i++) { -+ prov = dth->dthps_provs[i]; -+ -+ if (prov->dthp_generation == gen) -+ break; -+ } -+ -+ /* -+ * If there were no matches, we are done. -+ */ -+ if (i == dth->dthps_nprovs) -+ break; -+ -+ dt_dbg_dof(" Found provider with gen %d\n", gen); -+ -+ /* -+ * Move the last helper provider into this slot. -+ */ -+ dth->dthps_nprovs--; -+ dth->dthps_provs[i] = dth->dthps_provs[dth->dthps_nprovs]; -+ dth->dthps_provs[dth->dthps_nprovs] = NULL; -+ -+ mutex_unlock(&dtrace_lock); -+ -+ /* -+ * If we have a meta provider, remove this helper provider. -+ */ -+ mutex_lock(&dtrace_meta_lock); -+ -+ if (dtrace_meta_pid != NULL) { -+ ASSERT(dtrace_deferred_pid == NULL); -+ -+ dtrace_helper_provider_remove(&prov->dthp_prov, -+ p->pid); -+ } -+ -+ mutex_unlock(&dtrace_meta_lock); -+ -+ dtrace_helper_provider_destroy(prov); -+ -+ mutex_lock(&dtrace_lock); -+ } -+ -+ return 0; -+} -+ -+static void dtrace_helper_trace(struct dtrace_helper_action *helper, -+ struct dtrace_mstate *mstate, -+ struct dtrace_vstate *vstate, int where) -+{ -+ uint32_t size, next, nnext, i; -+ struct dtrace_helptrace *ent; -+ uint16_t flags = this_cpu_core->cpuc_dtrace_flags; -+ -+ if (!dtrace_helptrace_enabled) -+ return; -+ -+ ASSERT(vstate->dtvs_nlocals <= dtrace_helptrace_nlocals); -+ -+ /* -+ * What would a tracing framework be without its own tracing -+ * framework? (Well, a hell of a lot simpler, for starters...) -+ */ -+ size = sizeof(struct dtrace_helptrace) + dtrace_helptrace_nlocals * -+ sizeof(uint64_t) - sizeof(uint64_t); -+ -+ /* -+ * Iterate until we can allocate a slot in the trace buffer. -+ */ -+ do { -+ next = dtrace_helptrace_next; -+ -+ if (next + size < dtrace_helptrace_bufsize) -+ nnext = next + size; -+ else -+ nnext = size; -+ } while (cmpxchg(&dtrace_helptrace_next, next, nnext) != next); -+ -+ /* -+ * We have our slot; fill it in. -+ */ -+ if (nnext == size) -+ next = 0; -+ -+ ent = (struct dtrace_helptrace *)&dtrace_helptrace_buffer[next]; -+ ent->dtht_helper = helper; -+ ent->dtht_where = where; -+ ent->dtht_nlocals = vstate->dtvs_nlocals; -+ -+ ent->dtht_fltoffs = (mstate->dtms_present & DTRACE_MSTATE_FLTOFFS) -+ ? mstate->dtms_fltoffs -+ : -1; -+ ent->dtht_fault = DTRACE_FLAGS2FLT(flags); -+ ent->dtht_illval = this_cpu_core->cpuc_dtrace_illval; -+ -+ for (i = 0; i < vstate->dtvs_nlocals; i++) { -+ struct dtrace_statvar *svar; -+ -+ svar = vstate->dtvs_locals[i]; -+ if (svar == NULL) -+ continue; -+ -+ ASSERT(svar->dtsv_size >= NR_CPUS * sizeof(uint64_t)); -+ ent->dtht_locals[i] = -+ ((uint64_t *)(uintptr_t)svar->dtsv_data)[ -+ smp_processor_id()]; -+ } -+} -+ -+uint64_t dtrace_helper(int which, struct dtrace_mstate *mstate, -+ struct dtrace_state *state, uint64_t arg0, -+ uint64_t arg1) -+{ -+ uint16_t *flags = &this_cpu_core->cpuc_dtrace_flags; -+ uint64_t sarg0 = mstate->dtms_arg[0]; -+ uint64_t sarg1 = mstate->dtms_arg[1]; -+ uint64_t rval = 0; -+ struct dtrace_helpers *helpers; -+ struct dtrace_helper_action *helper; -+ struct dtrace_vstate *vstate; -+ struct dtrace_difo *pred; -+ int i, trace = dtrace_helptrace_enabled; -+ -+ ASSERT(which >= 0 && which < DTRACE_NHELPER_ACTIONS); -+ -+ if (current->dt_task == NULL) -+ return 0; -+ -+ helpers = current->dt_task->dt_helpers; -+ if (helpers == NULL) -+ return 0; -+ -+ helper = helpers->dthps_actions[which]; -+ if (helper == NULL) -+ return 0; -+ -+ vstate = &helpers->dthps_vstate; -+ mstate->dtms_arg[0] = arg0; -+ mstate->dtms_arg[1] = arg1; -+ -+ /* -+ * Now iterate over each helper. If its predicate evaluates to 'true', -+ * we'll call the corresponding actions. Note that the below calls -+ * to dtrace_dif_emulate() may set faults in machine state. This is -+ * okay: our caller (the outer dtrace_dif_emulate()) will simply plow -+ * the stored DIF offset with its own (which is the desired behavior). -+ * Also, note the calls to dtrace_dif_emulate() may allocate scratch -+ * from machine state; this is okay, too. -+ */ -+ for (; helper != NULL; helper = helper->dtha_next) { -+ pred = helper->dtha_predicate; -+ if (pred != NULL) { -+ if (trace) -+ dtrace_helper_trace(helper, mstate, vstate, 0); -+ -+ if (!dtrace_dif_emulate(pred, mstate, vstate, state)) -+ goto next; -+ -+ if (*flags & CPU_DTRACE_FAULT) -+ goto err; -+ } -+ -+ for (i = 0; i < helper->dtha_nactions; i++) { -+ if (trace) -+ dtrace_helper_trace(helper, mstate, vstate, -+ i + 1); -+ -+ rval = dtrace_dif_emulate(helper->dtha_actions[i], -+ mstate, vstate, state); -+ -+ if (*flags & CPU_DTRACE_FAULT) -+ goto err; -+ } -+ -+next: -+ if (trace) -+ dtrace_helper_trace(helper, mstate, vstate, -+ DTRACE_HELPTRACE_NEXT); -+ } -+ -+ if (trace) -+ dtrace_helper_trace(helper, mstate, vstate, -+ DTRACE_HELPTRACE_DONE); -+ -+ /* -+ * Restore the arg0 that we saved upon entry. -+ */ -+ mstate->dtms_arg[0] = sarg0; -+ mstate->dtms_arg[1] = sarg1; -+ -+ return rval; -+ -+err: -+ if (trace) -+ dtrace_helper_trace(helper, mstate, vstate, -+ DTRACE_HELPTRACE_ERR); -+ -+ /* -+ * Restore the arg0 that we saved upon entry. -+ */ -+ mstate->dtms_arg[0] = sarg0; -+ mstate->dtms_arg[1] = sarg1; -+ -+ return 0; -+} -diff --git a/dtrace/dtrace_ecb.c b/dtrace/dtrace_ecb.c -new file mode 100644 -index 0000000000000000000000000000000000000000..cc04d1a14661b08694a09a3d741523d9380b0dd2 ---- /dev/null -+++ b/dtrace/dtrace_ecb.c -@@ -0,0 +1,936 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_ecb.c -+ * DESCRIPTION: DTrace - ECB implementation -+ * -+ * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/slab.h> -+#include <linux/vmalloc.h> -+ -+#include "dtrace.h" -+ -+struct dtrace_ecb *dtrace_ecb_create_cache; -+ -+static struct dtrace_action * -+dtrace_ecb_aggregation_create(struct dtrace_ecb *ecb, -+ struct dtrace_actdesc *desc) -+{ -+ struct dtrace_aggregation *agg; -+ size_t size = sizeof(uint64_t); -+ int ntuple = desc->dtad_ntuple; -+ struct dtrace_action *act; -+ struct dtrace_recdesc *frec; -+ dtrace_aggid_t aggid; -+ struct dtrace_state *state = ecb->dte_state; -+ -+ agg = kzalloc(sizeof(struct dtrace_aggregation), GFP_KERNEL); -+ if (agg == NULL) -+ return NULL; -+ -+ agg->dtag_ecb = ecb; -+ -+ ASSERT(DTRACEACT_ISAGG(desc->dtad_kind)); -+ -+ switch (desc->dtad_kind) { -+ case DTRACEAGG_MIN: -+ agg->dtag_initial = INT64_MAX; -+ agg->dtag_aggregate = dtrace_aggregate_min; -+ break; -+ -+ case DTRACEAGG_MAX: -+ agg->dtag_initial = INT64_MIN; -+ agg->dtag_aggregate = dtrace_aggregate_max; -+ break; -+ -+ case DTRACEAGG_COUNT: -+ agg->dtag_aggregate = dtrace_aggregate_count; -+ break; -+ -+ case DTRACEAGG_QUANTIZE: -+ agg->dtag_aggregate = dtrace_aggregate_quantize; -+ size = (((sizeof(uint64_t) * NBBY) - 1) * 2 + 1) * -+ sizeof(uint64_t); -+ break; -+ -+ case DTRACEAGG_LQUANTIZE: { -+ uint16_t step = DTRACE_LQUANTIZE_STEP(desc->dtad_arg); -+ uint16_t levels = -+ DTRACE_LQUANTIZE_LEVELS(desc->dtad_arg); -+ -+ agg->dtag_initial = desc->dtad_arg; -+ agg->dtag_aggregate = dtrace_aggregate_lquantize; -+ -+ if (step == 0 || levels == 0) -+ goto err; -+ -+ size = levels * sizeof(uint64_t) + 3 * sizeof(uint64_t); -+ break; -+ } -+ -+ case DTRACEAGG_LLQUANTIZE: { -+ uint16_t factor = DTRACE_LLQUANTIZE_FACTOR(desc->dtad_arg); -+ uint16_t lmag = DTRACE_LLQUANTIZE_LMAG(desc->dtad_arg); -+ uint16_t hmag = DTRACE_LLQUANTIZE_HMAG(desc->dtad_arg); -+ uint16_t steps = DTRACE_LLQUANTIZE_STEPS(desc->dtad_arg); -+ uint64_t buf64s; -+ -+ agg->dtag_initial = desc->dtad_arg; -+ agg->dtag_aggregate = dtrace_aggregate_llquantize; -+ -+ /* -+ * 64 is the largest hmag can practically be (for the smallest -+ * possible value of factor, 2). libdtrace has already checked -+ * for overflow, so if hmag > 64, we have corrupted DOF. -+ */ -+ if (factor < 2 || steps == 0 || hmag > 64) -+ goto err; -+ -+ /* -+ * The size of the buffer for an llquantize() is given by: -+ * (hmag-lmag+1) logarithmic ranges -+ * x -+ * (steps - steps/factor) bins per range -+ * x -+ * 2 signs -+ * + -+ * two overflow bins -+ * + -+ * one underflow bin -+ * + -+ * beginning word to encode factor,lmag,hmag,steps -+ */ -+ buf64s = ((hmag-lmag+1)*(steps-steps/factor)*2+4); -+ size = buf64s * sizeof(uint64_t); -+ break; -+ } -+ -+ case DTRACEAGG_AVG: -+ agg->dtag_aggregate = dtrace_aggregate_avg; -+ size = sizeof(uint64_t) * 2; -+ break; -+ -+ case DTRACEAGG_STDDEV: -+ agg->dtag_aggregate = dtrace_aggregate_stddev; -+ size = sizeof(uint64_t) * 4; -+ break; -+ -+ case DTRACEAGG_SUM: -+ agg->dtag_aggregate = dtrace_aggregate_sum; -+ break; -+ -+ default: -+ goto err; -+ } -+ -+ agg->dtag_action.dta_rec.dtrd_size = size; -+ -+ if (ntuple == 0) -+ goto err; -+ -+ for (act = ecb->dte_action_last; act != NULL; act = act->dta_prev) { -+ if (DTRACEACT_ISAGG(act->dta_kind)) -+ break; -+ -+ if (--ntuple == 0) { -+ agg->dtag_first = act; -+ goto success; -+ } -+ } -+ -+ ASSERT(ntuple != 0); -+err: -+ kfree(agg); -+ return NULL; -+ -+success: -+ ASSERT(ecb->dte_action_last != NULL); -+ act = ecb->dte_action_last; -+ -+ if (act->dta_kind == DTRACEACT_DIFEXPR) { -+ ASSERT(act->dta_difo != NULL); -+ -+ if (act->dta_difo->dtdo_rtype.dtdt_size == 0) -+ agg->dtag_hasarg = 1; -+ } -+ -+ /* -+ * Get an ID for the aggregation (add it to the idr). -+ */ -+ idr_preload(GFP_KERNEL); -+ aggid = idr_alloc_cyclic(&state->dts_agg_idr, agg, 0, 0, GFP_NOWAIT); -+ idr_preload_end(); -+ if (aggid < 0) { -+ /* FIXME: need to handle this */ -+ } -+ -+ state->dts_naggs++; -+ agg->dtag_id = aggid; -+ -+ frec = &agg->dtag_first->dta_rec; -+ if (frec->dtrd_alignment < sizeof(dtrace_aggid_t)) -+ frec->dtrd_alignment = sizeof(dtrace_aggid_t); -+ -+ for (act = agg->dtag_first; act != NULL; act = act->dta_next) { -+ ASSERT(!act->dta_intuple); -+ -+ act->dta_intuple = 1; -+ } -+ -+ return &agg->dtag_action; -+} -+ -+void dtrace_ecb_aggregation_destroy(struct dtrace_ecb *ecb, -+ struct dtrace_action *act) -+{ -+ struct dtrace_aggregation *agg = (struct dtrace_aggregation *)act; -+ struct dtrace_state *state = ecb->dte_state; -+ -+ ASSERT(DTRACEACT_ISAGG(act->dta_kind)); -+ -+ idr_remove(&state->dts_agg_idr, agg->dtag_id); -+ state->dts_naggs--; -+ -+ kfree(agg); -+} -+ -+static int dtrace_ecb_action_add(struct dtrace_ecb *ecb, -+ struct dtrace_actdesc *desc) -+{ -+ struct dtrace_action *action, *last; -+ struct dtrace_difo *dp = desc->dtad_difo; -+ uint32_t size = 0, align = sizeof(uint8_t), mask; -+ uint16_t format = 0; -+ struct dtrace_recdesc *rec; -+ struct dtrace_state *state = ecb->dte_state; -+ dtrace_optval_t *opt = state->dts_options, nframes, strsize; -+ uint64_t arg = desc->dtad_arg; -+ -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ ASSERT(ecb->dte_action == NULL || ecb->dte_action->dta_refcnt == 1); -+ -+ if (DTRACEACT_ISAGG(desc->dtad_kind)) { -+ struct dtrace_action *act; -+ -+ for (act = ecb->dte_action; act != NULL; act = act->dta_next) { -+ if (act->dta_kind == DTRACEACT_COMMIT) -+ return -EINVAL; -+ -+ if (act->dta_kind == DTRACEACT_SPECULATE) -+ return -EINVAL; -+ } -+ -+ action = dtrace_ecb_aggregation_create(ecb, desc); -+ if (action == NULL) -+ return -EINVAL; -+ } else { -+ if (DTRACEACT_ISDESTRUCTIVE(desc->dtad_kind) || -+ (desc->dtad_kind == DTRACEACT_DIFEXPR && -+ dp != NULL && dp->dtdo_destructive)) -+ state->dts_destructive = 1; -+ -+ switch (desc->dtad_kind) { -+ case DTRACEACT_PRINTF: -+ case DTRACEACT_PRINTA: -+ case DTRACEACT_SYSTEM: -+ case DTRACEACT_FREOPEN: -+ if ((void *)(uintptr_t)arg == NULL) { -+ ASSERT(desc->dtad_kind == DTRACEACT_PRINTA); -+ -+ format = 0; -+ } else { -+ ASSERT((void *)(uintptr_t)arg != NULL); -+#ifdef FIXME -+ ASSERT(arg > KERNELBASE); -+#endif -+ -+ format = dtrace_format_add( -+ state, (char *)(uintptr_t)arg); -+ } -+ /* fallthru */ -+ -+ case DTRACEACT_TRACEMEM: -+ case DTRACEACT_LIBACT: -+ case DTRACEACT_DIFEXPR: -+ if (dp == NULL) -+ return -EINVAL; -+ -+ size = dp->dtdo_rtype.dtdt_size; -+ if (size != 0) -+ break; -+ -+ if (dp->dtdo_rtype.dtdt_kind == DIF_TYPE_STRING) { -+ if (!(dp->dtdo_rtype.dtdt_flags & DIF_TF_BYREF)) -+ return -EINVAL; -+ -+ size = opt[DTRACEOPT_STRSIZE]; -+ } -+ -+ break; -+ -+ case DTRACEACT_STACK: -+ nframes = arg; -+ if (nframes == 0) { -+ nframes = opt[DTRACEOPT_STACKFRAMES]; -+ -+ ASSERT(nframes > 0); -+ -+ arg = nframes; -+ } -+ -+ size = nframes * sizeof(uint64_t); -+ break; -+ -+ case DTRACEACT_JSTACK: -+ strsize = DTRACE_USTACK_STRSIZE(arg); -+ if (strsize == 0) -+ strsize = opt[DTRACEOPT_JSTACKSTRSIZE]; -+ -+ nframes = DTRACE_USTACK_NFRAMES(arg); -+ if (nframes == 0) -+ nframes = opt[DTRACEOPT_JSTACKFRAMES]; -+ -+ arg = DTRACE_USTACK_ARG(nframes, strsize); -+ /* fallthru */ -+ -+ case DTRACEACT_USTACK: -+ if (desc->dtad_kind != DTRACEACT_JSTACK && -+ (nframes = DTRACE_USTACK_NFRAMES(arg)) == 0) { -+ strsize = DTRACE_USTACK_STRSIZE(arg); -+ nframes = opt[DTRACEOPT_USTACKFRAMES]; -+ -+ ASSERT(nframes > 0); -+ -+ arg = DTRACE_USTACK_ARG(nframes, strsize); -+ } -+ -+ size = (nframes + 2) * sizeof(uint64_t); -+ size += DTRACE_USTACK_STRSIZE(arg); -+ size = P2ROUNDUP(size, (uint32_t)(sizeof(uintptr_t))); -+ -+ break; -+ -+ case DTRACEACT_SYM: -+ case DTRACEACT_MOD: -+ if (dp == NULL || ((size = dp->dtdo_rtype.dtdt_size) != -+ sizeof(uint64_t)) || -+ (dp->dtdo_rtype.dtdt_flags & DIF_TF_BYREF)) -+ return -EINVAL; -+ -+ break; -+ -+ case DTRACEACT_USYM: -+ case DTRACEACT_UMOD: -+ case DTRACEACT_UADDR: -+ if (dp == NULL || -+ (dp->dtdo_rtype.dtdt_size != sizeof(uint64_t)) || -+ (dp->dtdo_rtype.dtdt_flags & DIF_TF_BYREF)) -+ return -EINVAL; -+ -+ size = 3 * sizeof(uint64_t); -+ -+ break; -+ -+ case DTRACEACT_STOP: -+ case DTRACEACT_BREAKPOINT: -+ case DTRACEACT_PANIC: -+ break; -+ -+ case DTRACEACT_CHILL: -+ case DTRACEACT_DISCARD: -+ case DTRACEACT_RAISE: -+ if (dp == NULL) -+ return -EINVAL; -+ -+ break; -+ -+ case DTRACEACT_EXIT: -+ if (dp == NULL || (size = dp->dtdo_rtype.dtdt_size) != -+ sizeof(int) || -+ (dp->dtdo_rtype.dtdt_flags & DIF_TF_BYREF)) -+ return -EINVAL; -+ -+ break; -+ -+ case DTRACEACT_SPECULATE: -+ if (ecb->dte_size > sizeof(dtrace_epid_t)) -+ return -EINVAL; -+ -+ if (dp == NULL) -+ return -EINVAL; -+ -+ state->dts_speculates = 1; -+ -+ break; -+ -+ case DTRACEACT_COMMIT: { -+ struct dtrace_action *act = ecb->dte_action; -+ -+ for (; act != NULL; act = act->dta_next) { -+ if (act->dta_kind == DTRACEACT_COMMIT) -+ return -EINVAL; -+ } -+ -+ if (dp == NULL) -+ return -EINVAL; -+ -+ break; -+ } -+ -+ case DTRACEACT_PCAP: -+ size = dp->dtdo_rtype.dtdt_size; -+ break; -+ -+ default: -+ return -EINVAL; -+ } -+ -+ if (size != 0 || desc->dtad_kind == DTRACEACT_SPECULATE) { -+ struct dtrace_action *act = ecb->dte_action; -+ -+ for (; act != NULL; act = act->dta_next) { -+ if (act->dta_kind == DTRACEACT_COMMIT) -+ return -EINVAL; -+ } -+ } -+ -+ action = kzalloc(sizeof(struct dtrace_action), GFP_KERNEL); -+ if (action == NULL) -+ return -ENOMEM; -+ -+ action->dta_rec.dtrd_size = size; -+ } -+ -+ action->dta_refcnt = 1; -+ rec = &action->dta_rec; -+ size = rec->dtrd_size; -+ -+ for (mask = sizeof(uint64_t) - 1; size != 0 && mask > 0; mask >>= 1) { -+ if (!(size & mask)) { -+ align = mask + 1; -+ -+ break; -+ } -+ } -+ -+ action->dta_kind = desc->dtad_kind; -+ -+ action->dta_difo = dp; -+ if (action->dta_difo != NULL) -+ dtrace_difo_hold(dp); -+ -+ rec->dtrd_action = action->dta_kind; -+ rec->dtrd_arg = arg; -+ rec->dtrd_uarg = desc->dtad_uarg; -+ rec->dtrd_alignment = (uint16_t)align; -+ rec->dtrd_format = format; -+ -+ last = ecb->dte_action_last; -+ if (last != NULL) { -+ ASSERT(ecb->dte_action != NULL); -+ -+ action->dta_prev = last; -+ last->dta_next = action; -+ } else { -+ ASSERT(ecb->dte_action == NULL); -+ -+ ecb->dte_action = action; -+ } -+ -+ ecb->dte_action_last = action; -+ -+ return 0; -+} -+ -+static void dtrace_ecb_action_remove(struct dtrace_ecb *ecb) -+{ -+ struct dtrace_action *act = ecb->dte_action, *next; -+ struct dtrace_vstate *vstate = &ecb->dte_state->dts_vstate; -+ struct dtrace_difo *dp; -+ uint16_t format; -+ -+ if (act != NULL && act->dta_refcnt > 1) { -+ ASSERT(act->dta_next == NULL || act->dta_next->dta_refcnt == 1); -+ -+ act->dta_refcnt--; -+ } else { -+ for (; act != NULL; act = next) { -+ next = act->dta_next; -+ ASSERT(next != NULL || act == ecb->dte_action_last); -+ ASSERT(act->dta_refcnt == 1); -+ -+ format = act->dta_rec.dtrd_format; -+ if (format != 0) -+ dtrace_format_remove(ecb->dte_state, format); -+ -+ dp = act->dta_difo; -+ if (dp != NULL) -+ dtrace_difo_release(dp, vstate); -+ -+ if (DTRACEACT_ISAGG(act->dta_kind)) -+ dtrace_ecb_aggregation_destroy(ecb, act); -+ else -+ kfree(act); -+ } -+ } -+ -+ ecb->dte_action = NULL; -+ ecb->dte_action_last = NULL; -+ ecb->dte_size = sizeof(dtrace_epid_t); -+} -+ -+/* -+ * Disable the ECB by removing it from its probe. -+ */ -+void dtrace_ecb_disable(struct dtrace_ecb *ecb) -+{ -+ struct dtrace_ecb *pecb, *prev = NULL; -+ struct dtrace_probe *probe = ecb->dte_probe; -+ -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ -+ if (probe == NULL) -+ return; -+ -+ for (pecb = probe->dtpr_ecb; pecb != NULL; pecb = pecb->dte_next) { -+ if (pecb == ecb) -+ break; -+ -+ prev = pecb; -+ } -+ -+ ASSERT(pecb != NULL); -+ -+ if (prev == NULL) -+ probe->dtpr_ecb = ecb->dte_next; -+ else -+ prev->dte_next = ecb->dte_next; -+ -+ if (ecb == probe->dtpr_ecb_last) { -+ ASSERT(ecb->dte_next == NULL); -+ probe->dtpr_ecb_last = prev; -+ } -+ -+ /* -+ * The ECB has been disconnected from the probe; now sync to assure -+ * that all CPUs have seen the change before returning. -+ */ -+ dtrace_sync(); -+ -+ if (probe->dtpr_ecb == NULL) { -+ /* -+ * That was the last ECB on the probe; clear the predicate -+ * cache ID for the probe, disable it and sync one more time -+ * to assure that we'll never hit it again. -+ */ -+ struct dtrace_provider *prov = probe->dtpr_provider; -+ -+ ASSERT(ecb->dte_next == NULL); -+ ASSERT(probe->dtpr_ecb_last == NULL); -+ -+ probe->dtpr_predcache = DTRACE_CACHEIDNONE; -+ prov->dtpv_pops.dtps_disable(prov->dtpv_arg, -+ probe->dtpr_id, probe->dtpr_arg); -+ -+ dtrace_sync(); -+ } else { -+ /* -+ * There is at least one ECB remaining on the probe. If there -+ * is _exactly_ one, set the probe's predicate cache ID to be -+ * the predicate cache ID of the remaining ECB. -+ */ -+ ASSERT(probe->dtpr_ecb_last != NULL); -+ ASSERT(probe->dtpr_predcache == DTRACE_CACHEIDNONE); -+ -+ if (probe->dtpr_ecb == probe->dtpr_ecb_last) { -+ struct dtrace_predicate *p = -+ probe->dtpr_ecb->dte_predicate; -+ -+ ASSERT(probe->dtpr_ecb->dte_next == NULL); -+ -+ if (p != NULL) -+ probe->dtpr_predcache = p->dtp_cacheid; -+ } -+ -+ ecb->dte_next = NULL; -+ } -+} -+ -+static struct dtrace_ecb *dtrace_ecb_add(struct dtrace_state *state, -+ struct dtrace_probe *probe) -+{ -+ struct dtrace_ecb *ecb; -+ dtrace_epid_t epid; -+ -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ -+ ecb = kzalloc(sizeof(struct dtrace_ecb), GFP_KERNEL); -+ if (ecb == NULL) -+ return NULL; -+ -+ ecb->dte_predicate = NULL; -+ ecb->dte_probe = probe; -+ ecb->dte_size = ecb->dte_needed = sizeof(dtrace_epid_t); -+ ecb->dte_alignment = sizeof(dtrace_epid_t); -+ -+ epid = state->dts_epid++; -+ -+ if (epid - 1 >= state->dts_necbs) { -+ struct dtrace_ecb **oecbs = state->dts_ecbs, **ecbs; -+ int necbs = state->dts_necbs << 1; -+ -+ ASSERT(epid == state->dts_necbs + 1); -+ -+ if (necbs == 0) { -+ ASSERT(oecbs == NULL); -+ -+ necbs = 1; -+ } -+ -+ ecbs = vzalloc(necbs * sizeof(*ecbs)); -+ if (ecbs == NULL) { -+ kfree(ecb); -+ return NULL; -+ } -+ -+ if (oecbs != NULL) -+ memcpy(ecbs, oecbs, state->dts_necbs * sizeof(*ecbs)); -+ -+ dtrace_membar_producer(); -+ -+ state->dts_ecbs = ecbs; -+ -+ if (oecbs != NULL) { -+ if (state->dts_activity != DTRACE_ACTIVITY_INACTIVE) -+ dtrace_sync(); -+ -+ vfree(oecbs); -+ } -+ -+ dtrace_membar_producer(); -+ -+ state->dts_necbs = necbs; -+ } -+ -+ ecb->dte_state = state; -+ -+ ASSERT(state->dts_ecbs[epid - 1] == NULL); -+ -+ dtrace_membar_producer(); -+ -+ state->dts_ecbs[(ecb->dte_epid = epid) - 1] = ecb; -+ -+ return ecb; -+} -+ -+static struct dtrace_ecb * dtrace_ecb_create(struct dtrace_state *state, -+ struct dtrace_probe *probe, -+ struct dtrace_enabling *enab) -+{ -+ struct dtrace_ecb *ecb; -+ struct dtrace_predicate *pred; -+ struct dtrace_actdesc *act; -+ struct dtrace_provider *prov; -+ struct dtrace_ecbdesc *desc = enab->dten_current; -+ -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ ASSERT(state != NULL); -+ -+ ecb = dtrace_ecb_add(state, probe); -+ if (ecb == NULL) -+ return NULL; -+ -+ ecb->dte_uarg = desc->dted_uarg; -+ -+ pred = desc->dted_pred.dtpdd_predicate; -+ if (pred != NULL) { -+ dtrace_predicate_hold(pred); -+ ecb->dte_predicate = pred; -+ } -+ -+ if (probe != NULL) { -+ prov = probe->dtpr_provider; -+ -+ if (!(state->dts_cred.dcr_visible & DTRACE_CRV_ALLPROC) && -+ (prov->dtpv_priv.dtpp_flags & DTRACE_PRIV_USER)) -+ ecb->dte_cond |= DTRACE_COND_OWNER; -+ -+ if (!(state->dts_cred.dcr_visible & DTRACE_CRV_KERNEL) && -+ (prov->dtpv_priv.dtpp_flags & DTRACE_PRIV_KERNEL)) -+ ecb->dte_cond |= DTRACE_COND_USERMODE; -+ } -+ -+ if (dtrace_ecb_create_cache != NULL) { -+ struct dtrace_ecb *cached = dtrace_ecb_create_cache; -+ struct dtrace_action *act = cached->dte_action; -+ -+ if (act != NULL) { -+ ASSERT(act->dta_refcnt > 0); -+ -+ act->dta_refcnt++; -+ ecb->dte_action = act; -+ ecb->dte_action_last = cached->dte_action_last; -+ ecb->dte_needed = cached->dte_needed; -+ ecb->dte_size = cached->dte_size; -+ ecb->dte_alignment = cached->dte_alignment; -+ } -+ -+ return ecb; -+ } -+ -+ for (act = desc->dted_action; act != NULL; act = act->dtad_next) { -+ enab->dten_error = dtrace_ecb_action_add(ecb, act); -+ if (enab->dten_error != 0) { -+ dtrace_ecb_destroy(ecb); -+ return NULL; -+ } -+ } -+ -+ dtrace_ecb_resize(ecb); -+ -+ return (dtrace_ecb_create_cache = ecb); -+} -+ -+int dtrace_ecb_create_enable(struct dtrace_probe *probe, void *arg) -+{ -+ struct dtrace_ecb *ecb; -+ struct dtrace_enabling *enab = arg; -+ struct dtrace_state *state = enab->dten_vstate->dtvs_state; -+ -+ ASSERT(state != NULL); -+ -+ if (probe != NULL && probe->dtpr_gen < enab->dten_probegen) -+ return DTRACE_MATCH_NEXT; -+ -+ ecb = dtrace_ecb_create(state, probe, enab); -+ if (ecb == NULL) -+ return DTRACE_MATCH_DONE; -+ -+ if (dtrace_ecb_enable(ecb) < 0) -+ return DTRACE_MATCH_FAIL; -+ -+ return DTRACE_MATCH_NEXT; -+} -+ -+void dtrace_ecb_destroy(struct dtrace_ecb *ecb) -+{ -+ struct dtrace_state *state = ecb->dte_state; -+ struct dtrace_vstate *vstate = &state->dts_vstate; -+ struct dtrace_predicate *pred; -+ dtrace_epid_t epid = ecb->dte_epid; -+ -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ ASSERT(ecb->dte_next == NULL); -+ ASSERT(ecb->dte_probe == NULL || ecb->dte_probe->dtpr_ecb != ecb); -+ -+ pred = ecb->dte_predicate; -+ if (pred != NULL) -+ dtrace_predicate_release(pred, vstate); -+ -+ dtrace_ecb_action_remove(ecb); -+ -+ ASSERT(state->dts_ecbs[epid - 1] == ecb); -+ state->dts_ecbs[epid - 1] = NULL; -+ -+ kfree(ecb); -+} -+ -+void dtrace_ecb_resize(struct dtrace_ecb *ecb) -+{ -+ struct dtrace_action *act; -+ uint32_t maxalign = sizeof(dtrace_epid_t); -+ uint32_t align = sizeof(uint8_t), offs, diff; -+ int wastuple = 0; -+ uint32_t aggbase = UINT32_MAX; -+ struct dtrace_state *state = ecb->dte_state; -+ -+ /* -+ * If we record anything, we always record the epid. (And we always -+ * record it first.) -+ */ -+ offs = sizeof(dtrace_epid_t); -+ ecb->dte_size = ecb->dte_needed = sizeof(dtrace_epid_t); -+ -+ for (act = ecb->dte_action; act != NULL; act = act->dta_next) { -+ struct dtrace_recdesc *rec = &act->dta_rec; -+ -+ align = rec->dtrd_alignment; -+ if (align > maxalign) -+ maxalign = align; -+ -+ if (!wastuple && act->dta_intuple) { -+ /* -+ * This is the first record in a tuple. Align the -+ * offset to be at offset 4 in an 8-byte aligned -+ * block. -+ */ -+ diff = offs + sizeof(dtrace_aggid_t); -+ -+ diff &= sizeof(uint64_t) - 1; -+ if (diff) -+ offs += sizeof(uint64_t) - diff; -+ -+ aggbase = offs - sizeof(dtrace_aggid_t); -+ ASSERT(!(aggbase & (sizeof(uint64_t) - 1))); -+ } -+ -+ if (rec->dtrd_size != 0) { -+ diff = offs & (align - 1); -+ if (diff) -+ /* -+ * The current offset is not properly -+ * aligned; align it. -+ */ -+ offs += align - diff; -+ } -+ -+ rec->dtrd_offset = offs; -+ -+ if (offs + rec->dtrd_size > ecb->dte_needed) { -+ ecb->dte_needed = offs + rec->dtrd_size; -+ -+ if (ecb->dte_needed > state->dts_needed) -+ state->dts_needed = ecb->dte_needed; -+ } -+ -+ if (DTRACEACT_ISAGG(act->dta_kind)) { -+ struct dtrace_aggregation *agg; -+ struct dtrace_action *first, *prev; -+ -+ agg = (struct dtrace_aggregation *)act; -+ first = agg->dtag_first; -+ -+ ASSERT(rec->dtrd_size != 0 && first != NULL); -+ ASSERT(wastuple); -+ ASSERT(aggbase != UINT32_MAX); -+ -+ agg->dtag_base = aggbase; -+ -+ while ((prev = first->dta_prev) != NULL && -+ DTRACEACT_ISAGG(prev->dta_kind)) { -+ agg = (struct dtrace_aggregation *)prev; -+ first = agg->dtag_first; -+ } -+ -+ if (prev != NULL) { -+ offs = prev->dta_rec.dtrd_offset + -+ prev->dta_rec.dtrd_size; -+ } else -+ offs = sizeof(dtrace_epid_t); -+ -+ wastuple = 0; -+ } else { -+ if (!act->dta_intuple) -+ ecb->dte_size = offs + rec->dtrd_size; -+ -+ offs += rec->dtrd_size; -+ } -+ -+ wastuple = act->dta_intuple; -+ } -+ -+ act = ecb->dte_action; -+ if (act != NULL && -+ !(act->dta_kind == DTRACEACT_SPECULATE && act->dta_next == NULL) && -+ ecb->dte_size == sizeof(dtrace_epid_t)) { -+ /* -+ * If the size is still sizeof(dtrace_epid_t), then all -+ * actions store no data; set the size to 0. -+ */ -+ ecb->dte_alignment = maxalign; -+ ecb->dte_size = 0; -+ -+ /* -+ * If the needed space is still sizeof(dtrace_epid_t), then -+ * all actions need no additional space; set the needed -+ * size to 0. -+ */ -+ if (ecb->dte_needed == sizeof(dtrace_epid_t)) -+ ecb->dte_needed = 0; -+ -+ return; -+ } -+ -+ /* -+ * Set our alignment, and make sure that the dte_size and dte_needed -+ * are aligned to the size of an EPID. -+ */ -+ ecb->dte_alignment = maxalign; -+ ecb->dte_size = (ecb->dte_size + (sizeof(dtrace_epid_t) - 1)) & -+ ~(sizeof(dtrace_epid_t) - 1); -+ ecb->dte_needed = (ecb->dte_needed + (sizeof(dtrace_epid_t) - 1)) & -+ ~(sizeof(dtrace_epid_t) - 1); -+ ASSERT(ecb->dte_size <= ecb->dte_needed); -+} -+ -+int dtrace_ecb_enable(struct dtrace_ecb *ecb) -+{ -+ struct dtrace_probe *probe = ecb->dte_probe; -+ -+ ASSERT(MUTEX_HELD(&cpu_lock)); -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ ASSERT(ecb->dte_next == NULL); -+ -+ if (probe == NULL) -+ return 0; -+ -+ if (probe->dtpr_ecb == NULL) { -+ struct dtrace_provider *prov = probe->dtpr_provider; -+ -+ probe->dtpr_ecb = probe->dtpr_ecb_last = ecb; -+ -+ -+ if (ecb->dte_predicate != NULL) -+ probe->dtpr_predcache = ecb->dte_predicate->dtp_cacheid; -+ -+ return prov->dtpv_pops.dtps_enable(prov->dtpv_arg, -+ probe->dtpr_id, -+ probe->dtpr_arg); -+ } else { -+ ASSERT(probe->dtpr_ecb_last != NULL); -+ -+ probe->dtpr_ecb_last->dte_next = ecb; -+ probe->dtpr_ecb_last = ecb; -+ probe->dtpr_predcache = 0; -+ -+ dtrace_sync(); -+ -+ return 0; -+ } -+} -+ -+struct dtrace_ecb *dtrace_epid2ecb(struct dtrace_state *state, -+ dtrace_epid_t id) -+{ -+ struct dtrace_ecb *ecb; -+ -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ -+ if (id == 0 || id > state->dts_necbs) -+ return NULL; -+ -+ ASSERT(state->dts_necbs > 0 && state->dts_ecbs != NULL); -+ ecb = state->dts_ecbs[id - 1]; -+ ASSERT(ecb == NULL || ecb->dte_epid == id); -+ -+ return ecb; -+} -+ -+struct dtrace_aggregation *dtrace_aggid2agg(struct dtrace_state *state, -+ dtrace_aggid_t id) -+{ -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ -+ return idr_find(&state->dts_agg_idr, id); -+} -diff --git a/dtrace/dtrace_enable.c b/dtrace/dtrace_enable.c -new file mode 100644 -index 0000000000000000000000000000000000000000..72f30149cb9c6c7bad2d1f38303399bafdc86170 ---- /dev/null -+++ b/dtrace/dtrace_enable.c -@@ -0,0 +1,449 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_enable.c -+ * DESCRIPTION: DTrace - probe enabling implementation -+ * -+ * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/mutex.h> -+#include <linux/slab.h> -+#include <linux/vmalloc.h> -+ -+#include "dtrace.h" -+ -+size_t dtrace_retain_max = 1024; -+struct dtrace_enabling *dtrace_retained; -+dtrace_genid_t dtrace_retained_gen; -+ -+struct dtrace_enabling *dtrace_enabling_create(struct dtrace_vstate *vstate) -+{ -+ struct dtrace_enabling *enab; -+ -+ enab = kzalloc(sizeof(struct dtrace_enabling), GFP_KERNEL); -+ if (enab == NULL) -+ return NULL; -+ -+ enab->dten_vstate = vstate; -+ -+ return enab; -+} -+ -+void dtrace_enabling_add(struct dtrace_enabling *enab, -+ struct dtrace_ecbdesc *ecb) -+{ -+ struct dtrace_ecbdesc **ndesc; -+ size_t osize, nsize; -+ -+ /* -+ * We can't add to enablings after we've enabled them, or after we've -+ * retained them. -+ */ -+ ASSERT(enab->dten_probegen == 0); -+ ASSERT(enab->dten_next == NULL && enab->dten_prev == NULL); -+ -+ if (enab->dten_ndesc < enab->dten_maxdesc) { -+ enab->dten_desc[enab->dten_ndesc++] = ecb; -+ return; -+ } -+ -+ osize = enab->dten_maxdesc * sizeof(struct dtrace_enabling *); -+ -+ if (enab->dten_maxdesc == 0) -+ enab->dten_maxdesc = 1; -+ else -+ enab->dten_maxdesc <<= 1; -+ -+ ASSERT(enab->dten_ndesc < enab->dten_maxdesc); -+ -+ nsize = enab->dten_maxdesc * sizeof(struct dtrace_enabling *); -+ ndesc = vzalloc(nsize); -+ memcpy(ndesc, enab->dten_desc, osize); -+ vfree(enab->dten_desc); -+ -+ enab->dten_desc = ndesc; -+ enab->dten_desc[enab->dten_ndesc++] = ecb; -+} -+ -+static void dtrace_enabling_addlike(struct dtrace_enabling *enab, -+ struct dtrace_ecbdesc *ecb, -+ struct dtrace_probedesc *pd) -+{ -+ struct dtrace_ecbdesc *new; -+ struct dtrace_predicate *pred; -+ struct dtrace_actdesc *act; -+ -+ /* -+ * We're going to create a new ECB description that matches the -+ * specified ECB in every way, but has the specified probe description. -+ */ -+ new = kzalloc(sizeof(struct dtrace_ecbdesc), GFP_KERNEL); -+ -+ pred = ecb->dted_pred.dtpdd_predicate; -+ if (pred != NULL) -+ dtrace_predicate_hold(pred); -+ -+ for (act = ecb->dted_action; act != NULL; act = act->dtad_next) -+ dtrace_actdesc_hold(act); -+ -+ new->dted_action = ecb->dted_action; -+ new->dted_pred = ecb->dted_pred; -+ new->dted_probe = *pd; -+ new->dted_uarg = ecb->dted_uarg; -+ -+ dtrace_enabling_add(enab, new); -+} -+ -+void dtrace_enabling_dump(struct dtrace_enabling *enab) -+{ -+ int i; -+ -+ for (i = 0; i < enab->dten_ndesc; i++) { -+ struct dtrace_probedesc *desc = -+ &enab->dten_desc[i]->dted_probe; -+ -+ pr_info("enabling probe %d (%s:%s:%s:%s)", -+ i, desc->dtpd_provider, desc->dtpd_mod, -+ desc->dtpd_func, desc->dtpd_name); -+ } -+} -+ -+void dtrace_enabling_destroy(struct dtrace_enabling *enab) -+{ -+ int i; -+ struct dtrace_ecbdesc *ep; -+ struct dtrace_vstate *vstate = enab->dten_vstate; -+ -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ -+ for (i = 0; i < enab->dten_ndesc; i++) { -+ struct dtrace_actdesc *act, *next; -+ struct dtrace_predicate *pred; -+ -+ ep = enab->dten_desc[i]; -+ -+ pred = ep->dted_pred.dtpdd_predicate; -+ if (pred != NULL) -+ dtrace_predicate_release(pred, vstate); -+ -+ for (act = ep->dted_action; act != NULL; act = next) { -+ next = act->dtad_next; -+ dtrace_actdesc_release(act, vstate); -+ } -+ -+ kfree(ep); -+ } -+ -+ vfree(enab->dten_desc); -+ -+ /* -+ * If this was a retained enabling, decrement the dts_nretained count -+ * and remove it from the dtrace_retained list. -+ */ -+ if (enab->dten_prev != NULL || enab->dten_next != NULL || -+ dtrace_retained == enab) { -+ ASSERT(enab->dten_vstate->dtvs_state != NULL); -+ ASSERT(enab->dten_vstate->dtvs_state->dts_nretained > 0); -+ enab->dten_vstate->dtvs_state->dts_nretained--; -+ dtrace_retained_gen++; -+ } -+ -+ if (enab->dten_prev == NULL) { -+ if (dtrace_retained == enab) { -+ dtrace_retained = enab->dten_next; -+ -+ if (dtrace_retained != NULL) -+ dtrace_retained->dten_prev = NULL; -+ } -+ } else { -+ ASSERT(enab != dtrace_retained); -+ ASSERT(dtrace_retained != NULL); -+ enab->dten_prev->dten_next = enab->dten_next; -+ } -+ -+ if (enab->dten_next != NULL) { -+ ASSERT(dtrace_retained != NULL); -+ enab->dten_next->dten_prev = enab->dten_prev; -+ } -+ -+ kfree(enab); -+} -+ -+int dtrace_enabling_retain(struct dtrace_enabling *enab) -+{ -+ struct dtrace_state *state; -+ -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ ASSERT(enab->dten_next == NULL && enab->dten_prev == NULL); -+ ASSERT(enab->dten_vstate != NULL); -+ -+ state = enab->dten_vstate->dtvs_state; -+ ASSERT(state != NULL); -+ -+ /* -+ * We only allow each state to retain dtrace_retain_max enablings. -+ */ -+ if (state->dts_nretained >= dtrace_retain_max) -+ return -ENOSPC; -+ -+ state->dts_nretained++; -+ dtrace_retained_gen++; -+ -+ if (dtrace_retained == NULL) { -+ dtrace_retained = enab; -+ return 0; -+ } -+ -+ enab->dten_next = dtrace_retained; -+ dtrace_retained->dten_prev = enab; -+ dtrace_retained = enab; -+ -+ return 0; -+} -+ -+int dtrace_enabling_replicate(struct dtrace_state *state, -+ struct dtrace_probedesc *match, -+ struct dtrace_probedesc *create) -+{ -+ struct dtrace_enabling *new, *enab; -+ int found = 0, err = -ENOENT; -+ -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ ASSERT(strlen(match->dtpd_provider) < DTRACE_PROVNAMELEN); -+ ASSERT(strlen(match->dtpd_mod) < DTRACE_MODNAMELEN); -+ ASSERT(strlen(match->dtpd_func) < DTRACE_FUNCNAMELEN); -+ ASSERT(strlen(match->dtpd_name) < DTRACE_NAMELEN); -+ -+ new = dtrace_enabling_create(&state->dts_vstate); -+ if (new == NULL) -+ return -ENOMEM; -+ -+ /* -+ * Iterate over all retained enablings, looking for enablings that -+ * match the specified state. -+ */ -+ for (enab = dtrace_retained; enab != NULL; enab = enab->dten_next) { -+ int i; -+ -+ /* -+ * dtvs_state can only be NULL for helper enablings -- and -+ * helper enablings can't be retained. -+ */ -+ ASSERT(enab->dten_vstate->dtvs_state != NULL); -+ -+ if (enab->dten_vstate->dtvs_state != state) -+ continue; -+ -+ /* -+ * Now iterate over each probe description; we're looking for -+ * an exact match to the specified probe description. -+ */ -+ for (i = 0; i < enab->dten_ndesc; i++) { -+ struct dtrace_ecbdesc *ep = enab->dten_desc[i]; -+ struct dtrace_probedesc *pd = &ep->dted_probe; -+ -+ if (strcmp(pd->dtpd_provider, match->dtpd_provider)) -+ continue; -+ -+ if (strcmp(pd->dtpd_mod, match->dtpd_mod)) -+ continue; -+ -+ if (strcmp(pd->dtpd_func, match->dtpd_func)) -+ continue; -+ -+ if (strcmp(pd->dtpd_name, match->dtpd_name)) -+ continue; -+ -+ /* -+ * We have a winning probe! Add it to our growing -+ * enabling. -+ */ -+ found = 1; -+ dtrace_enabling_addlike(new, ep, create); -+ } -+ } -+ -+ if (!found || (err = dtrace_enabling_retain(new)) != 0) { -+ dtrace_enabling_destroy(new); -+ return err; -+ } -+ -+ return 0; -+} -+ -+void dtrace_enabling_retract(struct dtrace_state *state) -+{ -+ struct dtrace_enabling *enab, *next; -+ -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ -+ /* -+ * Iterate over all retained enablings, destroy the enablings retained -+ * for the specified state. -+ */ -+ for (enab = dtrace_retained; enab != NULL; enab = next) { -+ next = enab->dten_next; -+ -+ /* -+ * dtvs_state can only be NULL for helper enablings, and helper -+ * enablings can't be retained. -+ */ -+ ASSERT(enab->dten_vstate->dtvs_state != NULL); -+ -+ if (enab->dten_vstate->dtvs_state == state) { -+ ASSERT(state->dts_nretained > 0); -+ dtrace_enabling_destroy(enab); -+ } -+ } -+ -+ ASSERT(state->dts_nretained == 0); -+} -+ -+int dtrace_enabling_match(struct dtrace_enabling *enab, int *nmatched) -+{ -+ int i; -+ int total_matched = 0, matched = 0; -+ -+ for (i = 0; i < enab->dten_ndesc; i++) { -+ struct dtrace_ecbdesc *ep = enab->dten_desc[i]; -+ -+ enab->dten_current = ep; -+ enab->dten_error = 0; -+ -+ dt_dbg_enable(" Matching enabling %p[%d] for %s:%s:%s:%s\n", -+ enab, i, ep->dted_probe.dtpd_provider, -+ ep->dted_probe.dtpd_mod, -+ ep->dted_probe.dtpd_func, -+ ep->dted_probe.dtpd_name); -+ -+ matched = dtrace_probe_enable(&ep->dted_probe, enab); -+ if (matched < 0) { -+ dt_dbg_enable(" Matching enabling %p[%d] failed: " -+ "busy\n", enab, i); -+ return -EBUSY; -+ } -+ -+ dt_dbg_enable(" Matching enabling %p[%d] found %d matches.\n", -+ enab, i, matched); -+ -+ total_matched += matched; -+ -+ if (enab->dten_error != 0) { -+ if (nmatched == NULL) -+ pr_warn("%s error on %p: %d\n", __func__, -+ (void *)ep, enab->dten_error); -+ -+ return enab->dten_error; -+ } -+ } -+ -+ enab->dten_probegen = dtrace_probegen; -+ if (nmatched != NULL) -+ *nmatched = total_matched; -+ -+ return 0; -+} -+ -+void dtrace_enabling_matchall(void) -+{ -+ struct dtrace_enabling *enab; -+ -+ mutex_lock(&cpu_lock); -+ mutex_lock(&dtrace_lock); -+ -+ for (enab = dtrace_retained; enab != NULL; enab = enab->dten_next) -+ (void) dtrace_enabling_match(enab, NULL); -+ -+ mutex_unlock(&dtrace_lock); -+ mutex_unlock(&cpu_lock); -+} -+ -+/* -+ * If an enabling is to be enabled without having matched probes (that is, if -+ * dtrace_state_go() is to be called on the underlying dtrace_state_t), the -+ * enabling must be _primed_ by creating an ECB for every ECB description. -+ * This must be done to assure that we know the number of speculations, the -+ * number of aggregations, the minimum buffer size needed, etc. before we -+ * transition out of DTRACE_ACTIVITY_INACTIVE. To do this without actually -+ * enabling any probes, we create ECBs for every ECB description, but with a -+ * NULL probe -- which is exactly what this function does. -+ */ -+void dtrace_enabling_prime(struct dtrace_state *state) -+{ -+ struct dtrace_enabling *enab; -+ int i; -+ -+ for (enab = dtrace_retained; enab != NULL; enab = enab->dten_next) { -+ ASSERT(enab->dten_vstate->dtvs_state != NULL); -+ -+ if (enab->dten_vstate->dtvs_state != state) -+ continue; -+ -+ /* -+ * We don't want to prime an enabling more than once, lest -+ * we allow a malicious user to induce resource exhaustion. -+ * (The ECBs that result from priming an enabling aren't -+ * leaked -- but they also aren't deallocated until the -+ * consumer state is destroyed.) -+ */ -+ if (enab->dten_primed) -+ continue; -+ -+ for (i = 0; i < enab->dten_ndesc; i++) { -+ enab->dten_current = enab->dten_desc[i]; -+ dtrace_probe_enable(NULL, enab); -+ } -+ -+ enab->dten_primed = 1; -+ } -+} -+ -+void dtrace_enabling_provide(struct dtrace_provider *prv) -+{ -+ int all = 0; -+ dtrace_genid_t gen; -+ -+ if (prv == NULL) { -+ all = 1; -+ prv = dtrace_provider; -+ } -+ -+ do { -+ struct dtrace_enabling *enab; -+ void *parg = prv->dtpv_arg; -+ -+retry: -+ gen = dtrace_retained_gen; -+ for (enab = dtrace_retained; enab != NULL; -+ enab = enab->dten_next) { -+ int i; -+ -+ for (i = 0; i < enab->dten_ndesc; i++) { -+ struct dtrace_probedesc desc; -+ -+ desc = enab->dten_desc[i]->dted_probe; -+ mutex_unlock(&dtrace_lock); -+ prv->dtpv_pops.dtps_provide(parg, &desc); -+ mutex_lock(&dtrace_lock); -+ -+ if (gen != dtrace_retained_gen) -+ goto retry; -+ } -+ } -+ } while (all && (prv = prv->dtpv_next) != NULL); -+ -+ mutex_unlock(&dtrace_lock); -+ dtrace_probe_provide(NULL, all ? NULL : prv); -+ mutex_lock(&dtrace_lock); -+} -diff --git a/dtrace/dtrace_fmt.c b/dtrace/dtrace_fmt.c -new file mode 100644 -index 0000000000000000000000000000000000000000..78fcc8e6efb88cc156945e5d66182b1c455152e4 ---- /dev/null -+++ b/dtrace/dtrace_fmt.c -@@ -0,0 +1,104 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_fmt.c -+ * DESCRIPTION: DTrace - format string implementation -+ * -+ * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/slab.h> -+#include <linux/vmalloc.h> -+ -+#include "dtrace.h" -+ -+uint16_t dtrace_format_add(struct dtrace_state *state, char *str) -+{ -+ char *fmt, **new; -+ uint16_t ndx; -+ -+ fmt = dtrace_strdup(str); -+ if (fmt == NULL) -+ return 0; -+ -+ for (ndx = 0; ndx < state->dts_nformats; ndx++) { -+ if (state->dts_formats[ndx] == NULL) { -+ state->dts_formats[ndx] = fmt; -+ -+ return ndx + 1; -+ } -+ } -+ -+ if (state->dts_nformats == UINT16_MAX) { -+ kfree(fmt); -+ -+ return 0; -+ } -+ -+ ndx = state->dts_nformats; -+ new = vmalloc((ndx + 1) * sizeof(char *)); -+ if (new == NULL) { -+ kfree(fmt); -+ return 0; -+ } -+ -+ state->dts_nformats++; -+ -+ if (state->dts_formats != NULL) { -+ ASSERT(ndx != 0); -+ memcpy(new, state->dts_formats, ndx * sizeof(char *)); -+ vfree(state->dts_formats); -+ } -+ -+ state->dts_formats = new; -+ state->dts_formats[ndx] = fmt; -+ -+ return ndx + 1; -+} -+ -+void dtrace_format_remove(struct dtrace_state *state, uint16_t format) -+{ -+ char *fmt; -+ -+ ASSERT(state->dts_formats != NULL); -+ ASSERT(format <= state->dts_nformats); -+ ASSERT(state->dts_formats[format - 1] != NULL); -+ -+ fmt = state->dts_formats[format - 1]; -+ kfree(fmt); -+ state->dts_formats[format - 1] = NULL; -+} -+ -+void dtrace_format_destroy(struct dtrace_state *state) -+{ -+ int i; -+ -+ if (state->dts_nformats == 0) { -+ ASSERT(state->dts_formats == NULL); -+ return; -+ } -+ -+ ASSERT(state->dts_formats != NULL); -+ -+ for (i = 0; i < state->dts_nformats; i++) { -+ char *fmt = state->dts_formats[i]; -+ -+ if (fmt == NULL) -+ continue; -+ -+ kfree(fmt); -+ } -+ -+ vfree(state->dts_formats); -+ state->dts_nformats = 0; -+ state->dts_formats = NULL; -+} -diff --git a/dtrace/dtrace_hash.c b/dtrace/dtrace_hash.c -new file mode 100644 -index 0000000000000000000000000000000000000000..0773c60e7897ce9cbc8efaa25f54f7181d86be02 ---- /dev/null -+++ b/dtrace/dtrace_hash.c -@@ -0,0 +1,266 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_hash.c -+ * DESCRIPTION: DTrace - hash table implementation -+ * -+ * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/slab.h> -+#include <linux/vmalloc.h> -+ -+#include "dtrace.h" -+ -+#define DTRACE_HASHSTR(hash, probe) \ -+ dtrace_hash_str(*((char **)((uintptr_t)(probe) + (hash)->dth_stroffs))) -+#define DTRACE_HASHEQ(hash, lhs, rhs) \ -+ (strcmp(*((char **)((uintptr_t)(lhs) + (hash)->dth_stroffs)), \ -+ *((char **)((uintptr_t)(rhs) + (hash)->dth_stroffs))) == 0) -+ -+static uint_t dtrace_hash_str(char *p) -+{ -+ uint_t g; -+ uint_t hval = 0; -+ -+ while (*p) { -+ hval = (hval << 4) + *p++; -+ g = hval & 0xf0000000; -+ if (g != 0) -+ hval ^= g >> 24; -+ -+ hval &= ~g; -+ } -+ -+ return hval; -+} -+ -+struct dtrace_hash *dtrace_hash_create(uintptr_t stroffs, uintptr_t nextoffs, -+ uintptr_t prevoffs) -+{ -+ struct dtrace_hash *hash; -+ -+ hash = kzalloc(sizeof(struct dtrace_hash), GFP_KERNEL); -+ if (hash == NULL) -+ return NULL; -+ -+ hash->dth_stroffs = stroffs; -+ hash->dth_nextoffs = nextoffs; -+ hash->dth_prevoffs = prevoffs; -+ -+ hash->dth_size = 1; -+ hash->dth_mask = hash->dth_size - 1; -+ -+ hash->dth_tab = vzalloc(hash->dth_size * -+ sizeof(struct dtrace_hashbucket *)); -+ -+ if (hash->dth_tab == NULL) { -+ kfree(hash); -+ return NULL; -+ } -+ -+ return hash; -+} -+ -+void dtrace_hash_destroy(struct dtrace_hash *hash) -+{ -+#ifdef DEBUG -+ int i; -+ -+ for (i = 0; i < hash->dth_size; i++) -+ ASSERT(hash->dth_tab[i] == NULL); -+#endif -+ -+ if (hash == NULL) -+ return; -+ -+ vfree(hash->dth_tab); -+ kfree(hash); -+} -+ -+static int dtrace_hash_resize(struct dtrace_hash *hash) -+{ -+ int size = hash->dth_size, i, ndx; -+ int new_size = hash->dth_size << 1; -+ int new_mask = new_size - 1; -+ struct dtrace_hashbucket **new_tab, *bucket, *next; -+ -+ ASSERT((new_size & new_mask) == 0); -+ -+ new_tab = vzalloc(new_size * sizeof(void *)); -+ if (new_tab == NULL) -+ return -ENOMEM; -+ -+ for (i = 0; i < size; i++) { -+ for (bucket = hash->dth_tab[i]; bucket != NULL; -+ bucket = next) { -+ struct dtrace_probe *probe = bucket->dthb_chain; -+ -+ ASSERT(probe != NULL); -+ ndx = DTRACE_HASHSTR(hash, probe) & new_mask; -+ -+ next = bucket->dthb_next; -+ bucket->dthb_next = new_tab[ndx]; -+ new_tab[ndx] = bucket; -+ } -+ } -+ -+ vfree(hash->dth_tab); -+ hash->dth_tab = new_tab; -+ hash->dth_size = new_size; -+ hash->dth_mask = new_mask; -+ -+ return 0; -+} -+ -+int dtrace_hash_add(struct dtrace_hash *hash, struct dtrace_probe *new) -+{ -+ int hashval = DTRACE_HASHSTR(hash, new); -+ int ndx = hashval & hash->dth_mask; -+ struct dtrace_hashbucket *bucket = hash->dth_tab[ndx]; -+ struct dtrace_probe **nextp, **prevp; -+ -+ for (; bucket != NULL; bucket = bucket->dthb_next) { -+ if (DTRACE_HASHEQ(hash, bucket->dthb_chain, new)) -+ goto add; -+ } -+ -+ if ((hash->dth_nbuckets >> 1) > hash->dth_size) { -+ int err = 0; -+ -+ err = dtrace_hash_resize(hash); -+ if (err != 0) -+ return err; -+ -+ dtrace_hash_add(hash, new); -+ return 0; -+ } -+ -+ bucket = kzalloc(sizeof(struct dtrace_hashbucket), GFP_KERNEL); -+ if (bucket == NULL) -+ return -ENOMEM; -+ -+ bucket->dthb_next = hash->dth_tab[ndx]; -+ hash->dth_tab[ndx] = bucket; -+ hash->dth_nbuckets++; -+ -+add: -+ nextp = DTRACE_HASHNEXT(hash, new); -+ -+ ASSERT(*nextp == NULL && *(DTRACE_HASHPREV(hash, new)) == NULL); -+ -+ *nextp = bucket->dthb_chain; -+ -+ if (bucket->dthb_chain != NULL) { -+ prevp = DTRACE_HASHPREV(hash, bucket->dthb_chain); -+ -+ ASSERT(*prevp == NULL); -+ -+ *prevp = new; -+ } -+ -+ bucket->dthb_chain = new; -+ bucket->dthb_len++; -+ -+ return 0; -+} -+ -+struct dtrace_probe *dtrace_hash_lookup(struct dtrace_hash *hash, -+ struct dtrace_probe *template) -+{ -+ int hashval = DTRACE_HASHSTR(hash, template); -+ int ndx = hashval & hash->dth_mask; -+ -+ struct dtrace_hashbucket *bucket = hash->dth_tab[ndx]; -+ -+ for (; bucket != NULL; bucket = bucket->dthb_next) { -+ if (DTRACE_HASHEQ(hash, bucket->dthb_chain, template)) -+ return bucket->dthb_chain; -+ } -+ -+ return NULL; -+} -+ -+/* -+ * FIXME: -+ * It would be more accurate to calculate a lookup cost based on the number -+ * of buckets in the hash table slot, the length of the chain, and the length -+ * of the string being looked up. -+ * The hash tables can also be optimized by storing the hashval in each element -+ * rather than always performing string comparisons. -+ */ -+int dtrace_hash_collisions(struct dtrace_hash *hash, -+ struct dtrace_probe *template) -+{ -+ int hashval = DTRACE_HASHSTR(hash, template); -+ int ndx = hashval & hash->dth_mask; -+ -+ struct dtrace_hashbucket *bucket = hash->dth_tab[ndx]; -+ -+ for (; bucket != NULL; bucket = bucket->dthb_next) { -+ if (DTRACE_HASHEQ(hash, bucket->dthb_chain, template)) -+ return bucket->dthb_len; -+ } -+ -+ return 0; -+} -+ -+void dtrace_hash_remove(struct dtrace_hash *hash, struct dtrace_probe *probe) -+{ -+ int ndx = DTRACE_HASHSTR(hash, probe) & hash->dth_mask; -+ -+ struct dtrace_hashbucket *bucket = hash->dth_tab[ndx]; -+ struct dtrace_probe **prevp = DTRACE_HASHPREV(hash, probe); -+ struct dtrace_probe **nextp = DTRACE_HASHNEXT(hash, probe); -+ -+ for (; bucket != NULL; bucket = bucket->dthb_next) { -+ if (DTRACE_HASHEQ(hash, bucket->dthb_chain, probe)) -+ break; -+ } -+ -+ ASSERT(bucket != NULL); -+ -+ if (*prevp == NULL) { -+ if (*nextp == NULL) { -+ /* -+ * This is the last probe in the bucket; we can remove -+ * the bucket. -+ */ -+ struct dtrace_hashbucket *b = hash->dth_tab[ndx]; -+ -+ ASSERT(bucket->dthb_chain == probe); -+ ASSERT(b != NULL); -+ -+ if (b == bucket) -+ hash->dth_tab[ndx] = bucket->dthb_next; -+ else { -+ while (b->dthb_next != bucket) -+ b = b->dthb_next; -+ -+ b->dthb_next = bucket->dthb_next; -+ } -+ -+ ASSERT(hash->dth_nbuckets > 0); -+ -+ hash->dth_nbuckets--; -+ kfree(bucket); -+ -+ return; -+ } -+ -+ bucket->dthb_chain = *nextp; -+ } else -+ *(DTRACE_HASHNEXT(hash, *prevp)) = *nextp; -+ -+ if (*nextp != NULL) -+ *(DTRACE_HASHPREV(hash, *nextp)) = *prevp; -+} -diff --git a/dtrace/dtrace_isa.c b/dtrace/dtrace_isa.c -new file mode 100644 -index 0000000000000000000000000000000000000000..f84ce1cd52cc82e6af9e6048c870865c7ec312ff ---- /dev/null -+++ b/dtrace/dtrace_isa.c -@@ -0,0 +1,361 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_isa.c -+ * DESCRIPTION: DTrace - architecture specific code -+ * -+ * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/dtrace_cpu.h> -+#include <linux/dtrace_task_impl.h> -+#include <linux/hardirq.h> -+#include <linux/mm.h> -+#include <linux/smp.h> -+#include <linux/uaccess.h> -+#include <linux/cpumask.h> -+#include <asm/cacheflush.h> -+#include <asm/ptrace.h> -+#include <asm/stacktrace.h> -+ -+#include "dtrace.h" -+ -+DEFINE_MUTEX(cpu_lock); -+EXPORT_SYMBOL(cpu_lock); -+ -+int dtrace_getipl(void) -+{ -+ return in_interrupt(); -+} -+ -+void dtrace_xcall(processorid_t cpu, dtrace_xcall_t func, void *arg) -+{ -+ if (cpu == DTRACE_CPUALL) -+ smp_call_function(func, arg, 1); -+ else -+ smp_call_function_single(cpu, func, arg, 1); -+} -+ -+void dtrace_toxic_ranges(void (*func)(uintptr_t, uintptr_t)) -+{ -+ /* FIXME */ -+} -+ -+/* -+ * Note: not called from probe context. This function is called -+ * asynchronously (and at a regular interval) from outside of probe context -+ * by the DTrace framework to sync shared data which DTrace probe context -+ * may access without locks. -+ * -+ * Whenever the framework updates data which can be accessed from probe context, -+ * the framework then calls dtrace_sync(). dtrace_sync() guarantees all probes -+ * are using the new data before returning. -+ * -+ * See the comment in dtrace_impl.h which describes this algorithm. -+ * The cpuc_in_probe_ctxt flag is an increasing 16-bit count. It is odd when -+ * in DTrace probe context and even when not in DTrace probe context. -+ * The upper 15 bits are a counter which are incremented when exiting DTrace -+ * probe context. These upper 15 bits are used to detect "sample aliasing": -+ * i.e. the target CPU is not in DTrace probe context between samples but -+ * continually enters probe context just before being sampled. -+ * -+ * dtrace_sync() loops over NCPUs. CPUs which are not in DTrace probe context -+ * (cpuc_in_probe_ctxt is even) are removed from the list. This is repeated -+ * until there are no CPUs left in the sync list. -+ * -+ * In the rare cases where dtrace_sync() loops over all NCPUs more than -+ * dtrace_sync_sample_count times, dtrace_sync() then spins on one CPU's -+ * cpuc_in_probe_ctxt count until the count increments. This is intended to -+ * avoid sample aliasing. -+ */ -+void dtrace_sync(void) -+{ -+ /* -+ * sync_cpus is a bitmap of CPUs that need to be synced with. -+ */ -+ cpumask_t sync_cpus; -+ uint64_t sample_count = 0; -+ int cpuid, sample_cpuid = 0; -+ int outstanding; -+ -+ /* -+ * Create bitmap of CPUs that need to be synced with. -+ */ -+ cpumask_copy(&sync_cpus, cpu_online_mask); -+ outstanding = 0; -+ for_each_cpu(cpuid, &sync_cpus) { -+ ++outstanding; -+ -+ /* -+ * Set a flag to let the CPU know we are syncing with it. -+ */ -+ DTRACE_SYNC_START(cpuid); -+ } -+ -+ /* -+ * The preceding stores by DTRACE_SYNC_START() must complete before -+ * subsequent loads or stores. No membar is needed because the -+ * atomic-add operation in DTRACE_SYNC_START is a memory barrier on -+ * SPARC and X86. -+ */ -+ -+ while (outstanding > 0) { -+ /* -+ * Loop over the map of CPUs that need to be synced with. -+ */ -+ for_each_cpu(cpuid, &sync_cpus) { -+ if (!DTRACE_SYNC_IN_CRITICAL(cpuid)) { -+ -+ /* Clear the CPU's sync request flag */ -+ DTRACE_SYNC_END(cpuid); -+ -+ /* -+ * remove cpuid from list of CPUs that -+ * still need to be synced with. -+ */ -+ DTRACE_SYNC_DONE(cpuid, &sync_cpus); -+ --outstanding; -+ } else { -+ /* -+ * Remember one of the outstanding CPUs to spin -+ * on once we reach the sampling limit. -+ */ -+ sample_cpuid = cpuid; -+ } -+ } -+ -+ /* -+ * dtrace_probe may be running in sibling threads in this core. -+ */ -+ if (outstanding > 0) { -+ dtrace_safe_smt_pause(); -+ -+ /* -+ * After sample_count loops, spin on one CPU's count -+ * instead of just checking for odd/even. -+ */ -+ if (++sample_count > dtrace_sync_sample_count) { -+ uint64_t count = -+ DTRACE_SYNC_CRITICAL_COUNT(sample_cpuid); -+ -+ /* -+ * Spin until critical section count increments. -+ */ -+ if (DTRACE_SYNC_IN_CRITICAL(sample_cpuid)) { -+ while (count == -+ DTRACE_SYNC_CRITICAL_COUNT( -+ sample_cpuid)) { -+ -+ dtrace_safe_smt_pause(); -+ } -+ } -+ -+ DTRACE_SYNC_END(sample_cpuid); -+ DTRACE_SYNC_DONE(sample_cpuid, &sync_cpus); -+ --outstanding; -+ } -+ } -+ } -+ -+/* -+ * All preceding loads by DTRACE_SYNC_IN_CRITICAL() and -+ * DTRACE_SYNC_CRITICAL_COUNT() must complete before subsequent loads -+ * or stores. No membar is needed because the atomic-add operation in -+ * DTRACE_SYNC_END() is a memory barrier on SPARC and X86. -+ */ -+} -+ -+/* -+ * Handle a few special cases where we store information in kernel memory that -+ * in other systems is typically found in userspace. -+ */ -+static int dtrace_fake_copyin(intptr_t addr, size_t size) -+{ -+ struct dtrace_psinfo *psinfo; -+ uintptr_t argv; -+ unsigned long argc; -+ uintptr_t envp; -+ unsigned long envc; -+ -+ if (current->dt_task == NULL) -+ return 0; -+ -+ psinfo = current->dt_task->dt_psinfo; -+ if (psinfo == NULL) -+ return 0; -+ -+ argv = (uintptr_t)psinfo->dtps_argv; -+ argc = psinfo->dtps_argc; -+ envp = (uintptr_t)psinfo->dtps_envp; -+ envc = psinfo->dtps_envc; -+ -+ /* -+ * Ensure addr is within the argv array (or the envp array): -+ * addr in [argv..argv + argc * sizeof(psinfo->argv[0])[ -+ * Ensure that addr + size is within the same array -+ * addr + size in [argv..argv * sizeof(psinfo->argv[0])] -+ * -+ * To guard against overflows on (addr + size) we rewrite this basic -+ * equation: -+ * addr + size <= argv + argc * sizeof(psinfo->argv[0]) -+ * into: -+ * addr - argv <= argc * sizeof(psinfo->argv[0]) - size -+ */ -+ return (addr >= argv && -+ addr - argv < argc * sizeof(psinfo->dtps_argv[0]) && -+ addr - argv <= argc * sizeof(psinfo->dtps_argv[0]) - size) || -+ (addr >= envp && -+ addr - envp < envc * sizeof(psinfo->dtps_envp[0]) && -+ addr - envp <= envc * sizeof(psinfo->dtps_envp[0]) - size); -+} -+ -+void dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size, -+ volatile uint16_t *flags) -+{ -+ if (dtrace_fake_copyin(uaddr, size)) { -+ memcpy((char *)kaddr, (char *)uaddr, size); -+ return; -+ } -+ -+ dtrace_copyin_arch(uaddr, kaddr, size, flags); -+} -+ -+void dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size, -+ volatile uint16_t *flags) -+{ -+ if (dtrace_fake_copyin(uaddr, size)) { -+ strncpy((char *)kaddr, (char *)uaddr, -+ min(size, (size_t)PR_PSARGS_SZ)); -+ return; -+ } -+ -+ dtrace_copyinstr_arch(uaddr, kaddr, size, flags); -+} -+ -+/* -+ * FIXME: aframes + 3 should really be aframes + 1, dtrace_stacktrace() in the -+ * kernel should do its own aframes + 2 -+ */ -+void dtrace_getpcstack(uint64_t *pcstack, int pcstack_limit, int aframes, -+ uint32_t *intrpc) -+{ -+ struct stacktrace_state st = { -+ pcstack, -+ NULL, -+ pcstack_limit, -+ aframes + 3, -+ STACKTRACE_KERNEL -+ }; -+ -+ dtrace_stacktrace(&st); -+ -+ while (st.depth < st.limit) -+ pcstack[st.depth++] = 0; -+} -+EXPORT_SYMBOL(dtrace_getpcstack); -+ -+/* -+ * Get user stack entries up to the pcstack_limit; return the number of entries -+ * acquired. If pcstack is NULL, return the number of entries potentially -+ * acquirable. -+ */ -+unsigned long dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, -+ int pcstack_limit) -+{ -+ struct task_struct *p = current; -+ struct stacktrace_state st; -+ unsigned long depth; -+ -+ if (pcstack) { -+ if (unlikely(pcstack_limit < 2)) { -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); -+ return 0; -+ } -+ *pcstack++ = (uint64_t)p->pid; -+ *pcstack++ = (uint64_t)p->tgid; -+ pcstack_limit -= 2; -+ } -+ -+ st.pcs = pcstack; -+ st.fps = fpstack; -+ st.limit = pcstack_limit; -+ st.depth = 0; -+ st.flags = STACKTRACE_USER; -+ -+ dtrace_stacktrace(&st); -+ -+ depth = st.depth; -+ if (pcstack) { -+ while (st.depth < st.limit) { -+ pcstack[st.depth++] = 0; -+ if (fpstack) -+ fpstack[st.depth++] = 0; -+ } -+ } -+ -+ return depth; -+} -+ -+void dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit) -+{ -+ dtrace_getufpstack(pcstack, NULL, pcstack_limit); -+} -+ -+/* -+ * FIXME: aframes + 3 should really be aframes + 1, dtrace_stacktrace() in the -+ * kernel should do its own aframes + 2 -+ */ -+int dtrace_getstackdepth(struct dtrace_mstate *mstate, int aframes) -+{ -+ uintptr_t old = mstate->dtms_scratch_ptr; -+ struct stacktrace_state st = { -+ NULL, -+ NULL, -+ 0, -+ aframes + 3, -+ STACKTRACE_KERNEL -+ }; -+ -+ st.pcs = (uint64_t *)ALIGN(old, 8); -+ if ((uintptr_t)st.pcs > -+ mstate->dtms_scratch_base + mstate->dtms_scratch_size) { -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); -+ return 0; -+ } -+ -+ /* -+ * Calculate how many (64-bit) PCs we can fit in the remaining scratch -+ * memory. -+ */ -+ st.limit = (mstate->dtms_scratch_base + mstate->dtms_scratch_size - -+ (uintptr_t)st.pcs) >> 3; -+ -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); -+ dtrace_stacktrace(&st); -+ DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); -+ -+ mstate->dtms_scratch_ptr = old; -+ -+ return st.depth; -+} -+ -+int dtrace_getustackdepth(void) -+{ -+ return dtrace_getufpstack(NULL, NULL, INT_MAX); -+} -+ -+void dtrace_probe_error(struct dtrace_state *state, dtrace_epid_t epid, -+ int act, int fltoffs, int flags, uintptr_t addr) -+{ -+ dtrace_probe(dtrace_probeid_error, (uintptr_t)state, epid, act, -+ fltoffs, flags, addr, 0); -+} -diff --git a/dtrace/dtrace_match.c b/dtrace/dtrace_match.c -new file mode 100644 -index 0000000000000000000000000000000000000000..a63e3f8be1cde0114bfc7f78e6df6f278ed81a40 ---- /dev/null -+++ b/dtrace/dtrace_match.c -@@ -0,0 +1,364 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_match.c -+ * DESCRIPTION: DTrace - probe match implementation -+ * -+ * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include "dtrace.h" -+ -+struct dtrace_hash *dtrace_bymod; -+struct dtrace_hash *dtrace_byfunc; -+struct dtrace_hash *dtrace_byname; -+ -+int dtrace_match_priv(const struct dtrace_probe *prp, uint32_t priv, -+ kuid_t uid) -+{ -+ if (priv != DTRACE_PRIV_ALL) { -+ uint32_t ppriv = -+ prp->dtpr_provider->dtpv_priv.dtpp_flags; -+ uint32_t match = priv & ppriv; -+ -+ if ((priv & (DTRACE_PRIV_PROC | DTRACE_PRIV_USER | -+ DTRACE_PRIV_KERNEL)) == 0) -+ return 0; -+ -+ if (match == 0 && ppriv != 0) -+ return 0; -+ -+ if (((ppriv & ~match) & DTRACE_PRIV_OWNER) != 0 && -+ !uid_eq(uid, make_kuid(init_user_namespace, -+ prp->dtpr_provider->dtpv_priv.dtpp_uid))) -+ return 0; -+ } -+ -+ return 1; -+} -+ -+int dtrace_match_probe(const struct dtrace_probe *prp, -+ const struct dtrace_probekey *pkp, -+ uint32_t priv, kuid_t uid) -+{ -+ struct dtrace_provider *pvp = prp->dtpr_provider; -+ int rv; -+ -+ if (pvp->dtpv_defunct) -+ return 0; -+ -+ rv = pkp->dtpk_pmatch(pvp->dtpv_name, pkp->dtpk_prov, 0); -+ if (rv <= 0) -+ return rv; -+ -+ rv = pkp->dtpk_mmatch(prp->dtpr_mod, pkp->dtpk_mod, 0); -+ if (rv <= 0) -+ return rv; -+ -+ rv = pkp->dtpk_fmatch(prp->dtpr_func, pkp->dtpk_func, 0); -+ if (rv <= 0) -+ return rv; -+ -+ rv = pkp->dtpk_nmatch(prp->dtpr_name, pkp->dtpk_name, 0); -+ if (rv <= 0) -+ return rv; -+ -+ if (dtrace_match_priv(prp, priv, uid) == 0) -+ return 0; -+ -+ return rv; -+} -+ -+int dtrace_match_glob(const char *s, const char *p, int depth) -+{ -+ const char *olds; -+ char s1, c; -+ int gs; -+ -+ if (depth > DTRACE_PROBEKEY_MAXDEPTH) -+ return -1; -+ -+ if (s == NULL) -+ s = ""; -+ -+top: -+ olds = s; -+ s1 = *s++; -+ -+ if (p == NULL) -+ return 0; -+ -+ c = *p++; -+ if (c == '\0') -+ return s1 == '\0'; -+ -+ switch (c) { -+ case '[': -+ { -+ int ok = 0, notflag = 0; -+ char lc = '\0'; -+ -+ if (s1 == '\0') -+ return 0; -+ -+ if (*p == '!') { -+ notflag = 1; -+ p++; -+ } -+ -+ c = *p++; -+ if (c == '\0') -+ return 0; -+ -+ do { -+ if (c == '-' && lc != '\0' && *p != ']') { -+ c = *p++; -+ if (c == '\0') -+ return 0; -+ if (c == '\\') { -+ c = *p++; -+ if (c == '\0') -+ return 0; -+ } -+ if (notflag) { -+ if (s1 < lc || s1 > c) -+ ok++; -+ else -+ return 0; -+ } else if (lc <= s1 && s1 <= c) -+ ok++; -+ } else if (c == '\\') { -+ c = *p++; -+ if (c == '\0') -+ return 0; -+ } -+ lc = c; -+ -+ if (notflag) { -+ if (s1 != c) -+ ok++; -+ else -+ return 0; -+ } else if (s1 == c) -+ ok++; -+ -+ c = *p++; -+ if (c == '\0') -+ return 0; -+ } while (c != ']'); -+ -+ if (ok) -+ goto top; -+ -+ return 0; -+ } -+ -+ case '\\': -+ c = *p++; -+ if (c == '\0') -+ return 0; -+ /* fallthru */ -+ default: -+ if (c != s1) -+ return 0; -+ /* fallthru */ -+ -+ case '?': -+ if (s1 != '\0') -+ goto top; -+ -+ return 0; -+ -+ case '*': -+ while (*p == '*') -+ p++; -+ -+ if (*p == '\0') -+ return 1; -+ -+ for (s = olds; *s != '\0'; s++) { -+ gs = dtrace_match_glob(s, p, depth + 1); -+ if (gs != 0) -+ return gs; -+ } -+ -+ return 0; -+ } -+} -+ -+int dtrace_match_string(const char *s, const char *p, int depth) -+{ -+ return s != NULL && strcmp(s, p) == 0; -+} -+ -+int dtrace_match_nul(const char *s, const char *p, int depth) -+{ -+ return 1; -+} -+ -+int dtrace_match_nonzero(const char *s, const char *p, int depth) -+{ -+ return s != NULL && s[0] != '\0'; -+} -+ -+struct probe_match { -+ const struct dtrace_probekey *pkp; -+ uint32_t priv; -+ kuid_t uid; -+ int (*matched)(struct dtrace_probe *, void *); -+ void *arg; -+ int nmatched; -+}; -+ -+static int dtrace_match_one(int id, void *p, void *data) -+{ -+ struct probe_match *pbm = (struct probe_match *)data; -+ struct dtrace_probe *probe = (struct dtrace_probe *)p; -+ int rc; -+ -+ if (dtrace_match_probe(probe, pbm->pkp, pbm->priv, pbm->uid) <= 0) -+ return 0; -+ -+ pbm->nmatched++; -+ -+ rc = (pbm->matched)(probe, pbm->arg); -+ if (rc != DTRACE_MATCH_NEXT) { -+ if (rc == DTRACE_MATCH_FAIL) -+ return DTRACE_MATCH_FAIL; -+ } -+ -+ return 0; -+} -+ -+int dtrace_match(const struct dtrace_probekey *pkp, uint32_t priv, kuid_t uid, -+ int (*matched)(struct dtrace_probe *, void *), void *arg) -+{ -+ struct dtrace_probe template, *probe; -+ struct dtrace_hash *hash = NULL; -+ int len, rc, best = INT_MAX, nmatched = 0; -+ -+ if (pkp->dtpk_id != DTRACE_IDNONE) { -+ probe = dtrace_probe_lookup_id(pkp->dtpk_id); -+ if (probe != NULL && -+ dtrace_match_probe(probe, pkp, priv, uid) > 0) { -+ if ((*matched)(probe, arg) == DTRACE_MATCH_FAIL) -+ return DTRACE_MATCH_FAIL; -+ -+ nmatched++; -+ } -+ -+ return nmatched; -+ } -+ -+ template.dtpr_mod = (char *)pkp->dtpk_mod; -+ template.dtpr_func = (char *)pkp->dtpk_func; -+ template.dtpr_name = (char *)pkp->dtpk_name; -+ -+ if (pkp->dtpk_mmatch == &dtrace_match_string) { -+ len = dtrace_hash_collisions(dtrace_bymod, &template); -+ if (len < best) { -+ best = len; -+ hash = dtrace_bymod; -+ } -+ } -+ -+ if (pkp->dtpk_fmatch == &dtrace_match_string) { -+ len = dtrace_hash_collisions(dtrace_byfunc, &template); -+ if (len < best) { -+ best = len; -+ hash = dtrace_byfunc; -+ } -+ } -+ -+ if (pkp->dtpk_nmatch == &dtrace_match_string) { -+ len = dtrace_hash_collisions(dtrace_byname, &template); -+ if (len < best) { -+ best = len; -+ hash = dtrace_byname; -+ } -+ } -+ -+ if (hash == NULL) { -+ struct probe_match pbm; -+ -+ pbm.pkp = pkp; -+ pbm.priv = priv; -+ pbm.uid = uid; -+ pbm.matched = matched; -+ pbm.arg = arg; -+ pbm.nmatched = 0; -+ -+ rc = dtrace_probe_for_each(dtrace_match_one, &pbm); -+ if (rc == DTRACE_MATCH_FAIL) -+ return DTRACE_MATCH_FAIL; -+ -+ return pbm.nmatched; -+ } -+ -+ for (probe = dtrace_hash_lookup(hash, &template); probe != NULL; -+ probe = *(DTRACE_HASHNEXT(hash, probe))) { -+ if (dtrace_match_probe(probe, pkp, priv, uid) <= 0) -+ continue; -+ -+ nmatched++; -+ -+ rc = (*matched)(probe, arg); -+ if (rc != DTRACE_MATCH_NEXT) { -+ if (rc == DTRACE_MATCH_FAIL) -+ return DTRACE_MATCH_FAIL; -+ -+ break; -+ } -+ } -+ -+ return nmatched; -+} -+ -+static dtrace_probekey_f *dtrace_probekey_func(const char *p) -+{ -+ char c; -+ -+ if (p == NULL || *p == '\0') -+ return &dtrace_match_nul; -+ -+ while ((c = *p++) != '\0') { -+ if (c == '[' || c == '?' || c == '*' || c == '\\') -+ return &dtrace_match_glob; -+ } -+ -+ return &dtrace_match_string; -+} -+ -+void dtrace_probekey(const struct dtrace_probedesc *pdp, -+ struct dtrace_probekey *pkp) -+{ -+ pkp->dtpk_prov = pdp->dtpd_provider; -+ pkp->dtpk_pmatch = dtrace_probekey_func(pdp->dtpd_provider); -+ -+ pkp->dtpk_mod = pdp->dtpd_mod; -+ pkp->dtpk_mmatch = dtrace_probekey_func(pdp->dtpd_mod); -+ -+ pkp->dtpk_func = pdp->dtpd_func; -+ pkp->dtpk_fmatch = dtrace_probekey_func(pdp->dtpd_func); -+ -+ pkp->dtpk_name = pdp->dtpd_name; -+ pkp->dtpk_nmatch = dtrace_probekey_func(pdp->dtpd_name); -+ -+ pkp->dtpk_id = pdp->dtpd_id; -+ -+ if (pkp->dtpk_id == DTRACE_IDNONE && -+ pkp->dtpk_pmatch == &dtrace_match_nul && -+ pkp->dtpk_mmatch == &dtrace_match_nul && -+ pkp->dtpk_fmatch == &dtrace_match_nul && -+ pkp->dtpk_nmatch == &dtrace_match_nul) -+ pkp->dtpk_fmatch = &dtrace_match_nonzero; -+} -diff --git a/dtrace/dtrace_mod.c b/dtrace/dtrace_mod.c -new file mode 100644 -index 0000000000000000000000000000000000000000..4da08c3cd816b751242765e8f680480b84ea29e7 ---- /dev/null -+++ b/dtrace/dtrace_mod.c -@@ -0,0 +1,45 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_mod.c -+ * DESCRIPTION: DTrace - framework kernel module -+ * -+ * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/module.h> -+ -+#include "dtrace_dev.h" -+ -+MODULE_AUTHOR("Kris Van Hees (kris.van.hees@oracle.com)"); -+MODULE_DESCRIPTION("Dynamic Tracing"); -+MODULE_VERSION("v0.1"); -+MODULE_LICENSE("GPL"); -+ -+/* -+ * Initialize the module. -+ */ -+static int __init dtrace_init(void) -+{ -+ return dtrace_dev_init(); -+} -+ -+/* -+ * Perform cleanup before the module is removed. -+ */ -+static void __exit dtrace_exit(void) -+{ -+ dtrace_dev_exit(); -+} -+ -+module_init(dtrace_init); -+module_exit(dtrace_exit); -diff --git a/dtrace/dtrace_predicate.c b/dtrace/dtrace_predicate.c -new file mode 100644 -index 0000000000000000000000000000000000000000..004a1c542c760f16631b54cbf105b3f37acc13e1 ---- /dev/null -+++ b/dtrace/dtrace_predicate.c -@@ -0,0 +1,80 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_predicate.c -+ * DESCRIPTION: DTrace - predicate cache implementation -+ * -+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/slab.h> -+ -+#include "dtrace.h" -+ -+static dtrace_cacheid_t dtrace_predcache_id = DTRACE_CACHEIDNONE + 1; -+ -+struct dtrace_predicate *dtrace_predicate_create(struct dtrace_difo *dp) -+{ -+ struct dtrace_predicate *pred; -+ -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ ASSERT(dp->dtdo_refcnt != 0); -+ -+ pred = kzalloc(sizeof(struct dtrace_predicate), GFP_KERNEL); -+ if (pred == NULL) -+ return NULL; -+ -+ pred->dtp_difo = dp; -+ pred->dtp_refcnt = 1; -+ -+ if (!dtrace_difo_cacheable(dp)) -+ return pred; -+ -+ /* -+ * This is only theoretically possible -- we have had 2^32 cacheable -+ * predicates on this machine. We cannot allow any more predicates to -+ * become cacheable: as unlikely as it is, there may be a thread -+ * caching a (now stale) predicate cache ID. (N.B.: the temptation is -+ * being successfully resisted to have this cmn_err() "Holy shit -- we -+ * executed this code!") -+ */ -+ if (dtrace_predcache_id == DTRACE_CACHEIDNONE) -+ return pred; -+ -+ pred->dtp_cacheid = dtrace_predcache_id++; -+ -+ return pred; -+} -+ -+void dtrace_predicate_hold(struct dtrace_predicate *pred) -+{ -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ ASSERT(pred->dtp_difo != NULL && pred->dtp_difo->dtdo_refcnt != 0); -+ ASSERT(pred->dtp_refcnt > 0); -+ -+ pred->dtp_refcnt++; -+} -+ -+void dtrace_predicate_release(struct dtrace_predicate *pred, -+ struct dtrace_vstate *vstate) -+{ -+ struct dtrace_difo *dp = pred->dtp_difo; -+ -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ ASSERT(dp != NULL && dp->dtdo_refcnt != 0); -+ ASSERT(pred->dtp_refcnt > 0); -+ -+ if (--pred->dtp_refcnt == 0) { -+ dtrace_difo_release(dp, vstate); -+ kfree(pred); -+ } -+} -diff --git a/dtrace/dtrace_priv.c b/dtrace/dtrace_priv.c -new file mode 100644 -index 0000000000000000000000000000000000000000..f50133de572df2be7c34b162124cfc05ac0b39d5 ---- /dev/null -+++ b/dtrace/dtrace_priv.c -@@ -0,0 +1,120 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_priv.c -+ * DESCRIPTION: DTrace - privilege support implementation -+ * -+ * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/dtrace_cpu.h> -+ -+#include "dtrace.h" -+ -+/* -+ * This privilege check should be used by actions and subroutines to -+ * verify that the user credentials of the process that enabled the -+ * invoking ECB match the target credentials -+ */ -+int dtrace_priv_proc_common_user(struct dtrace_state *state) -+{ -+ const struct cred *cr, *s_cr = state->dts_cred.dcr_cred; -+ -+ /* -+ * We should always have a non-NULL state cred here, since if cred -+ * is null (anonymous tracing), we fast-path bypass this routine. -+ */ -+ ASSERT(s_cr != NULL); -+ -+ cr = current_cred(); -+ if (cr != NULL && -+ uid_eq(s_cr->euid, cr->euid) && -+ uid_eq(s_cr->euid, cr->uid) && -+ uid_eq(s_cr->euid, cr->suid) && -+ gid_eq(s_cr->egid, cr->egid) && -+ gid_eq(s_cr->egid, cr->gid) && -+ gid_eq(s_cr->egid, cr->sgid)) -+ return 1; -+ -+ return 0; -+} -+ -+/* -+ * This privilege check should be used by actions and subroutines to -+ * verify that the process has not setuid or changed credentials. -+ */ -+int dtrace_priv_proc_common_nocd(void) -+{ -+#ifdef FIXME -+ proc_t *proc; -+ -+ proc = ttoproc(curthread); -+ if (proc != NULL && !(proc->p_flag & SNOCD)) -+ return 1; -+#endif -+ -+ return 0; -+} -+ -+int dtrace_priv_proc_destructive(struct dtrace_state *state) -+{ -+ int action = state->dts_cred.dcr_action; -+ -+ if (((action & DTRACE_CRA_PROC_DESTRUCTIVE_ALLUSER) == 0) && -+ dtrace_priv_proc_common_user(state) == 0) -+ goto bad; -+ -+ if (((action & DTRACE_CRA_PROC_DESTRUCTIVE_CREDCHG) == 0) && -+ dtrace_priv_proc_common_nocd() == 0) -+ goto bad; -+ -+ return 1; -+ -+bad: -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_UPRIV); -+ -+ return 0; -+} -+ -+int dtrace_priv_proc_control(struct dtrace_state *state) -+{ -+ if (state->dts_cred.dcr_action & DTRACE_CRA_PROC_CONTROL) -+ return 1; -+ -+ if (dtrace_priv_proc_common_user(state) && -+ dtrace_priv_proc_common_nocd()) -+ return 1; -+ -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_UPRIV); -+ -+ return 0; -+} -+ -+int dtrace_priv_proc(struct dtrace_state *state) -+{ -+ if (state->dts_cred.dcr_action & DTRACE_CRA_PROC) -+ return 1; -+ -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_UPRIV); -+ -+ return 0; -+} -+ -+int dtrace_priv_kernel(struct dtrace_state *state) -+{ -+ if (state->dts_cred.dcr_action & DTRACE_CRA_KERNEL) -+ return 1; -+ -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_KPRIV); -+ -+ return 0; -+} -diff --git a/dtrace/dtrace_probe.c b/dtrace/dtrace_probe.c -new file mode 100644 -index 0000000000000000000000000000000000000000..8e2e04cb9c1358edc46cd70b6855967b663868f5 ---- /dev/null -+++ b/dtrace/dtrace_probe.c -@@ -0,0 +1,1542 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_probe.c -+ * DESCRIPTION: DTrace - probe implementation -+ * -+ * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/dtrace_cpu.h> -+#include <linux/dtrace_task_impl.h> -+#include <linux/hardirq.h> -+#include <linux/highmem.h> -+#include <linux/idr.h> -+#include <linux/module.h> -+#include <linux/skbuff.h> -+#include <linux/slab.h> -+#include <linux/vmalloc.h> -+#include <asm/pgtable.h> -+#include <asm/cmpxchg.h> -+#include <linux/sched/signal.h> -+ -+#include "dtrace.h" -+ -+ktime_t dtrace_chill_interval = -+ KTIME_INIT(1, 0); -+ktime_t dtrace_chill_max = -+ KTIME_INIT(0, -+ 500 * (NANOSEC / MILLISEC)); -+ -+dtrace_genid_t dtrace_probegen; -+struct kmem_cache *dtrace_probe_cachep; -+ -+static struct idr dtrace_probe_idr; -+ -+static struct task_struct *dtrace_panicked; -+ -+/* -+ * Free probe structure (including partially filled in ones). -+ */ -+void dtrace_probe_free(struct dtrace_probe *probe) -+{ -+ if (probe == NULL) -+ return; -+ -+ dtrace_probe_remove_id(probe->dtpr_id); -+ -+ kfree(probe->dtpr_mod); -+ kfree(probe->dtpr_func); -+ kfree(probe->dtpr_name); -+ -+ kmem_cache_free(dtrace_probe_cachep, probe); -+} -+ -+/* -+ * Create a new probe. -+ */ -+dtrace_id_t dtrace_probe_create(dtrace_provider_id_t prov, const char *mod, -+ const char *func, const char *name, -+ int aframes, void *arg) -+{ -+ struct dtrace_probe *probe; -+ struct dtrace_provider *provider = (struct dtrace_provider *)prov; -+ dtrace_id_t id; -+ -+ probe = kmem_cache_alloc(dtrace_probe_cachep, GFP_KERNEL); -+ if (probe == NULL) -+ goto err_probe; -+ -+ /* -+ * The idr_preload() should be called without holding locks as it may -+ * block. At the same time it is required to protect DTrace structures. -+ * We can't drop it before idr_preload() and acquire after it because -+ * we can't sleep in atomic context (until we reach idr_preload_end()). -+ * -+ * It is better to delay DTrace framework than traced host so the lock -+ * is being held for the duration of idr allocation. -+ * -+ * When the provider is the DTrace core itself, dtrace_lock will be -+ * held when we enter this function. -+ */ -+ if (provider == dtrace_provider) -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ else -+ mutex_lock(&dtrace_lock); -+ -+ idr_preload(GFP_KERNEL); -+ id = idr_alloc_cyclic(&dtrace_probe_idr, probe, 0, 0, GFP_NOWAIT); -+ idr_preload_end(); -+ if (id < 0) -+ goto err_probe; -+ -+ probe->dtpr_id = id; -+ probe->dtpr_ecb = NULL; -+ probe->dtpr_ecb_last = NULL; -+ probe->dtpr_arg = arg; -+ probe->dtpr_predcache = DTRACE_CACHEIDNONE; -+ probe->dtpr_aframes = aframes; -+ probe->dtpr_provider = provider; -+ -+ probe->dtpr_mod = dtrace_strdup(mod); -+ if (probe->dtpr_mod == NULL) -+ goto err_probe; -+ -+ probe->dtpr_func = dtrace_strdup(func); -+ if (probe->dtpr_func == NULL) -+ goto err_probe; -+ -+ probe->dtpr_name = dtrace_strdup(name); -+ if (probe->dtpr_name == NULL) -+ goto err_probe; -+ -+ probe->dtpr_nextmod = probe->dtpr_prevmod = NULL; -+ probe->dtpr_nextfunc = probe->dtpr_prevfunc = NULL; -+ probe->dtpr_nextname = probe->dtpr_prevname = NULL; -+ probe->dtpr_gen = dtrace_probegen++; -+ -+ if (dtrace_hash_add(dtrace_bymod, probe) != 0) -+ goto err_probe; -+ -+ if (dtrace_hash_add(dtrace_byfunc, probe) != 0) -+ goto err_hash_byfunc; -+ -+ if (dtrace_hash_add(dtrace_byname, probe) != 0) -+ goto err_hash_byname; -+ -+ if (provider != dtrace_provider) -+ mutex_unlock(&dtrace_lock); -+ -+ return id; -+ -+err_hash_byname: -+ dtrace_hash_remove(dtrace_byfunc, probe); -+err_hash_byfunc: -+ dtrace_hash_remove(dtrace_bymod, probe); -+err_probe: -+ dtrace_probe_free(probe); -+ if (provider != dtrace_provider) -+ mutex_unlock(&dtrace_lock); -+ return DTRACE_IDNONE; -+} -+EXPORT_SYMBOL(dtrace_probe_create); -+ -+int dtrace_probe_enable(const struct dtrace_probedesc *desc, -+ struct dtrace_enabling *enab) -+{ -+ struct dtrace_probekey pkey; -+ uint32_t priv; -+ kuid_t uid; -+ -+ dtrace_ecb_create_cache = NULL; -+ -+ if (desc == NULL) { -+ (void) dtrace_ecb_create_enable(NULL, enab); -+ -+ return 0; -+ } -+ -+ dtrace_probekey(desc, &pkey); -+ dtrace_cred2priv(enab->dten_vstate->dtvs_state->dts_cred.dcr_cred, -+ &priv, &uid); -+ -+ return dtrace_match(&pkey, priv, uid, dtrace_ecb_create_enable, enab); -+} -+ -+/* -+ * Return the probe argument associated with the specified probe. -+ */ -+void *dtrace_probe_arg(dtrace_provider_id_t id, dtrace_id_t pid) -+{ -+ struct dtrace_probe *probe; -+ void *rval = NULL; -+ -+ mutex_lock(&dtrace_lock); -+ -+ probe = dtrace_probe_lookup_id(pid); -+ if (probe != NULL && -+ probe->dtpr_provider == (struct dtrace_provider *)id) -+ rval = probe->dtpr_arg; -+ -+ mutex_unlock(&dtrace_lock); -+ -+ return rval; -+} -+EXPORT_SYMBOL(dtrace_probe_arg); -+ -+/* -+ * Copy a probe into a probe description. -+ */ -+void dtrace_probe_description(const struct dtrace_probe *prp, -+ struct dtrace_probedesc *pdp) -+{ -+ memset(pdp, 0, sizeof(struct dtrace_probedesc)); -+ pdp->dtpd_id = prp->dtpr_id; -+ -+ strncpy(pdp->dtpd_provider, prp->dtpr_provider->dtpv_name, -+ DTRACE_PROVNAMELEN - 1); -+ -+ strncpy(pdp->dtpd_mod, prp->dtpr_mod, DTRACE_MODNAMELEN - 1); -+ strncpy(pdp->dtpd_func, prp->dtpr_func, DTRACE_FUNCNAMELEN - 1); -+ strncpy(pdp->dtpd_name, prp->dtpr_name, DTRACE_NAMELEN - 1); -+} -+ -+void dtrace_probe_provide(struct dtrace_probedesc *desc, -+ struct dtrace_provider *prv) -+{ -+ int all = 0; -+ -+ if (prv == NULL) { -+ all = 1; -+ prv = dtrace_provider; -+ } -+ -+ do { -+ prv->dtpv_pops.dtps_provide(prv->dtpv_arg, desc); -+ dtrace_for_each_module(prv->dtpv_pops.dtps_provide_module, -+ prv->dtpv_arg); -+ } while (all && (prv = prv->dtpv_next) != NULL); -+} -+ -+/* -+ * Atomically increment a specified error counter from probe context. -+ */ -+static void dtrace_error(uint32_t *counter) -+{ -+ /* -+ * Most counters stored to in probe context are per-CPU counters. -+ * However, there are some error conditions that are sufficiently -+ * arcane that they don't merit per-CPU storage. If these counters -+ * are incremented concurrently on different CPUs, scalability will be -+ * adversely affected -- but we don't expect them to be white-hot in a -+ * correctly constructed enabling... -+ */ -+ uint32_t oval, nval; -+ -+ do { -+ oval = *counter; -+ -+ nval = oval + 1; -+ if (nval == 0) { -+ /* -+ * If the counter would wrap, set it to 1 -- assuring -+ * that the counter is never zero when we have seen -+ * errors. (The counter must be 32-bits because we -+ * aren't guaranteed a 64-bit compare&swap operation.) -+ * To save this code both the infamy of being fingered -+ * by a priggish news story and the indignity of being -+ * the target of a neo-puritan witch trial, we're -+ * carefully avoiding any colorful description of the -+ * likelihood of this condition -- but suffice it to -+ * say that it is only slightly more likely than the -+ * overflow of predicate cache IDs, as discussed in -+ * dtrace_predicate_create(). -+ */ -+ nval = 1; -+ } -+ } while (cmpxchg(counter, oval, nval) != oval); -+} -+ -+static int dtrace_priv_kernel_destructive(struct dtrace_state *state) -+{ -+ if (state->dts_cred.dcr_action & DTRACE_CRA_KERNEL_DESTRUCTIVE) -+ return 1; -+ -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_KPRIV); -+ -+ return 0; -+} -+ -+static void dtrace_action_breakpoint(struct dtrace_ecb *ecb) -+{ -+ struct dtrace_probe *probe = ecb->dte_probe; -+ struct dtrace_provider *prov = probe->dtpr_provider; -+ char c[DTRACE_FULLNAMELEN + 80], *str; -+ char *msg = "dtrace: breakpoint action at probe "; -+ char *ecbmsg = " (ecb "; -+ uintptr_t mask = (0xf << (sizeof(uintptr_t) * NBBY / 4)); -+ uintptr_t val = (uintptr_t)ecb; -+ int shift = (sizeof(uintptr_t) * NBBY) - 4, i = 0; -+ -+ if (dtrace_destructive_disallow) -+ return; -+ -+ /* -+ * It's impossible to be taking action on the NULL probe. -+ */ -+ ASSERT(probe != NULL); -+ -+ /* -+ * This is a poor man's (destitute man's?) sprintf(): we want to -+ * print the provider name, module name, function name and name of -+ * the probe, along with the hex address of the ECB with the breakpoint -+ * action -- all of which we must place in the character buffer by -+ * hand. -+ */ -+ while (*msg != '\0') -+ c[i++] = *msg++; -+ -+ for (str = prov->dtpv_name; *str != '\0'; str++) -+ c[i++] = *str; -+ c[i++] = ':'; -+ -+ for (str = probe->dtpr_mod; *str != '\0'; str++) -+ c[i++] = *str; -+ c[i++] = ':'; -+ -+ for (str = probe->dtpr_func; *str != '\0'; str++) -+ c[i++] = *str; -+ c[i++] = ':'; -+ -+ for (str = probe->dtpr_name; *str != '\0'; str++) -+ c[i++] = *str; -+ -+ while (*ecbmsg != '\0') -+ c[i++] = *ecbmsg++; -+ -+ while (shift >= 0) { -+ mask = (uintptr_t)0xf << shift; -+ -+ if (val >= ((uintptr_t)1 << shift)) -+ c[i++] = "0123456789abcdef"[(val & mask) >> shift]; -+ -+ shift -= 4; -+ } -+ -+ c[i++] = ')'; -+ c[i] = '\0'; -+ -+// debug_enter(c); /* FIXME */ -+} -+ -+static void dtrace_action_panic(struct dtrace_ecb *ecb) -+{ -+ struct dtrace_probe *probe = ecb->dte_probe; -+ -+ /* -+ * It's impossible to be taking action on the NULL probe. -+ */ -+ ASSERT(probe != NULL); -+ -+ if (dtrace_destructive_disallow) -+ return; -+ -+ if (dtrace_panicked != NULL) -+ return; -+ -+ if (cmpxchg(&dtrace_panicked, NULL, current) != NULL) -+ return; -+ -+ /* -+ * We won the right to panic. (We want to be sure that only one -+ * thread calls panic() from dtrace_probe(), and that panic() is -+ * called exactly once.) -+ */ -+ dtrace_panic(KERN_EMERG -+ "dtrace: panic action at probe %s:%s:%s:%s (ecb %p)", -+ probe->dtpr_provider->dtpv_name, probe->dtpr_mod, -+ probe->dtpr_func, probe->dtpr_name, (void *)ecb); -+} -+ -+static void dtrace_action_raise(uint64_t sig) -+{ -+ if (current->dt_task == NULL) -+ return; -+ -+ if (dtrace_destructive_disallow) -+ return; -+ -+ if (sig >= _NSIG) { -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); -+ return; -+ } -+ -+ /* -+ * raise() has a queue depth of 1 -- we ignore all subsequent -+ * invocations of the raise() action. -+ */ -+ if (current->dt_task->dt_sig == 0) -+ current->dt_task->dt_sig = (uint8_t)sig; -+} -+ -+static void dtrace_action_stop(void) -+{ -+ if (current->dt_task == NULL) -+ return; -+ -+ if (dtrace_destructive_disallow) -+ return; -+ -+ if (!current->dt_task->dt_stop) { -+ current->dt_task->dt_stop = 1; -+// current->sig_check = 1; /* FIXME */ -+// aston(current); /* FIXME */ -+ } -+} -+ -+static void dtrace_action_chill(struct dtrace_mstate *mstate, ktime_t val) -+{ -+ ktime_t now; -+ volatile uint16_t *flags; -+ struct cpu_core *cpu = this_cpu_core; -+ -+ if (dtrace_destructive_disallow) -+ return; -+ -+ flags = (volatile uint16_t *)&cpu->cpuc_dtrace_flags; -+ -+ now = dtrace_gethrtime(); -+ -+ if (ktime_gt(ktime_sub(now, cpu->cpu_dtrace_chillmark), -+ dtrace_chill_interval)) { -+ /* -+ * We need to advance the mark to current time. -+ */ -+ cpu->cpu_dtrace_chillmark = now; -+ cpu->cpu_dtrace_chilled = ktime_set(0, 0); -+ } -+ -+ /* -+ * Now check to see if the requested chill time would take us over -+ * the maximum amount of time allowed in the chill interval. (Or -+ * worse, if the calculation itself induces overflow.) -+ */ -+ if (ktime_gt(ktime_add(cpu->cpu_dtrace_chilled, val), -+ dtrace_chill_max) || -+ ktime_lt(ktime_add(cpu->cpu_dtrace_chilled, val), -+ cpu->cpu_dtrace_chilled)) { -+ *flags |= CPU_DTRACE_ILLOP; -+ return; -+ } -+ -+ while (ktime_lt(ktime_sub(dtrace_gethrtime(), now), val)) -+ continue; -+ -+ /* -+ * Normally, we assure that the value of the variable "timestamp" does -+ * not change within an ECB. The presence of chill() represents an -+ * exception from this rule, however. -+ */ -+ mstate->dtms_present &= ~DTRACE_MSTATE_TIMESTAMP; -+ cpu->cpu_dtrace_chilled = ktime_add(cpu->cpu_dtrace_chilled, val); -+} -+ -+static void dtrace_action_ustack(struct dtrace_mstate *mstate, -+ struct dtrace_state *state, uint64_t *buf, -+ uint64_t arg) -+{ -+ int nframes = DTRACE_USTACK_NFRAMES(arg); -+ int strsize = DTRACE_USTACK_STRSIZE(arg); -+ uint64_t *pcs = &buf[2], *fps; -+ char *str = (char *)&pcs[nframes]; -+ int size, offs = 0, i, j; -+ uintptr_t old = mstate->dtms_scratch_ptr, saved; -+ uint16_t *flags = &this_cpu_core->cpuc_dtrace_flags; -+ char *sym; -+ -+ /* -+ * Should be taking a faster path if string space has not been -+ * allocated. -+ */ -+ ASSERT(strsize != 0); -+ -+ /* -+ * We will first allocate some temporary space for the frame pointers. -+ */ -+ fps = (uint64_t *)P2ROUNDUP(mstate->dtms_scratch_ptr, 8); -+ size = (uintptr_t)fps - mstate->dtms_scratch_ptr + -+ (nframes * sizeof(uint64_t)); -+ -+ if (!DTRACE_INSCRATCH(mstate, size)) { -+ /* -+ * Not enough room for our frame pointers -- need to indicate -+ * that we ran out of scratch space. -+ */ -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOSCRATCH); -+ return; -+ } -+ -+ mstate->dtms_scratch_ptr += size; -+ saved = mstate->dtms_scratch_ptr; -+ -+ /* -+ * Now get a stack with both program counters and frame pointers. -+ */ -+ dtrace_getufpstack(buf, fps, nframes + 2); -+ -+ /* -+ * If that faulted, we're cooked. -+ */ -+ if (*flags & CPU_DTRACE_FAULT) -+ goto out; -+ -+ /* -+ * Now we want to walk up the stack, calling the USTACK helper. For -+ * each iteration, we restore the scratch pointer. -+ */ -+ for (i = 0; i < nframes; i++) { -+ mstate->dtms_scratch_ptr = saved; -+ -+ if (offs >= strsize) -+ break; -+ -+ sym = (char *)(uintptr_t)dtrace_helper( -+ DTRACE_HELPER_ACTION_USTACK, -+ mstate, state, pcs[i], fps[i]); -+ -+ /* -+ * If we faulted while running the helper, we're going to -+ * clear the fault and null out the corresponding string. -+ */ -+ if (*flags & CPU_DTRACE_FAULT) { -+ *flags &= ~CPU_DTRACE_FAULT; -+ str[offs++] = '\0'; -+ continue; -+ } -+ -+ if (sym == NULL) { -+ str[offs++] = '\0'; -+ continue; -+ } -+ -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); -+ -+ /* -+ * Now copy in the string that the helper returned to us. -+ */ -+ for (j = 0; offs + j < strsize; j++) { -+ str[offs + j] = sym[j]; -+ if (str[offs + j] == '\0') -+ break; -+ } -+ -+ DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); -+ -+ offs += j + 1; -+ } -+ -+ /* -+ * If we didn't have room for all of the strings, we don't abort -+ * processing -- this needn't be a fatal error -- but we still want -+ * to increment a counter (dts_stkstroverflows) to allow this condition -+ * to be warned about. (If this is from a jstack() action, it is -+ * easily tuned via jstackstrsize.) -+ */ -+ if (offs >= strsize) -+ dtrace_error(&state->dts_stkstroverflows); -+ -+ while (offs < strsize) -+ str[offs++] = '\0'; -+ -+out: -+ mstate->dtms_scratch_ptr = old; -+} -+ -+/* -+ * This macro is used by dtrace_probe_pcap() below. See linux/skbuff.h for the -+ * original. Only change is we pass in an already dereferenced page.p as -+ * the fragment f. -+ */ -+#define dtrace_skb_frag_foreach_page(f, f_off, f_len, p, p_off, p_len, copied) \ -+ for (p = f + ((f_off) >> PAGE_SHIFT), \ -+ p_off = (f_off) & (PAGE_SIZE - 1), \ -+ p_len = skb_frag_must_loop(p) ? \ -+ min_t(u32, f_len, PAGE_SIZE - p_off) : f_len, \ -+ copied = 0; \ -+ copied < f_len; \ -+ copied += p_len, p++, p_off = 0, \ -+ p_len = min_t(u32, f_len - copied, PAGE_SIZE)) \ -+ -+ -+/* -+ * Capture skb data in linear and non-linear portions. Returns 0 on success, -+ * -1 if an error is encountered. -+ */ -+static __always_inline int dtrace_probe_pcap(uint64_t val, size_t *valoffs, -+ size_t size, caddr_t tomax, -+ ktime_t now, -+ struct dtrace_mstate *mstate, -+ struct dtrace_vstate *vstate, -+ volatile uint16_t *flags) -+ -+{ -+ uintptr_t start = *valoffs, end = *valoffs + size; -+ uintptr_t skb_head, skb_data, skb_tail, shinfo; -+ uint32_t skb_end, tail, skb_len = 0; -+ uintptr_t baddr = val; -+ uint8_t nr_frags, f; -+ uint32_t data_len; -+ -+ DTRACE_STORE(uint64_t, tomax, start, ktime_to_ns(now)); -+ -+ *valoffs += (2 * sizeof(uint64_t)); -+ -+ /* -+ * Skip capture of NULL skbs. -+ */ -+ if ((void *)baddr == NULL) -+ goto pcap_done; -+ -+ if (!dtrace_canload(baddr, sizeof(struct sk_buff), mstate, vstate)) -+ return -1; -+ -+ skb_data = dtrace_loadptr(baddr + offsetof(struct sk_buff, data)); -+ skb_head = dtrace_loadptr(baddr + offsetof(struct sk_buff, head)); -+ skb_len = dtrace_load32(baddr + offsetof(struct sk_buff, len)); -+ tail = dtrace_load32(baddr + offsetof(struct sk_buff, tail)); -+ skb_tail = skb_head + tail; -+ -+ if (skb_tail < skb_data) { -+ *flags |= CPU_DTRACE_BADADDR; -+ return -1; -+ } -+ while (*valoffs < end && skb_data < skb_tail) { -+ DTRACE_STORE(uint8_t, tomax, (*valoffs)++, -+ dtrace_load8(skb_data++)); -+ } -+ -+ data_len = dtrace_load32(baddr + offsetof(struct sk_buff, data_len)); -+ -+ /* -+ * If skb is linear, no need to explore fragments. -+ */ -+ if (data_len == 0) -+ goto pcap_done; -+ -+ skb_end = dtrace_load32(baddr + offsetof(struct sk_buff, end)); -+ shinfo = skb_head + skb_end; -+ -+ if (!dtrace_canload(shinfo, sizeof(struct skb_shared_info), -+ mstate, vstate)) -+ return -1; -+ -+ nr_frags = dtrace_load8(shinfo + offsetof(struct skb_shared_info, -+ nr_frags)); -+ -+ /* -+ * See skb_frag_foreach_page() macro usage elsewhere to understand the -+ * manipulations here; the reason we need this complexity is to support -+ * compound pages. -+ */ -+ for (f = 0; f < nr_frags; f++) { -+ uint32_t poff, plen, copied, flen; -+ struct page *p, *frag; -+ uintptr_t foff, v; -+ void *vaddr; -+ -+ flen = dtrace_load32(shinfo + offsetof(struct skb_shared_info, -+ frags[f].bv_len)); -+ foff = dtrace_load32(shinfo + offsetof(struct skb_shared_info, -+ frags[f].bv_offset)); -+ frag = (struct page *)dtrace_loadptr(shinfo + offsetof( -+ struct skb_shared_info, -+ frags[f].bv_page)); -+ -+ dtrace_skb_frag_foreach_page(frag, foff, flen, -+ p, poff, plen, copied) { -+ if (data_len == 0) -+ break; -+ -+ vaddr = kmap_atomic(p); -+ v = (uintptr_t)vaddr + poff; -+ if (!dtrace_canload(v, plen, mstate, vstate)) { -+ kunmap_atomic(vaddr); -+ return -1; -+ } -+ while (*valoffs < end && data_len-- > 0) { -+ DTRACE_STORE(uint8_t, tomax, (*valoffs)++, -+ dtrace_load8(v++)); -+ } -+ kunmap_atomic(vaddr); -+ } -+ } -+ -+pcap_done: -+ /* -+ * Note that we store the skb len here rather than the portion of it we -+ * capture; we can determine the latter when collecting data by using -+ * the "pcapsize" option. Packet capture headers specify a packet size -+ * and a capture size, so we want to be able to provide both. Since -+ * the capture size can be determined from the packet length when -+ * consuming records, we don't need to store it. -+ */ -+ DTRACE_STORE(uint64_t, tomax, start + sizeof(uint64_t), -+ (uint64_t)skb_len); -+ -+ return 0; -+} -+void dtrace_probe(dtrace_id_t id, uintptr_t arg0, uintptr_t arg1, -+ uintptr_t arg2, uintptr_t arg3, uintptr_t arg4, -+ uintptr_t arg5, uintptr_t arg6) -+{ -+ processorid_t cpuid; -+ dtrace_icookie_t cookie; -+ struct dtrace_probe *probe; -+ struct dtrace_mstate mstate; -+ struct dtrace_ecb *ecb; -+ struct dtrace_action *act; -+ intptr_t offs; -+ size_t size; -+ int onintr; -+ int vtime; -+ volatile uint16_t *flags; -+ ktime_t now; -+ uint32_t re_entry; -+ struct dtrace_task *dtsk = current->dt_task; -+ dtrace_id_t old_id; -+ -+#ifdef FIXME -+ /* -+ * Kick out immediately if this CPU is still being born (in which case -+ * curthread will be set to -1) or the current thread can't allow -+ * probes in its current context. -+ */ -+ if (((uintptr_t)curthread & 1) || (curthread->t_flag & T_DONTDTRACE)) -+ return; -+#endif -+ -+ DTRACE_SYNC_ENTER_CRITICAL(cookie, re_entry); -+ -+ /* -+ * Probe context is not re-entrant, unless we're getting called to -+ * process an ERROR probe. -+ */ -+ flags = (volatile uint16_t *)&this_cpu_core->cpuc_dtrace_flags; -+ cpuid = smp_processor_id(); -+ if (re_entry && id != dtrace_probeid_error) { -+ dt_dbg_probe("Attempt to fire probe from within a probe " \ -+ "(ID %d, oID %d, CPU %d)\n", id, -+ (int)this_cpu_core->cpuc_current_probe, cpuid); -+ DTRACE_SYNC_EXIT_CRITICAL(cookie, re_entry); -+ return; -+ } -+ -+ probe = dtrace_probe_lookup_id(id); -+ onintr = in_interrupt(); -+ -+ if (!onintr && probe->dtpr_predcache != DTRACE_CACHEIDNONE && -+ dtsk != NULL && probe->dtpr_predcache == dtsk->dt_predcache) { -+ DTRACE_SYNC_EXIT_CRITICAL(cookie, re_entry); -+ return; -+ } -+ -+ if (oops_in_progress) { -+ DTRACE_SYNC_EXIT_CRITICAL(cookie, re_entry); -+ return; -+ } -+ -+ old_id = this_cpu_core->cpuc_current_probe; -+ this_cpu_core->cpuc_current_probe = id; -+ -+ now = dtrace_gethrtime(); -+ vtime = (dtrace_vtime_references > 0); -+ -+ if (vtime && dtsk != NULL && ktime_nz(dtsk->dt_start)) -+ dtsk->dt_vtime = ktime_add(dtsk->dt_vtime, -+ ktime_sub(now, dtsk->dt_start)); -+ -+ mstate.dtms_difo = NULL; -+ mstate.dtms_probe = probe; -+ mstate.dtms_strtok = (uintptr_t)NULL; -+ mstate.dtms_arg[0] = arg0; -+ mstate.dtms_arg[1] = arg1; -+ mstate.dtms_arg[2] = arg2; -+ mstate.dtms_arg[3] = arg3; -+ mstate.dtms_arg[4] = arg4; -+ mstate.dtms_arg[5] = arg5; -+ mstate.dtms_arg[6] = arg6; -+ -+ for (ecb = probe->dtpr_ecb; ecb != NULL; ecb = ecb->dte_next) { -+ struct dtrace_predicate *pred = ecb->dte_predicate; -+ struct dtrace_state *state = ecb->dte_state; -+ struct dtrace_buffer *buf = &state->dts_buffer[cpuid]; -+ struct dtrace_buffer *aggbuf = &state->dts_aggbuffer[cpuid]; -+ struct dtrace_vstate *vstate = &state->dts_vstate; -+ struct dtrace_provider *prov = probe->dtpr_provider; -+ int committed = 0; -+ caddr_t tomax; -+ -+ /* -+ * A little subtlety with the following (seemingly innocuous) -+ * declaration of the automatic 'val': by looking at the -+ * code, you might think that it could be declared in the -+ * action processing loop, below. (That is, it's only used in -+ * the action processing loop.) However, it must be declared -+ * out of that scope because in the case of DIF expression -+ * arguments to aggregating actions, one iteration of the -+ * action loop will use the last iteration's value. -+ */ -+ uint64_t val = 0; -+ -+ mstate.dtms_present = DTRACE_MSTATE_ARGS | DTRACE_MSTATE_PROBE; -+ *flags &= ~CPU_DTRACE_ERROR; -+ -+ if (prov == dtrace_provider) { -+ /* -+ * If dtrace itself is the provider of this probe, -+ * we're only going to continue processing the ECB if -+ * arg0 (the dtrace_state_t) is equal to the ECB's -+ * creating state. (This prevents disjoint consumers -+ * from seeing one another's metaprobes.) -+ */ -+ if (arg0 != (uint64_t)(uintptr_t)state) -+ continue; -+ } -+ -+ if (state->dts_activity != DTRACE_ACTIVITY_ACTIVE) { -+ /* -+ * We're not currently active. If our provider isn't -+ * the dtrace pseudo provider, we're not interested. -+ */ -+ if (prov != dtrace_provider) -+ continue; -+ -+ /* -+ * Now we must further check if we are in the BEGIN -+ * probe. If we are, we will only continue orocessing -+ * if we're still in WARMUP -- if one BEGIN enabling -+ * has invoked the exit() action, we don't want to -+ * evaluate subsequent BEGIN enablings. -+ */ -+ if (probe->dtpr_id == dtrace_probeid_begin && -+ state->dts_activity != DTRACE_ACTIVITY_WARMUP) { -+ ASSERT(state->dts_activity == -+ DTRACE_ACTIVITY_DRAINING); -+ continue; -+ } -+ } -+ -+ dt_dbg_probe("Probe (ID %d EPID %d) on CPU %d...\n", -+ id, ecb->dte_epid, cpuid); -+ if (ecb->dte_cond) { -+ /* -+ * If the dte_cond bits indicate that this -+ * consumer is only allowed to see user-mode firings -+ * of this probe, call the provider's dtps_usermode() -+ * entry point to check that the probe was fired -+ * while in a user context. Skip this ECB if that's -+ * not the case. -+ */ -+ if ((ecb->dte_cond & DTRACE_COND_USERMODE) && -+ prov->dtpv_pops.dtps_usermode( -+ prov->dtpv_arg, probe->dtpr_id, probe->dtpr_arg -+ ) == 0) { -+ dt_dbg_probe("Probe (ID %d EPID %d) Skipped\n", -+ id, ecb->dte_epid); -+ continue; -+ } -+ -+ /* -+ * This is more subtle than it looks. We have to be -+ * absolutely certain that current_cred() isn't going -+ * to change out from under us so it's only legit to -+ * examine that structure if we're in constrained -+ * situations. Currently, the only times we'll use this -+ * check is if a non-super-user has enabled the -+ * profile or syscall providers -- providers that -+ * allow visibility of all processes. For the -+ * profile case, the check above will ensure that -+ * we're examining a user context. -+ */ -+ if (ecb->dte_cond & DTRACE_COND_OWNER) { -+ const struct cred *cr; -+ const struct cred *s_cr = -+ ecb->dte_state->dts_cred.dcr_cred; -+ -+ ASSERT(s_cr != NULL); -+ -+ cr = current_cred(); -+ if (cr == NULL || -+ !uid_eq(s_cr->euid, cr->euid) || -+ !uid_eq(s_cr->euid, cr->uid) || -+ !uid_eq(s_cr->euid, cr->suid) || -+ !gid_eq(s_cr->egid, cr->egid) || -+ !gid_eq(s_cr->egid, cr->gid) || -+ !gid_eq(s_cr->egid, cr->sgid)) { -+ dt_dbg_probe("Probe (ID %d EPID %d) " -+ "Skipped\n", -+ id, ecb->dte_epid); -+ continue; -+ } -+ } -+ } -+ -+ if (ktime_gt(ktime_sub(now, state->dts_alive), -+ dtrace_deadman_timeout)) { -+ /* -+ * We seem to be dead. Unless we (a) have kernel -+ * destructive permissions (b) have expicitly enabled -+ * destructive actions and (c) destructive actions have -+ * not been disabled, we're going to transition into -+ * the KILLED state, from which no further processing -+ * on this state will be performed. -+ */ -+ if (!dtrace_priv_kernel_destructive(state) || -+ !state->dts_cred.dcr_destructive || -+ dtrace_destructive_disallow) { -+ enum dtrace_activity *activity = -+ &state->dts_activity; -+ enum dtrace_activity curr; -+ -+ do { -+ curr = state->dts_activity; -+ } while (cmpxchg(activity, curr, -+ DTRACE_ACTIVITY_KILLED) != curr); -+ -+ dt_dbg_probe("Probe (ID %d EPID %d) Skipped\n", -+ id, ecb->dte_epid); -+ continue; -+ } -+ } -+ -+ offs = dtrace_buffer_reserve(buf, ecb->dte_needed, -+ ecb->dte_alignment, state, -+ &mstate); -+ if (offs < 0) { -+ dt_dbg_probe("Probe (ID %d EPID %d) Skipped\n", -+ id, ecb->dte_epid); -+ continue; -+ } -+ -+ tomax = buf->dtb_tomax; -+ ASSERT(tomax != NULL); -+ -+ if (ecb->dte_size != 0) { -+ DTRACE_STORE(uint32_t, tomax, offs, ecb->dte_epid); -+ dt_dbg_buf(" Store: %p[%ld .. %ld] <- %d [EPID] " -+ "(from %s::%d)\n", -+ buf, offs, offs + sizeof(uint32_t) - 1, -+ ecb->dte_epid, __func__, __LINE__); -+ } -+ -+ mstate.dtms_epid = ecb->dte_epid; -+ mstate.dtms_present |= DTRACE_MSTATE_EPID; -+ -+ if (state->dts_cred.dcr_visible & DTRACE_CRV_KERNEL) -+ mstate.dtms_access = DTRACE_ACCESS_KERNEL; -+ else -+ mstate.dtms_access = 0; -+ -+ if (pred != NULL) { -+ struct dtrace_difo *dp = pred->dtp_difo; -+ int rval; -+ -+ dt_dbg_probe(" Evaluating predicate...\n"); -+ -+ rval = dtrace_dif_emulate(dp, &mstate, vstate, state); -+ -+ if (!(*flags & CPU_DTRACE_ERROR) && !rval) { -+ dtrace_cacheid_t cid = -+ probe->dtpr_predcache; -+ -+ if (cid != DTRACE_CACHEIDNONE && !onintr) { -+ /* -+ * Update the predicate cache... -+ */ -+ ASSERT(cid == pred->dtp_cacheid); -+ if (dtsk != NULL) -+ dtsk->dt_predcache = cid; -+ } -+ -+ dt_dbg_probe(" Predicate not met (%d)\n", -+ rval); -+ dt_dbg_probe("Probe (ID %d EPID %d) Done\n", -+ id, ecb->dte_epid); -+ continue; -+ } -+ -+ dt_dbg_probe(" Predicate met (%d)\n", rval); -+ } -+ -+ for (act = ecb->dte_action; -+ !(*flags & CPU_DTRACE_ERROR) && act != NULL; -+ act = act->dta_next) { -+ size_t valoffs; -+ struct dtrace_difo *dp; -+ struct dtrace_recdesc *rec = &act->dta_rec; -+ -+ dt_dbg_probe(" Evaluating action %p (kind %d)...\n", -+ act, act->dta_kind); -+ -+ size = rec->dtrd_size; -+ valoffs = offs + rec->dtrd_offset; -+ -+ if (DTRACEACT_ISAGG(act->dta_kind)) { -+ uint64_t v = 0xbad; -+ struct dtrace_aggregation *agg; -+ -+ agg = (struct dtrace_aggregation *)act; -+ -+ dp = act->dta_difo; -+ if (dp != NULL) -+ v = dtrace_dif_emulate(dp, &mstate, -+ vstate, state); -+ -+ if (*flags & CPU_DTRACE_ERROR) -+ continue; -+ -+ /* -+ * Note that we always pass the expression -+ * value from the previous iteration of the -+ * action loop. This value will only be used -+ * if there is an expression argument to the -+ * aggregating action, denoted by the -+ * dtag_hasarg field. -+ */ -+ dtrace_aggregate(agg, buf, offs, aggbuf, v, -+ val); -+ continue; -+ } -+ -+ switch (act->dta_kind) { -+ case DTRACEACT_STOP: -+ if (dtrace_priv_proc_destructive(state)) -+ dtrace_action_stop(); -+ continue; -+ -+ case DTRACEACT_BREAKPOINT: -+ if (dtrace_priv_kernel_destructive(state)) -+ dtrace_action_breakpoint(ecb); -+ continue; -+ -+ case DTRACEACT_PANIC: -+ if (dtrace_priv_kernel_destructive(state)) -+ dtrace_action_panic(ecb); -+ continue; -+ -+ case DTRACEACT_STACK: -+ if (!dtrace_priv_kernel(state)) -+ continue; -+ -+ dtrace_getpcstack( -+ (uint64_t *)(tomax + valoffs), -+ size / sizeof(pc_t), -+ probe->dtpr_aframes + 1, -+ DTRACE_ANCHORED(probe) -+ ? NULL -+ : (uint32_t *)arg0); -+ -+ continue; -+ -+ case DTRACEACT_JSTACK: -+ case DTRACEACT_USTACK: -+ if (!dtrace_priv_proc(state)) -+ continue; -+ -+ /* -+ * See comment in DIF_VAR_PID. -+ */ -+ if (DTRACE_ANCHORED(mstate.dtms_probe) && -+ in_interrupt()) { -+ int depth = DTRACE_USTACK_NFRAMES( -+ rec->dtrd_arg) + 2; -+ -+ dtrace_bzero((void *)(tomax + valoffs), -+ DTRACE_USTACK_STRSIZE( -+ rec->dtrd_arg) + -+ depth * sizeof(uint64_t)); -+ -+ continue; -+ } -+ -+ if (DTRACE_USTACK_STRSIZE(rec->dtrd_arg) != 0 && -+ dtsk != NULL && dtsk->dt_helpers != NULL) { -+ /* -+ * This is the slow path -- we have -+ * allocated string space, and we're -+ * getting the stack of a process that -+ * has helpers. Call into a separate -+ * routine to perform this processing. -+ */ -+ dtrace_action_ustack( -+ &mstate, state, -+ (uint64_t *)(tomax + valoffs), -+ rec->dtrd_arg); -+ continue; -+ } -+ -+ dtrace_getupcstack( -+ (uint64_t *)(tomax + valoffs), -+ DTRACE_USTACK_NFRAMES(rec->dtrd_arg) + -+ 2); -+ continue; -+ -+ default: -+ break; -+ } -+ -+ dp = act->dta_difo; -+ ASSERT(dp != NULL); -+ -+ val = dtrace_dif_emulate(dp, &mstate, vstate, state); -+ -+ if (*flags & CPU_DTRACE_ERROR) -+ continue; -+ -+ switch (act->dta_kind) { -+ case DTRACEACT_SPECULATE: -+ ASSERT(buf == &state->dts_buffer[cpuid]); -+ buf = dtrace_speculation_buffer(state, cpuid, -+ val); -+ -+ if (buf == NULL) { -+ *flags |= CPU_DTRACE_DROP; -+ continue; -+ } -+ -+ offs = dtrace_buffer_reserve(buf, -+ ecb->dte_needed, -+ ecb->dte_alignment, -+ state, NULL); -+ -+ if (offs < 0) { -+ *flags |= CPU_DTRACE_DROP; -+ continue; -+ } -+ -+ tomax = buf->dtb_tomax; -+ ASSERT(tomax != NULL); -+ -+ if (ecb->dte_size != 0) { -+ DTRACE_STORE(uint32_t, tomax, offs, -+ ecb->dte_epid); -+ dt_dbg_buf(" Store: %p[%ld .. %ld] " -+ "<- %d [EPID] " -+ "(from %s::%d)\n", -+ buf, offs, -+ offs + sizeof(uint32_t) - 1, -+ ecb->dte_epid, -+ __FUNCTION__, __LINE__); -+ } -+ -+ continue; -+ -+ case DTRACEACT_CHILL: -+ if (dtrace_priv_kernel_destructive(state)) -+ dtrace_action_chill(&mstate, -+ ns_to_ktime(val)); -+ -+ continue; -+ -+ case DTRACEACT_RAISE: -+ if (dtrace_priv_proc_destructive(state)) -+ dtrace_action_raise(val); -+ -+ continue; -+ -+ case DTRACEACT_COMMIT: -+ ASSERT(!committed); -+ -+ /* -+ * We need to commit our buffer state. -+ */ -+ if (ecb->dte_size) { -+ buf->dtb_offset = offs + ecb->dte_size; -+ dt_dbg_buf(" Consume: %p[%ld .. " -+ "%lld]\n", -+ buf, offs, -+ buf->dtb_offset - 1); -+ } -+ -+ buf = &state->dts_buffer[cpuid]; -+ dtrace_speculation_commit(state, cpuid, val); -+ committed = 1; -+ continue; -+ -+ case DTRACEACT_DISCARD: -+ dtrace_speculation_discard(state, cpuid, val); -+ continue; -+ -+ case DTRACEACT_DIFEXPR: -+ case DTRACEACT_LIBACT: -+ case DTRACEACT_PRINTF: -+ case DTRACEACT_PRINTA: -+ case DTRACEACT_SYSTEM: -+ case DTRACEACT_FREOPEN: -+ case DTRACEACT_TRACEMEM: -+ case DTRACEACT_PCAP: -+ break; -+ -+ case DTRACEACT_SYM: -+ case DTRACEACT_MOD: -+ if (!dtrace_priv_kernel(state)) -+ continue; -+ break; -+ -+ case DTRACEACT_USYM: -+ case DTRACEACT_UMOD: -+ case DTRACEACT_UADDR: { -+ pid_t pid = current->pid; -+ pid_t tgid = current->tgid; -+ -+ if (!dtrace_priv_proc(state)) -+ continue; -+ -+ DTRACE_STORE(uint64_t, tomax, valoffs, -+ (uint64_t)pid); -+ dt_dbg_buf(" Store: %p[%ld .. %ld] <- %lld " -+ "[PID] (from %s::%d)\n", -+ buf, valoffs, -+ valoffs + sizeof(uint64_t) - 1, -+ (uint64_t)pid, -+ __FUNCTION__, __LINE__); -+ DTRACE_STORE(uint64_t, tomax, -+ valoffs + sizeof(uint64_t), -+ (uint64_t)tgid); -+ dt_dbg_buf(" Store: %p[%ld .. %ld] <- %lld " -+ "[TGID] (from %s::%d)\n", -+ buf, valoffs + sizeof(uint64_t), -+ valoffs + 2 * sizeof(uint64_t) - 1, -+ (uint64_t)tgid, -+ __FUNCTION__, __LINE__); -+ DTRACE_STORE(uint64_t, tomax, -+ valoffs + 2 * sizeof(uint64_t), -+ val); -+ dt_dbg_buf(" Store: %p[%ld .. %ld] <- %lld " -+ "(from %s::%d)\n", -+ buf, valoffs + 2 * sizeof(uint64_t), -+ valoffs + 3 * sizeof(uint64_t) - 1, -+ val, __FUNCTION__, __LINE__); -+ -+ continue; -+ } -+ -+ case DTRACEACT_EXIT: { -+ /* -+ * For the exit action, we are going to attempt -+ * to atomically set our activity to be -+ * draining. If this fails (either because -+ * another CPU has beat us to the exit action, -+ * or because our current activity is something -+ * other than ACTIVE or WARMUP), we will -+ * continue. This assures that the exit action -+ * can be successfully recorded at most once -+ * when we're in the ACTIVE state. If we're -+ * encountering the exit() action while in -+ * COOLDOWN, however, we want to honor the new -+ * status code. (We know that we're the only -+ * thread in COOLDOWN, so there is no race.) -+ */ -+ enum dtrace_activity *activity = -+ &state->dts_activity; -+ enum dtrace_activity curr = -+ state->dts_activity; -+ -+ if (curr == DTRACE_ACTIVITY_COOLDOWN) -+ break; -+ -+ if (curr != DTRACE_ACTIVITY_WARMUP) -+ curr = DTRACE_ACTIVITY_ACTIVE; -+ -+ if (cmpxchg(activity, curr, -+ DTRACE_ACTIVITY_DRAINING) != curr) { -+ *flags |= CPU_DTRACE_DROP; -+ continue; -+ } -+ -+ break; -+ } -+ -+ default: -+ ASSERT(0); -+ } -+ -+ if (dp->dtdo_rtype.dtdt_flags & DIF_TF_BYREF) { -+ uintptr_t end = valoffs + size; -+ -+ if (!dtrace_vcanload((void *)(uintptr_t)val, -+ &dp->dtdo_rtype, &mstate, -+ vstate)) -+ continue; -+ -+ if (act->dta_kind == DTRACEACT_PCAP) { -+ if (dtrace_probe_pcap(val, &valoffs, -+ size, tomax, now, -+ &mstate, vstate, -+ flags) == -1) -+ break; -+ continue; -+ } -+ -+ /* -+ * If this is a string, we're going to only -+ * load until we find the zero byte -- after -+ * which we'll store zero bytes. -+ */ -+ if (dp->dtdo_rtype.dtdt_kind == -+ DIF_TYPE_STRING) { -+ char c = '\0' + 1; -+ int intuple = act->dta_intuple; -+ size_t s; -+ -+ for (s = 0; s < size; s++) { -+ if (c != '\0') -+ c = dtrace_load8(val++); -+ -+ DTRACE_STORE(uint8_t, tomax, -+ valoffs++, c); -+ dt_dbg_buf(" Store: %p[%ld]" -+ " <- %d (from " -+ "%s::%d)\n", -+ buf, valoffs, c, -+ __FUNCTION__, -+ __LINE__); -+ -+ if (c == '\0' && intuple) -+ break; -+ } -+ -+ continue; -+ } -+ -+ while (valoffs < end) { -+ DTRACE_STORE(uint8_t, tomax, valoffs++, -+ dtrace_load8(val++)); -+ dt_dbg_buf(" Store: %p[%ld] <- ??? " -+ "(from %s::%d)\n", -+ buf, valoffs, -+ __FUNCTION__, __LINE__); -+ } -+ -+ continue; -+ } -+ -+ switch (size) { -+ case 0: -+ break; -+ case sizeof(uint8_t): -+ DTRACE_STORE(uint8_t, tomax, valoffs, val); -+ dt_dbg_buf(" Store: %p[%ld] <- %d " -+ "(from %s::%d)\n", -+ buf, valoffs, (uint8_t)val, -+ __FUNCTION__, __LINE__); -+ break; -+ case sizeof(uint16_t): -+ DTRACE_STORE(uint16_t, tomax, valoffs, val); -+ dt_dbg_buf(" Store: %p[%ld .. %ld] <- %d " -+ "(from %s::%d)\n", -+ buf, valoffs, -+ valoffs + sizeof(uint16_t) - 1, -+ (uint16_t)val, -+ __FUNCTION__, __LINE__); -+ break; -+ case sizeof(uint32_t): -+ DTRACE_STORE(uint32_t, tomax, valoffs, val); -+ dt_dbg_buf(" Store: %p[%ld] <- %d " -+ "(from %s::%d)\n", -+ buf, valoffs, -+ (uint32_t)val, -+ __FUNCTION__, __LINE__); -+ break; -+ case sizeof(uint64_t): -+ DTRACE_STORE(uint64_t, tomax, valoffs, val); -+ dt_dbg_buf(" Store: %p[%ld] <- %lld " -+ "(from %s::%d)\n", -+ buf, valoffs, -+ val, -+ __FUNCTION__, __LINE__); -+ break; -+ default: -+ /* -+ * Any other size should have been returned by -+ * reference, not by value. -+ */ -+ ASSERT(0); -+ break; -+ } -+ } -+ -+ if (*flags & CPU_DTRACE_DROP) { -+ dt_dbg_probe(" -> Dropped\n"); -+ continue; -+ } -+ -+ if (*flags & CPU_DTRACE_FAULT) { -+ int ndx; -+ struct dtrace_action *err; -+ -+ dt_dbg_probe(" -> Failed (%x)\n", *flags); -+ -+ buf->dtb_errors++; -+ -+ if (probe->dtpr_id == dtrace_probeid_error) { -+ /* -+ * There's nothing we can do -- we had an -+ * error on the error probe. We bump an -+ * error counter to at least indicate that -+ * this condition happened. -+ */ -+ dtrace_error(&state->dts_dblerrors); -+ continue; -+ } -+ -+ if (vtime && dtsk != NULL) -+ /* -+ * Before recursing on dtrace_probe(), we -+ * need to explicitly clear out our start -+ * time to prevent it from being accumulated -+ * into the dtrace_vtime. -+ */ -+ dtsk->dt_start = ktime_set(0, 0); -+ -+ /* -+ * Iterate over the actions to figure out which action -+ * we were processing when we experienced the error. -+ * Note that act points _past_ the faulting action; if -+ * act is ecb->dte_action, the fault was in the -+ * predicate, if it's ecb->dte_action->dta_next it's -+ * in action #1, and so on. -+ */ -+ for (err = ecb->dte_action, ndx = 0; -+ err != act; err = err->dta_next, ndx++) -+ continue; -+ -+ dtrace_probe_error( -+ state, ecb->dte_epid, ndx, -+ (mstate.dtms_present & DTRACE_MSTATE_FLTOFFS) -+ ? mstate.dtms_fltoffs -+ : -1, -+ DTRACE_FLAGS2FLT(*flags), -+ this_cpu_core->cpuc_dtrace_illval); -+ -+ continue; -+ } -+ -+ if (!committed) { -+ buf->dtb_offset = offs + ecb->dte_size; -+ dt_dbg_buf(" Consume: %p[%ld .. %lld]\n", -+ buf, offs, buf->dtb_offset); -+ } -+ -+ dt_dbg_probe("Probe (ID %d EPID %d) Done\n", -+ id, ecb->dte_epid); -+ } -+ -+ if (vtime && dtsk != NULL) -+ dtsk->dt_start = dtrace_gethrtime(); -+ -+ this_cpu_core->cpuc_current_probe = old_id; -+ DTRACE_SYNC_EXIT_CRITICAL(cookie, re_entry); -+ -+ if (dtsk != NULL && dtsk->dt_sig != 0) { -+ int sig = dtsk->dt_sig; -+ -+ dtsk->dt_sig = 0; -+ -+ send_sig(sig, current, 0); -+ } -+} -+EXPORT_SYMBOL(dtrace_probe); -+ -+int dtrace_probe_init(void) -+{ -+ dtrace_id_t id; -+ -+ dtrace_probe_cachep = KMEM_CACHE(dtrace_probe, SLAB_HWCACHE_ALIGN); -+ if (dtrace_probe_cachep == NULL) -+ return -ENOMEM; -+ -+ idr_init(&dtrace_probe_idr); -+ -+ /* -+ * We create a ID 0 entry as a sentinel, so we can always depend on it -+ * being the very first entry. This is used in functionality that runs -+ * through the list of probes. -+ */ -+ idr_preload(GFP_KERNEL); -+ id = idr_alloc_cyclic(&dtrace_probe_idr, NULL, 0, 0, GFP_NOWAIT); -+ idr_preload_end(); -+ -+ return id == 0 ? 0 : -EAGAIN; -+} -+ -+void dtrace_probe_exit(void) -+{ -+ idr_destroy(&dtrace_probe_idr); -+ kmem_cache_destroy(dtrace_probe_cachep); -+} -+ -+void dtrace_probe_remove_id(dtrace_id_t id) -+{ -+ idr_remove(&dtrace_probe_idr, id); -+} -+ -+struct dtrace_probe *dtrace_probe_lookup_id(dtrace_id_t id) -+{ -+ return idr_find(&dtrace_probe_idr, id); -+} -+ -+static int dtrace_probe_lookup_match(struct dtrace_probe *probe, void *arg) -+{ -+ *((dtrace_id_t *)arg) = probe->dtpr_id; -+ -+ return DTRACE_MATCH_DONE; -+} -+ -+dtrace_id_t dtrace_probe_lookup(dtrace_provider_id_t prid, const char *mod, -+ const char *func, const char *name) -+{ -+ struct dtrace_probekey pkey; -+ dtrace_id_t id; -+ int match; -+ -+ pkey.dtpk_prov = ((struct dtrace_provider *)prid)->dtpv_name; -+ pkey.dtpk_pmatch = &dtrace_match_string; -+ pkey.dtpk_mod = mod; -+ pkey.dtpk_mmatch = mod ? &dtrace_match_string : &dtrace_match_nul; -+ pkey.dtpk_func = func; -+ pkey.dtpk_fmatch = func ? &dtrace_match_string : &dtrace_match_nul; -+ pkey.dtpk_name = name; -+ pkey.dtpk_nmatch = name ? &dtrace_match_string : &dtrace_match_nul; -+ pkey.dtpk_id = DTRACE_IDNONE; -+ -+ mutex_lock(&dtrace_lock); -+ match = dtrace_match(&pkey, DTRACE_PRIV_ALL, -+ make_kuid(init_user_namespace, 0), -+ dtrace_probe_lookup_match, &id); -+ mutex_unlock(&dtrace_lock); -+ -+ ASSERT(match == 1 || match == 0); -+ -+ return match ? id : 0; -+} -+EXPORT_SYMBOL(dtrace_probe_lookup); -+ -+struct dtrace_probe *dtrace_probe_get_next(dtrace_id_t *idp) -+{ -+ return idr_get_next(&dtrace_probe_idr, idp); -+} -+ -+int dtrace_probe_for_each(int (*fn)(int id, void *p, void *data), void *data) -+{ -+ return idr_for_each(&dtrace_probe_idr, fn, data); -+} -diff --git a/dtrace/dtrace_probe_ctx.c b/dtrace/dtrace_probe_ctx.c -new file mode 100644 -index 0000000000000000000000000000000000000000..f04b5b26922291955285a8aba7a3f6cb6ca6c512 ---- /dev/null -+++ b/dtrace/dtrace_probe_ctx.c -@@ -0,0 +1,659 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_probe_ctx.c -+ * DESCRIPTION: DTrace - probe context safe functions -+ * -+ * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/dtrace_cpu.h> -+ -+#include "dtrace.h" -+ -+void dtrace_panic(const char *fmt, ...) -+{ -+ va_list alist; -+ -+ va_start(alist, fmt); -+ vprintk(fmt, alist); -+ va_end(alist); -+ -+ BUG(); -+} -+EXPORT_SYMBOL(dtrace_panic); -+ -+int dtrace_assfail(const char *a, const char *f, int l) -+{ -+ dtrace_panic(KERN_EMERG "assertion failed: %s, file: %s, line: %d", -+ a, f, l); -+ -+ /* -+ * FIXME: We can do better than this. The OpenSolaris DTrace source -+ * states that this cannot be optimized away. -+ */ -+ return a[(uintptr_t)f]; -+} -+EXPORT_SYMBOL(dtrace_assfail); -+ -+#define DT_MASK_LO 0x00000000FFFFFFFFULL -+ -+static void dtrace_add_128(uint64_t *addend1, uint64_t *addend2, uint64_t *sum) -+{ -+ uint64_t result[2]; -+ -+ result[0] = addend1[0] + addend2[0]; -+ result[1] = addend1[1] + addend2[1] + -+ (result[0] < addend1[0] || result[0] < addend2[0] ? 1 : 0); -+ -+ sum[0] = result[0]; -+ sum[1] = result[1]; -+} -+ -+static void dtrace_shift_128(uint64_t *a, int b) -+{ -+ uint64_t mask; -+ -+ if (b == 0) -+ return; -+ -+ if (b < 0) { -+ b = -b; -+ -+ if (b >= 64) { -+ a[0] = a[1] >> (b - 64); -+ a[1] = 0; -+ } else { -+ a[0] >>= b; -+ mask = 1LL << (64 - b); -+ mask -= 1; -+ a[0] |= ((a[1] & mask) << (64 - b)); -+ a[1] >>= b; -+ } -+ } else { -+ if (b >= 64) { -+ a[1] = a[0] << (b - 64); -+ a[0] = 0; -+ } else { -+ a[1] <<= b; -+ mask = a[0] >> (64 - b); -+ a[1] |= mask; -+ a[0] <<= b; -+ } -+ } -+} -+ -+static void dtrace_multiply_128(uint64_t factor1, uint64_t factor2, -+ uint64_t *product) -+{ -+ uint64_t hi1, hi2, lo1, lo2; -+ uint64_t tmp[2]; -+ -+ hi1 = factor1 >> 32; -+ hi2 = factor2 >> 32; -+ -+ lo1 = factor1 & DT_MASK_LO; -+ lo2 = factor2 & DT_MASK_LO; -+ -+ product[0] = lo1 * lo2; -+ product[1] = hi1 * hi2; -+ -+ tmp[0] = hi1 * lo2; -+ tmp[1] = 0; -+ dtrace_shift_128(tmp, 32); -+ dtrace_add_128(product, tmp, product); -+ -+ tmp[0] = hi2 * lo1; -+ tmp[1] = 0; -+ dtrace_shift_128(tmp, 32); -+ dtrace_add_128(product, tmp, product); -+} -+ -+void dtrace_aggregate_min(uint64_t *oval, uint64_t nval, uint64_t arg) -+{ -+ if ((int64_t)nval < (int64_t)*oval) -+ *oval = nval; -+} -+ -+void dtrace_aggregate_max(uint64_t *oval, uint64_t nval, uint64_t arg) -+{ -+ if ((int64_t)nval > (int64_t)*oval) -+ *oval = nval; -+} -+ -+void dtrace_aggregate_quantize(uint64_t *quanta, uint64_t nval, uint64_t incr) -+{ -+ int i, zero = DTRACE_QUANTIZE_ZEROBUCKET; -+ int64_t val = (int64_t)nval; -+ -+ if (val < 0) { -+ for (i = 0; i < zero; i++) { -+ if (val <= DTRACE_QUANTIZE_BUCKETVAL(i)) { -+ quanta[i] += incr; -+ -+ return; -+ } -+ } -+ } else { -+ for (i = zero + 1; i < DTRACE_QUANTIZE_NBUCKETS; i++) { -+ if (val < DTRACE_QUANTIZE_BUCKETVAL(i)) { -+ quanta[i - 1] += incr; -+ -+ return; -+ } -+ } -+ -+ quanta[DTRACE_QUANTIZE_NBUCKETS - 1] += incr; -+ -+ return; -+ } -+ -+ ASSERT(0); -+} -+ -+void dtrace_aggregate_lquantize(uint64_t *lquanta, uint64_t nval, -+ uint64_t incr) -+{ -+ uint64_t arg = *lquanta++; -+ int32_t base = DTRACE_LQUANTIZE_BASE(arg); -+ uint16_t step = DTRACE_LQUANTIZE_STEP(arg); -+ uint16_t levels = DTRACE_LQUANTIZE_LEVELS(arg); -+ int64_t val = (int64_t)nval, level; -+ -+ ASSERT(step != 0); -+ ASSERT(levels != 0); -+ -+ if (val < base) { -+ lquanta[0] += incr; -+ -+ return; -+ } -+ -+ level = (val - base) / step; -+ -+ if (level < levels) { -+ lquanta[level + 1] += incr; -+ -+ return; -+ } -+ -+ lquanta[levels + 1] += incr; -+} -+ -+static uint64_t dtrace_pow(uint64_t base, uint64_t exp) -+{ -+ uint64_t p, r; -+ -+ p = base; -+ r = 1; -+ while (exp > 0) { -+ if (exp & 1) -+ r *= p; -+ -+ p *= p; -+ exp >>= 1; -+ } -+ -+ return (r); -+} -+ -+void dtrace_aggregate_llquantize(uint64_t *llquanta, uint64_t nval, -+ uint64_t incr) -+{ -+ uint64_t arg = *llquanta++; -+ int factor = DTRACE_LLQUANTIZE_FACTOR(arg); -+ int lmag = DTRACE_LLQUANTIZE_LMAG(arg); -+ int hmag = DTRACE_LLQUANTIZE_HMAG(arg); -+ int steps = DTRACE_LLQUANTIZE_STEPS(arg); -+ int i, signbit, steps_factor, mag, underflow_bin; -+ uint64_t val, bucket_max; -+ -+ ASSERT(steps != 0); -+ ASSERT(factor > 1); -+ -+ if (nval >> (64 - 1)) { -+ signbit = -1; -+ val = 1 + ~nval; -+ } else { -+ signbit = +1; -+ val = nval; -+ } -+ -+ /* -+ * Compute steps/factor. -+ * Notice that while we say there are "steps" bins per logarithmic -+ * range, steps/factor of them actually overlap with lower ranges. -+ * E.g., if factor=10 and steps=20, for mag=2 we have the 20 bins -+ * 0 50 100 150 200 250 300 350 ... 800 850 900 950 -+ * but the first two actually belong to lower ranges. -+ */ -+ steps_factor = steps/factor; -+ -+ /* the underflow bin is in the middle */ -+ underflow_bin = 1 + (hmag-lmag+1) * (steps-steps_factor); -+ -+ bucket_max = dtrace_pow(factor, lmag); -+ -+ /* check for "underflow" (smaller than the smallest bin) */ -+ if (val < bucket_max) { -+ llquanta[underflow_bin] += incr; -+ return; -+ } -+ -+ /* loop over the logarithmic ranges */ -+ i = 0; -+ for (mag = lmag; mag <= hmag; mag++) { -+ bucket_max *= factor; -+ if (val >= bucket_max) -+ continue; -+ -+ /* -+ * We want -+ * i = val * steps / bucket_max; -+ * but val*steps could overflow. An alternative is -+ * i = val / ( bucket_max/steps ) -+ * but bucket_max/steps might not divide evenly. -+ * (Plus, we end up with an extra divide.) -+ * -+ * From Solaris, we inherit constraints on factor and steps -+ * that mean bucket_max/steps divides evenly when mag>0. -+ * Meanwhile, if mag==0, val*steps cannot overflow. -+ * So between our two expressions for i, at least one -+ * will work and we just have to pick which one to use. -+ */ -+ if (mag == 0) -+ i = val * steps / bucket_max; -+ else -+ i = val / (bucket_max/steps); -+ -+ // shift for low indices that can never happen -+ i -= steps_factor; -+ break; -+ } -+ i = underflow_bin+signbit*((steps-steps_factor)*(mag-lmag)+i+1); -+ llquanta[i] += incr; -+} -+ -+void dtrace_aggregate_avg(uint64_t *data, uint64_t nval, uint64_t arg) -+{ -+ data[0]++; -+ data[1] += nval; -+} -+ -+void dtrace_aggregate_stddev(uint64_t *data, uint64_t nval, uint64_t arg) -+{ -+ int64_t snval = (int64_t)nval; -+ uint64_t tmp[2]; -+ -+ data[0]++; -+ data[1] += nval; -+ -+ if (snval < 0) -+ snval = -snval; -+ -+ dtrace_multiply_128((uint64_t)snval, (uint64_t)snval, tmp); -+ dtrace_add_128(data + 2, tmp, data + 2); -+} -+ -+void dtrace_aggregate_count(uint64_t *oval, uint64_t nval, uint64_t arg) -+{ -+ *oval = *oval + 1; -+} -+ -+void dtrace_aggregate_sum(uint64_t *oval, uint64_t nval, uint64_t arg) -+{ -+ *oval += nval; -+} -+ -+/* -+ * DTrace Aggregation Buffers -+ * -+ * Aggregation buffers use much of the same mechanism as described above -+ * ("DTrace Buffers"). However, because an aggregation is fundamentally a -+ * hash, there exists dynamic metadata associated with an aggregation buffer -+ * that is not associated with other kinds of buffers. This aggregation -+ * metadata is _only_ relevant for the in-kernel implementation of -+ * aggregations; it is not actually relevant to user-level consumers. To do -+ * this, we allocate dynamic aggregation data (hash keys and hash buckets) -+ * starting below the _limit_ of the buffer, and we allocate data from the -+ * _base_ of the buffer. When the aggregation buffer is copied out, _only_ the -+ * data is copied out; the metadata is simply discarded. Schematically, -+ * aggregation buffers look like: -+ * -+ * base of data buffer ---> +-------+------+-----------+-------+ -+ * | aggid | key | value | aggid | -+ * +-------+------+-----------+-------+ -+ * | key | -+ * +-------+-------+-----+------------+ -+ * | value | aggid | key | value | -+ * +-------+------++-----+------+-----+ -+ * | aggid | key | value | | -+ * +-------+------+-------------+ | -+ * | || | -+ * | || | -+ * | \/ | -+ * : : -+ * . . -+ * . . -+ * . . -+ * : : -+ * | /\ | -+ * | || +------------+ -+ * | || | | -+ * +---------------------+ | -+ * | hash keys | -+ * | (dtrace_aggkey structures) | -+ * | | -+ * +----------------------------------+ -+ * | hash buckets | -+ * | (dtrace_aggbuffer structure) | -+ * | | -+ * limit of data buffer ---> +----------------------------------+ -+ * -+ * As implied above, just as we assure that ECBs always store a constant -+ * amount of data, we assure that a given aggregation -- identified by its -+ * aggregation ID -- always stores data of a constant quantity and type. -+ * As with EPIDs, this allows the aggregation ID to serve as the metadata for a -+ * given record. -+ * -+ * Note that the size of the dtrace_aggkey structure must be sizeof (uintptr_t) -+ * aligned. (If this the structure changes such that this becomes false, an -+ * assertion will fail in dtrace_aggregate().) -+ */ -+#define DTRACE_AGGHASHSIZE_SLEW 17 -+ -+struct dtrace_aggkey { -+ uint32_t dtak_hashval; /* hash value */ -+ uint32_t dtak_action:4; /* action -- 4 bits */ -+ uint32_t dtak_size:28; /* size -- 28 bits */ -+ caddr_t dtak_data; /* data pointer */ -+ struct dtrace_aggkey *dtak_next; /* next in hash chain */ -+}; -+ -+struct dtrace_aggbuffer { -+ uintptr_t dtagb_hashsize; /* number of buckets */ -+ uintptr_t dtagb_free; /* free list of keys */ -+ struct dtrace_aggkey **dtagb_hash; /* hash table */ -+}; -+ -+#define DTRACEACT_ISSTRING(act) \ -+ ((act)->dta_kind == DTRACEACT_DIFEXPR && \ -+ (act)->dta_difo->dtdo_rtype.dtdt_kind == DIF_TYPE_STRING) -+ -+/* -+ * Aggregate given the tuple in the principal data buffer, and the aggregating -+ * action denoted by the specified dtrace_aggregation_t. The aggregation -+ * buffer is specified as the buf parameter. This routine does not return -+ * failure; if there is no space in the aggregation buffer, the data will be -+ * dropped, and a corresponding counter incremented. -+ */ -+void dtrace_aggregate(struct dtrace_aggregation *agg, -+ struct dtrace_buffer *dbuf, -+ intptr_t offset, struct dtrace_buffer *buf, -+ uint64_t expr, uint64_t arg) -+{ -+ struct dtrace_recdesc *rec = &agg->dtag_action.dta_rec; -+ uint32_t i, ndx, size, fsize; -+ uint32_t align = sizeof(uint64_t) - 1; -+ struct dtrace_aggbuffer *agb; -+ struct dtrace_aggkey *key; -+ uint32_t hashval = 0, limit, isstr; -+ caddr_t tomax, data, kdata; -+ dtrace_actkind_t action; -+ struct dtrace_action *act; -+ uintptr_t offs; -+ -+ if (buf == NULL) -+ return; -+ -+ if (!agg->dtag_hasarg) -+ /* -+ * Currently, only quantize(), lquantize() and llquantize() -+ * take additional arguments, and they have the same semantics: -+ * an increment value that defaults to 1 when not present. If -+ * additional aggregating actions take arguments, the setting -+ * of the default argument value will presumably have to -+ * become more sophisticated... -+ */ -+ arg = 1; -+ -+ action = agg->dtag_action.dta_kind - DTRACEACT_AGGREGATION; -+ size = rec->dtrd_offset - agg->dtag_base; -+ fsize = size + rec->dtrd_size; -+ -+ ASSERT(dbuf->dtb_tomax != NULL); -+ data = dbuf->dtb_tomax + offset + agg->dtag_base; -+ -+ tomax = buf->dtb_tomax; -+ if (tomax == NULL) { -+ dtrace_buffer_drop(buf); -+ return; -+ } -+ -+ /* -+ * The metastructure is always at the bottom of the buffer. -+ */ -+ agb = (struct dtrace_aggbuffer *)(tomax + buf->dtb_size - -+ sizeof(struct dtrace_aggbuffer)); -+ -+ if (buf->dtb_offset == 0) { -+ /* -+ * We just kludge up approximately 1/8th of the size to be -+ * buckets. If this guess ends up being routinely -+ * off-the-mark, we may need to dynamically readjust this -+ * based on past performance. -+ */ -+ uintptr_t hashsize = (buf->dtb_size >> 3) / -+ sizeof(uintptr_t); -+ -+ if ((uintptr_t)agb - hashsize * sizeof(struct dtrace_aggkey *) < -+ (uintptr_t)tomax || hashsize == 0) { -+ /* -+ * We've been given a ludicrously small buffer; -+ * increment our drop count and leave. -+ */ -+ dtrace_buffer_drop(buf); -+ return; -+ } -+ -+ /* -+ * And now, a pathetic attempt to try to get a an odd (or -+ * perchance, a prime) hash size for better hash distribution. -+ */ -+ if (hashsize > (DTRACE_AGGHASHSIZE_SLEW << 3)) -+ hashsize -= DTRACE_AGGHASHSIZE_SLEW; -+ -+ agb->dtagb_hashsize = hashsize; -+ agb->dtagb_hash = (struct dtrace_aggkey **)((uintptr_t)agb - -+ agb->dtagb_hashsize * sizeof(struct dtrace_aggkey *)); -+ agb->dtagb_free = (uintptr_t)agb->dtagb_hash; -+ -+ for (i = 0; i < agb->dtagb_hashsize; i++) -+ agb->dtagb_hash[i] = NULL; -+ } -+ -+ ASSERT(agg->dtag_first != NULL); -+ ASSERT(agg->dtag_first->dta_intuple); -+ -+ /* -+ * Calculate the hash value based on the key. Note that we _don't_ -+ * include the aggid in the hashing (but we will store it as part of -+ * the key). The hashing algorithm is Bob Jenkins' "One-at-a-time" -+ * algorithm: a simple, quick algorithm that has no known funnels, and -+ * gets good distribution in practice. The efficacy of the hashing -+ * algorithm (and a comparison with other algorithms) may be found by -+ * running the ::dtrace_aggstat MDB dcmd. -+ */ -+ for (act = agg->dtag_first; act->dta_intuple; act = act->dta_next) { -+ i = act->dta_rec.dtrd_offset - agg->dtag_base; -+ limit = i + act->dta_rec.dtrd_size; -+ ASSERT(limit <= size); -+ isstr = DTRACEACT_ISSTRING(act); -+ -+ for (; i < limit; i++) { -+ hashval += data[i]; -+ hashval += (hashval << 10); -+ hashval ^= (hashval >> 6); -+ -+ if (isstr && data[i] == '\0') -+ break; -+ } -+ } -+ -+ hashval += (hashval << 3); -+ hashval ^= (hashval >> 11); -+ hashval += (hashval << 15); -+ -+ /* -+ * Yes, the divide here is expensive -- but it's generally the least -+ * of the performance issues given the amount of data that we iterate -+ * over to compute hash values, compare data, etc. -+ */ -+ ndx = hashval % agb->dtagb_hashsize; -+ -+ for (key = agb->dtagb_hash[ndx]; key != NULL; key = key->dtak_next) { -+ ASSERT((caddr_t)key >= tomax); -+ ASSERT((caddr_t)key < tomax + buf->dtb_size); -+ -+ if (hashval != key->dtak_hashval || key->dtak_size != size) -+ continue; -+ -+ kdata = key->dtak_data; -+ ASSERT(kdata >= tomax && kdata < tomax + buf->dtb_size); -+ -+ for (act = agg->dtag_first; act->dta_intuple; -+ act = act->dta_next) { -+ i = act->dta_rec.dtrd_offset - agg->dtag_base; -+ limit = i + act->dta_rec.dtrd_size; -+ ASSERT(limit <= size); -+ isstr = DTRACEACT_ISSTRING(act); -+ -+ for (; i < limit; i++) { -+ if (kdata[i] != data[i]) -+ goto next; -+ -+ if (isstr && data[i] == '\0') -+ break; -+ } -+ } -+ -+ if (action != key->dtak_action) { -+ /* -+ * We are aggregating on the same value in the same -+ * aggregation with two different aggregating actions. -+ * (This should have been picked up in the compiler, -+ * so we may be dealing with errant or devious DIF.) -+ * This is an error condition; we indicate as much, -+ * and return. -+ */ -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); -+ return; -+ } -+ -+ /* -+ * This is a hit: we need to apply the aggregator to -+ * the value at this key. -+ */ -+ dt_dbg_agg(" Aggregate [accum]: Buf %p, offs %d, act %d, " -+ "%lld (%lld, %lld)\n", -+ buf, size, -+ agg->dtag_action.dta_kind - DTRACEACT_AGGREGATION, -+ *(uint64_t *)(kdata + size), expr, arg); -+ agg->dtag_aggregate((uint64_t *)(kdata + size), expr, arg); -+ return; -+next: -+ continue; -+ } -+ -+ /* -+ * We didn't find it. We need to allocate some zero-filled space, -+ * link it into the hash table appropriately, and apply the aggregator -+ * to the (zero-filled) value. -+ */ -+ offs = buf->dtb_offset; -+ while (offs & (align - 1)) -+ offs += sizeof(uint32_t); -+ -+ /* -+ * If we don't have enough room to both allocate a new key _and_ -+ * its associated data, increment the drop count and return. -+ */ -+ if ((uintptr_t)tomax + offs + fsize > -+ agb->dtagb_free - sizeof(struct dtrace_aggkey)) { -+ dtrace_buffer_drop(buf); -+ return; -+ } -+ -+ ASSERT(!(sizeof(struct dtrace_aggkey) & (sizeof(uintptr_t) - 1))); -+ key = (struct dtrace_aggkey *) -+ (agb->dtagb_free - sizeof(struct dtrace_aggkey)); -+ agb->dtagb_free -= sizeof(struct dtrace_aggkey); -+ -+ key->dtak_data = kdata = tomax + offs; -+ buf->dtb_offset = offs + fsize; -+ -+ /* -+ * Now copy the data across. -+ */ -+ *((dtrace_aggid_t *)kdata) = agg->dtag_id; -+ -+ for (i = sizeof(dtrace_aggid_t); i < size; i++) -+ kdata[i] = data[i]; -+ -+ /* -+ * Because strings are not zeroed out by default, we need to iterate -+ * looking for actions that store strings, and we need to explicitly -+ * pad these strings out with zeroes. -+ */ -+ for (act = agg->dtag_first; act->dta_intuple; act = act->dta_next) { -+ int nul; -+ -+ if (!DTRACEACT_ISSTRING(act)) -+ continue; -+ -+ i = act->dta_rec.dtrd_offset - agg->dtag_base; -+ limit = i + act->dta_rec.dtrd_size; -+ ASSERT(limit <= size); -+ -+ for (nul = 0; i < limit; i++) { -+ if (nul) { -+ kdata[i] = '\0'; -+ continue; -+ } -+ -+ if (data[i] != '\0') -+ continue; -+ -+ nul = 1; -+ } -+ } -+ -+ for (i = size; i < fsize; i++) -+ kdata[i] = 0; -+ -+ key->dtak_hashval = hashval; -+ key->dtak_size = size; -+ key->dtak_action = action; -+ key->dtak_next = agb->dtagb_hash[ndx]; -+ agb->dtagb_hash[ndx] = key; -+ -+ /* -+ * Finally, apply the aggregator. -+ */ -+ *((uint64_t *)(key->dtak_data + size)) = agg->dtag_initial; -+ dt_dbg_agg(" Aggregate [initial]: Buf %p, offs %d, act %d, " -+ "%lld (%lld, %lld)\n", -+ buf, size, -+ agg->dtag_action.dta_kind - DTRACEACT_AGGREGATION, -+ *(uint64_t *)(key->dtak_data + size), expr, arg); -+ agg->dtag_aggregate((uint64_t *)(key->dtak_data + size), expr, arg); -+} -diff --git a/dtrace/dtrace_ptofapi.c b/dtrace/dtrace_ptofapi.c -new file mode 100644 -index 0000000000000000000000000000000000000000..c42a8471879cc0ea532ad19adf9ea66b20c9183e ---- /dev/null -+++ b/dtrace/dtrace_ptofapi.c -@@ -0,0 +1,649 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_ptofapi.c -+ * DESCRIPTION: DTrace - (meta) provider-to-framework API -+ * -+ * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/idr.h> -+#include <linux/list.h> -+#include <linux/module.h> -+#include <linux/slab.h> -+ -+#include "dtrace.h" -+ -+struct dtrace_provider *dtrace_provider; -+struct dtrace_meta *dtrace_meta_pid; -+struct dtrace_helpers *dtrace_deferred_pid; -+ -+DEFINE_MUTEX(dtrace_provider_lock); -+DEFINE_MUTEX(dtrace_meta_lock); -+ -+/* -+ * Register the calling provider with the DTrace core. This should generally -+ * be called by providers during module initialization. -+ */ -+int dtrace_register(const char *name, const struct dtrace_pattr *pap, -+ uint32_t priv, const struct cred *cr, -+ const struct dtrace_pops *pops, void *arg, -+ dtrace_provider_id_t *idp) -+{ -+ struct dtrace_provider *provider; -+ -+ if (name == NULL || pap == NULL || pops == NULL || idp == NULL) { -+ pr_warn("Failed to register provider %s: invalid args\n", -+ name ? name : "<NULL>"); -+ return -EINVAL; -+ } -+ -+ if (name[0] == '\0' || dtrace_badname(name)) { -+ pr_warn("Failed to register provider %s: invalid name\n", -+ name); -+ return -EINVAL; -+ } -+ -+ if ((pops->dtps_provide == NULL && pops->dtps_provide_module == NULL) || -+ pops->dtps_enable == NULL || pops->dtps_disable == NULL || -+ pops->dtps_destroy == NULL || -+ ((pops->dtps_resume == NULL) != (pops->dtps_suspend == NULL))) { -+ pr_warn("Failed to register provider %s: invalid ops\n", -+ name); -+ return -EINVAL; -+ } -+ -+ if (dtrace_badattr(&pap->dtpa_provider) || -+ dtrace_badattr(&pap->dtpa_mod) || -+ dtrace_badattr(&pap->dtpa_func) || -+ dtrace_badattr(&pap->dtpa_name) || -+ dtrace_badattr(&pap->dtpa_args)) { -+ pr_warn("Failed to register provider %s: invalid attributes\n", -+ name); -+ return -EINVAL; -+ } -+ -+ if (priv & ~DTRACE_PRIV_ALL) { -+ pr_warn("Failed to register provider %s: invalid privilege " -+ "attributes\n", name); -+ return -EINVAL; -+ } -+ -+ if ((priv & DTRACE_PRIV_KERNEL) && -+ (priv & (DTRACE_PRIV_USER | DTRACE_PRIV_OWNER)) && -+ pops->dtps_usermode == NULL) { -+ pr_warn("Failed to register provider %s: need " -+ "dtps_usermode() op for given privilege " -+ "attributes\n", name); -+ return -EINVAL; -+ } -+ -+ dt_dbg_prov("Registering provider '%s'...\n", name); -+ provider = kzalloc(sizeof(struct dtrace_provider), GFP_KERNEL); -+ if (provider == NULL) { -+ dt_dbg_prov(" Failed to allocate provider struct\n"); -+ return -ENOMEM; -+ } -+ provider->dtpv_name = dtrace_strdup(name); -+ if (provider->dtpv_name == NULL) { -+ kfree(provider); -+ dt_dbg_prov(" Failed to allocate provider name\n"); -+ return -ENOMEM; -+ } -+ provider->dtpv_attr = *pap; -+ provider->dtpv_priv.dtpp_flags = priv; -+ -+ if (cr != NULL) { -+ provider->dtpv_priv.dtpp_uid = -+ from_kuid(init_user_namespace, get_cred(cr)->uid); -+ put_cred(cr); -+ } -+ -+ provider->dtpv_pops = *pops; -+ -+ if (pops->dtps_provide == NULL) { -+ ASSERT(pops->dtps_provide_module != NULL); -+ provider->dtpv_pops.dtps_provide = -+ (void (*)(void *, const struct dtrace_probedesc *)) -+ dtrace_nullop; -+ } -+ -+ if (pops->dtps_provide_module == NULL) { -+ ASSERT(pops->dtps_provide != NULL); -+ provider->dtpv_pops.dtps_provide_module = -+ (void (*)(void *, struct module *))dtrace_nullop; -+ } -+ -+ if (pops->dtps_destroy_module == NULL) { -+ provider->dtpv_pops.dtps_destroy_module = -+ (void (*)(void *, struct module *))dtrace_nullop; -+ } -+ -+ if (pops->dtps_suspend == NULL) { -+ ASSERT(pops->dtps_resume == NULL); -+ provider->dtpv_pops.dtps_suspend = -+ (void (*)(void *, dtrace_id_t, void *))dtrace_nullop; -+ provider->dtpv_pops.dtps_resume = -+ (void (*)(void *, dtrace_id_t, void *))dtrace_nullop; -+ } -+ -+ provider->dtpv_arg = arg; -+ *idp = (dtrace_provider_id_t)provider; -+ -+ if (pops == &dtrace_provider_ops) { -+ ASSERT(MUTEX_HELD(&dtrace_provider_lock)); -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ ASSERT(dtrace_anon.dta_enabling == NULL); -+ -+ /* -+ * The DTrace provider must be at the head of the provider -+ * chain. -+ */ -+ provider->dtpv_next = dtrace_provider; -+ dtrace_provider = provider; -+ -+ dt_dbg_prov(" Done registering %s\n", name); -+ -+ return 0; -+ } -+ -+ mutex_lock(&module_mutex); -+ mutex_lock(&dtrace_provider_lock); -+ mutex_lock(&dtrace_lock); -+ -+ /* -+ * If there is at least one provider registered, we'll add this new one -+ * after the first provider. -+ */ -+ if (dtrace_provider != NULL) { -+ provider->dtpv_next = dtrace_provider->dtpv_next; -+ dtrace_provider->dtpv_next = provider; -+ } else -+ dtrace_provider = provider; -+ -+ if (dtrace_retained != NULL) { -+ dt_dbg_prov(" Processing retained enablings for %s\n", name); -+ dtrace_enabling_provide(provider); -+ -+ /* -+ * We must now call dtrace_enabling_matchall() which needs to -+ * acquire cpu_lock and dtrace_lock. We therefore need to drop -+ * our locks before calling it. -+ */ -+ mutex_unlock(&dtrace_lock); -+ mutex_unlock(&dtrace_provider_lock); -+ mutex_unlock(&module_mutex); -+ dtrace_enabling_matchall(); -+ -+ dt_dbg_prov(" Done registering %s\n", name); -+ -+ return 0; -+ } -+ -+ mutex_unlock(&dtrace_lock); -+ mutex_unlock(&dtrace_provider_lock); -+ mutex_unlock(&module_mutex); -+ -+ dt_dbg_prov(" Done registering %s\n", name); -+ -+ return 0; -+} -+EXPORT_SYMBOL(dtrace_register); -+ -+struct unreg_state { -+ struct dtrace_provider *prov; -+ struct dtrace_probe *first; -+}; -+ -+/* -+ * Check whether the given probe is still enabled for the given provider. -+ */ -+static int dtrace_unregister_check(int id, void *p, void *data) -+{ -+ struct dtrace_probe *probe = (struct dtrace_probe *)p; -+ struct unreg_state *st = (struct unreg_state *)data; -+ -+ if (probe->dtpr_provider != st->prov) -+ return 0; -+ -+ if (probe->dtpr_ecb == NULL) -+ return 0; -+ -+ return -EBUSY; -+} -+ -+/* -+ * Remove the given probe from the hash tables and the probe IDR, if it is -+ * associated with the given provider. The probes are chained for further -+ * processing. -+ */ -+static int dtrace_unregister_probe(int id, void *p, void *data) -+{ -+ struct dtrace_probe *probe = (struct dtrace_probe *)p; -+ struct unreg_state *st = (struct unreg_state *)data; -+ -+ if (probe->dtpr_provider != st->prov) -+ return 0; -+ -+ dtrace_hash_remove(dtrace_bymod, probe); -+ dtrace_hash_remove(dtrace_byfunc, probe); -+ dtrace_hash_remove(dtrace_byname, probe); -+ -+ if (st->first == NULL) { -+ st->first = probe; -+ probe->dtpr_nextmod = NULL; -+ } else { -+ probe->dtpr_nextmod = st->first; -+ st->first = probe; -+ } -+ -+ return 0; -+} -+ -+/* -+ * Remove the given probe from the hash tables and the probe IDR, if it is -+ * associated with the given provider and if it does not have any enablings. -+ * The probes are chained for further processing. -+ */ -+static int dtrace_condense_probe(int id, void *p, void *data) -+{ -+ struct dtrace_probe *probe = (struct dtrace_probe *)p; -+ struct unreg_state *st = (struct unreg_state *)data; -+ -+ if (probe->dtpr_provider != st->prov) -+ return 0; -+ -+ if (probe->dtpr_ecb == NULL) -+ return 0; -+ -+ dtrace_hash_remove(dtrace_bymod, probe); -+ dtrace_hash_remove(dtrace_byfunc, probe); -+ dtrace_hash_remove(dtrace_byname, probe); -+ -+ if (st->first == NULL) { -+ st->first = probe; -+ probe->dtpr_nextmod = NULL; -+ } else { -+ probe->dtpr_nextmod = st->first; -+ st->first = probe; -+ } -+ -+ return 0; -+} -+ -+/* -+ * Unregister the specified provider from the DTrace core. This should be -+ * called by provider during module cleanup. -+ * -+ * The mutex_lock is already held during this call. -+ */ -+int dtrace_unregister(dtrace_provider_id_t id) -+{ -+ struct dtrace_provider *old = (struct dtrace_provider *)id; -+ struct dtrace_provider *prev = NULL; -+ int err, self = 0; -+ struct dtrace_probe *probe; -+ struct unreg_state st = { old, NULL }; -+ -+ ASSERT(MUTEX_HELD(&module_mutex)); -+ -+ dt_dbg_prov("Unregistering provider '%s'...\n", old->dtpv_name); -+ -+ if (old->dtpv_pops.dtps_enable == -+ (int (*)(void *, dtrace_id_t, void *))dtrace_enable_nullop) { -+ /* -+ * When the provider is the DTrace core itself, we're called -+ * with locks already held. -+ */ -+ ASSERT(old == dtrace_provider); -+ ASSERT(MUTEX_HELD(&dtrace_provider_lock)); -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ -+ self = 1; -+ -+ if (dtrace_provider->dtpv_next != NULL) { -+ /* -+ * We cannot and should not remove the DTrace provider -+ * if there is any other provider left. -+ */ -+ dt_dbg_prov(" Failed to unregister %s - not last\n", -+ old->dtpv_name); -+ -+ return -EBUSY; -+ } -+ } else { -+ mutex_lock(&dtrace_provider_lock); -+ mutex_lock(&dtrace_lock); -+ } -+ -+ /* -+ * If /dev/dtrace/dtrace is still held open by a process, or if there -+ * are anonymous probes that are still enabled, we refuse to deregister -+ * providers, unless the provider has been invalidated explicitly. -+ */ -+ if (!old->dtpv_defunct && -+ (dtrace_opens || (dtrace_anon.dta_state != NULL && -+ dtrace_anon.dta_state->dts_necbs > 0))) { -+ if (!self) { -+ mutex_unlock(&dtrace_lock); -+ mutex_unlock(&dtrace_provider_lock); -+ } -+ -+ dt_dbg_prov(" Failed to unregister %s - dtrace in use\n", -+ old->dtpv_name); -+ -+ return -EBUSY; -+ } -+ -+ /* -+ * Check whether any of the probes associated with this provider are -+ * still enabled (having at least one ECB). If any are found, we -+ * cannot remove this provider. -+ */ -+ st.prov = old; -+ err = dtrace_probe_for_each(dtrace_unregister_check, &st); -+ if (err < 0) { -+ if (!self) { -+ mutex_unlock(&dtrace_lock); -+ mutex_unlock(&dtrace_provider_lock); -+ } -+ -+ dt_dbg_prov(" Failed to unregister %s - provider in use\n", -+ old->dtpv_name); -+ -+ return err; -+ } -+ -+ /* -+ * All the probes associated with this provider are disabled. We can -+ * safely remove these probes from the hashtables and the probe array. -+ * We chain all the probes together for further processing. -+ */ -+ dtrace_probe_for_each(dtrace_unregister_probe, &st); -+ -+ /* -+ * The probes associated with the provider have been removed. Ensure -+ * synchronization on probe IDR processing. -+ */ -+ dtrace_sync(); -+ -+ /* -+ * Now get rid of the actual probes. -+ */ -+ for (probe = st.first; probe != NULL; probe = st.first) { -+ int probe_id = probe->dtpr_id; -+ -+ st.first = probe->dtpr_nextmod; -+ -+ old->dtpv_pops.dtps_destroy(old->dtpv_arg, probe_id, -+ probe->dtpr_arg); -+ -+ kfree(probe->dtpr_mod); -+ kfree(probe->dtpr_func); -+ kfree(probe->dtpr_name); -+ kmem_cache_free(dtrace_probe_cachep, probe); -+ -+ dtrace_probe_remove_id(probe_id); -+ } -+ -+ prev = dtrace_provider; -+ if (prev == old) { -+ /* -+ * We are removing the provider at the head of the chain. -+ */ -+ ASSERT(self); -+ ASSERT(old->dtpv_next == NULL); -+ -+ dtrace_provider = old->dtpv_next; -+ } else { -+ while (prev != NULL && prev->dtpv_next != old) -+ prev = prev->dtpv_next; -+ -+ if (prev == NULL) { -+ pr_err("Attempt to unregister non-existent DTrace " -+ "provider %p\n", (void *)id); -+ BUG(); -+ } -+ -+ prev->dtpv_next = old->dtpv_next; -+ } -+ -+ if (!self) { -+ mutex_unlock(&dtrace_lock); -+ mutex_unlock(&dtrace_provider_lock); -+ } -+ -+ kfree(old->dtpv_name); -+ kfree(old); -+ -+ dt_dbg_prov(" Done unregistering\n"); -+ -+ return 0; -+} -+EXPORT_SYMBOL(dtrace_unregister); -+ -+/* -+ * Invalidate the specified provider. All subsequent probe lookups for the -+ * specified provider will fail, but the probes will not be removed. -+ */ -+void dtrace_invalidate(dtrace_provider_id_t id) -+{ -+ struct dtrace_provider *pvp = (struct dtrace_provider *)id; -+ -+ ASSERT(pvp->dtpv_pops.dtps_enable != -+ (int (*)(void *, dtrace_id_t, void *))dtrace_enable_nullop); -+ -+ mutex_lock(&dtrace_provider_lock); -+ mutex_lock(&dtrace_lock); -+ -+ pvp->dtpv_defunct = 1; -+ -+ mutex_unlock(&dtrace_lock); -+ mutex_unlock(&dtrace_provider_lock); -+} -+EXPORT_SYMBOL(dtrace_invalidate); -+ -+/* -+ * Indicate whether or not DTrace has attached. -+ */ -+int dtrace_attached(void) -+{ -+ /* -+ * dtrace_provider will be non-NULL iff the DTrace driver has -+ * attached. (It's non-NULL because DTrace is always itself a -+ * provider.) -+ */ -+ return dtrace_provider != NULL; -+} -+EXPORT_SYMBOL(dtrace_attached); -+ -+/* -+ * Remove all the unenabled probes for the given provider. This function is -+ * not unlike dtrace_unregister(), except that it doesn't remove the provider -+ * -- just as many of its associated probes as it can. -+ */ -+int dtrace_condense(dtrace_provider_id_t id) -+{ -+ struct dtrace_provider *prov = (struct dtrace_provider *)id; -+ struct dtrace_probe *probe; -+ struct unreg_state st = { prov, NULL }; -+ -+ /* -+ * Make sure this isn't the DTrace provider itself. -+ */ -+ ASSERT(prov->dtpv_pops.dtps_enable != -+ (int (*)(void *, dtrace_id_t, void *))dtrace_enable_nullop); -+ -+ mutex_lock(&dtrace_provider_lock); -+ mutex_lock(&dtrace_lock); -+ -+ /* -+ * Attempt to destroy the probes associated with this provider. -+ */ -+ dtrace_probe_for_each(dtrace_condense_probe, &st); -+ -+ /* -+ * The probes associated with the provider have been removed. Ensure -+ * synchronization on probe IDR processing. -+ */ -+ dtrace_sync(); -+ -+ /* -+ * Now get rid of the actual probes. -+ */ -+ for (probe = st.first; probe != NULL; probe = st.first) { -+ int probe_id = probe->dtpr_id; -+ -+ st.first = probe->dtpr_nextmod; -+ -+ prov->dtpv_pops.dtps_destroy(prov->dtpv_arg, probe_id, -+ probe->dtpr_arg); -+ -+ kfree(probe->dtpr_mod); -+ kfree(probe->dtpr_func); -+ kfree(probe->dtpr_name); -+ kfree(probe); -+ -+ dtrace_probe_remove_id(probe_id); -+ } -+ -+ mutex_unlock(&dtrace_lock); -+ mutex_unlock(&dtrace_provider_lock); -+ -+ return 0; -+} -+EXPORT_SYMBOL(dtrace_condense); -+ -+int dtrace_meta_register(const char *name, const struct dtrace_mops *mops, -+ void *arg, dtrace_meta_provider_id_t *idp) -+{ -+ struct dtrace_meta *meta; -+ struct dtrace_helpers *help, *next; -+ int i; -+ -+ *idp = DTRACE_METAPROVNONE; -+ -+ /* -+ * We strictly don't need the name, but we hold onto it for -+ * debuggability. All hail error queues! -+ */ -+ if (name == NULL) { -+ pr_warn("failed to register meta-provider: invalid name\n"); -+ return -EINVAL; -+ } -+ -+ if (mops == NULL || -+ mops->dtms_create_probe == NULL || -+ mops->dtms_provide_pid == NULL || -+ mops->dtms_remove_pid == NULL) { -+ pr_warn("failed to register meta-register %s: invalid ops\n", -+ name); -+ return -EINVAL; -+ } -+ -+ dt_dbg_prov("Registering provider '%s'...\n", name); -+ meta = kzalloc(sizeof(struct dtrace_meta), GFP_KERNEL); -+ if (meta == NULL) { -+ dt_dbg_prov(" Failed to allocate meta provider struct\n"); -+ return -ENOMEM; -+ } -+ meta->dtm_mops = *mops; -+ meta->dtm_name = kmalloc(strlen(name) + 1, GFP_KERNEL); -+ if (meta->dtm_name == NULL) { -+ kfree(meta); -+ dt_dbg_prov(" Failed to allocate meta provider name\n"); -+ return -ENOMEM; -+ } -+ strcpy(meta->dtm_name, name); -+ meta->dtm_arg = arg; -+ -+ mutex_lock(&dtrace_meta_lock); -+ mutex_lock(&dtrace_lock); -+ -+ if (dtrace_meta_pid != NULL) { -+ mutex_unlock(&dtrace_lock); -+ mutex_unlock(&dtrace_meta_lock); -+ pr_warn("failed to register meta-register %s: user-land " -+ "meta-provider exists", name); -+ kfree(meta->dtm_name); -+ kfree(meta); -+ return -EINVAL; -+ } -+ -+ dtrace_meta_pid = meta; -+ *idp = (dtrace_meta_provider_id_t)meta; -+ -+ /* -+ * If there are providers and probes ready to go, pass them -+ * off to the new meta provider now. -+ */ -+ help = dtrace_deferred_pid; -+ dtrace_deferred_pid = NULL; -+ -+ mutex_unlock(&dtrace_lock); -+ -+ while (help != NULL) { -+ for (i = 0; i < help->dthps_nprovs; i++) { -+ dtrace_helper_provide(&help->dthps_provs[i]->dthp_prov, -+ help->dthps_pid); -+ } -+ -+ next = help->dthps_next; -+ help->dthps_next = NULL; -+ help->dthps_prev = NULL; -+ help->dthps_deferred = 0; -+ help = next; -+ } -+ -+ mutex_unlock(&dtrace_meta_lock); -+ -+ dt_dbg_prov(" Done registering %s\n", name); -+ -+ return 0; -+} -+EXPORT_SYMBOL(dtrace_meta_register); -+ -+int dtrace_meta_unregister(dtrace_meta_provider_id_t id) -+{ -+ struct dtrace_meta **pp, *old = (struct dtrace_meta *)id; -+ -+ dt_dbg_prov("Unregistering meta provider '%s'...\n", old->dtm_name); -+ mutex_lock(&dtrace_meta_lock); -+ mutex_lock(&dtrace_lock); -+ -+ if (old == dtrace_meta_pid) { -+ pp = &dtrace_meta_pid; -+ } else { -+ pr_err("Attempt to unregister non-existent DTrace meta-" -+ "provider %p\n", (void *)old); -+ BUG(); -+ } -+ -+ if (old->dtm_count != 0) { -+ mutex_unlock(&dtrace_lock); -+ mutex_unlock(&dtrace_meta_lock); -+ return -EBUSY; -+ } -+ -+ *pp = NULL; -+ -+ mutex_unlock(&dtrace_lock); -+ mutex_unlock(&dtrace_meta_lock); -+ -+ kfree(old->dtm_name); -+ kfree(old); -+ -+ dt_dbg_prov(" Done unregistering\n"); -+ -+ return 0; -+} -+EXPORT_SYMBOL(dtrace_meta_unregister); -diff --git a/dtrace/dtrace_spec.c b/dtrace/dtrace_spec.c -new file mode 100644 -index 0000000000000000000000000000000000000000..4ca9bb7a6427468d8a1fcf5d5b3aec00107200ac ---- /dev/null -+++ b/dtrace/dtrace_spec.c -@@ -0,0 +1,434 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_spec.c -+ * DESCRIPTION: DTrace - speculation implementation -+ * -+ * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/dtrace_cpu.h> -+#include <linux/smp.h> -+#include <asm/cmpxchg.h> -+ -+#include "dtrace.h" -+ -+/* -+ * Given consumer state, this routine finds a speculation in the INACTIVE -+ * state and transitions it into the ACTIVE state. If there is no speculation -+ * in the INACTIVE state, 0 is returned. In this case, no error counter is -+ * incremented -- it is up to the caller to take appropriate action. -+ */ -+int dtrace_speculation(struct dtrace_state *state) -+{ -+ int i = 0; -+ uint32_t count, *stat = &state->dts_speculations_unavail; -+ enum dtrace_speculation_state curr; -+ -+ while (i < state->dts_nspeculations) { -+ struct dtrace_speculation *spec = &state->dts_speculations[i]; -+ -+ curr = spec->dtsp_state; -+ -+ if (curr != DTRACESPEC_INACTIVE) { -+ if (curr == DTRACESPEC_COMMITTINGMANY || -+ curr == DTRACESPEC_COMMITTING || -+ curr == DTRACESPEC_DISCARDING) -+ stat = &state->dts_speculations_busy; -+ -+ i++; -+ continue; -+ } -+ -+ if (cmpxchg((uint32_t *)&spec->dtsp_state, curr, -+ DTRACESPEC_ACTIVE) == curr) -+ return i + 1; -+ } -+ -+ /* -+ * We couldn't find a speculation. If we found as much as a single -+ * busy speculation buffer, we'll attribute this failure as "busy" -+ * instead of "unavail". -+ */ -+ do { -+ count = *stat; -+ } while (cmpxchg(stat, count, count + 1) != count); -+ -+ return 0; -+} -+ -+/* -+ * This routine commits an active speculation. If the specified speculation -+ * is not in a valid state to perform a commit(), this routine will silently do -+ * nothing. The state of the specified speculation is transitioned according -+ * to the state transition diagram outlined in <sys/dtrace_impl.h> -+ */ -+void dtrace_speculation_commit(struct dtrace_state *state, processorid_t cpu, -+ dtrace_specid_t which) -+{ -+ struct dtrace_speculation *spec; -+ struct dtrace_buffer *src, *dest; -+ uintptr_t daddr, saddr, dlimit; -+ enum dtrace_speculation_state curr, new = 0; -+ intptr_t offs; -+ -+ if (which == 0) -+ return; -+ -+ if (which > state->dts_nspeculations) { -+ per_cpu_core(cpu)->cpuc_dtrace_flags |= CPU_DTRACE_ILLOP; -+ return; -+ } -+ -+ spec = &state->dts_speculations[which - 1]; -+ src = &spec->dtsp_buffer[cpu]; -+ dest = &state->dts_buffer[cpu]; -+ -+ do { -+ curr = spec->dtsp_state; -+ -+ if (curr == DTRACESPEC_COMMITTINGMANY) -+ break; -+ -+ switch (curr) { -+ case DTRACESPEC_INACTIVE: -+ case DTRACESPEC_DISCARDING: -+ return; -+ -+ case DTRACESPEC_COMMITTING: -+ /* -+ * This is only possible if we are (a) commit()'ing -+ * without having done a prior speculate() on this CPU -+ * and (b) racing with another commit() on a different -+ * CPU. There's nothing to do -- we just assert that -+ * our offset is 0. -+ */ -+ ASSERT(src->dtb_offset == 0); -+ return; -+ -+ case DTRACESPEC_ACTIVE: -+ new = DTRACESPEC_COMMITTING; -+ break; -+ -+ case DTRACESPEC_ACTIVEONE: -+ /* -+ * This speculation is active on one CPU. If our -+ * buffer offset is non-zero, we know that the one CPU -+ * must be us. Otherwise, we are committing on a -+ * different CPU from the speculate(), and we must -+ * rely on being asynchronously cleaned. -+ */ -+ if (src->dtb_offset != 0) { -+ new = DTRACESPEC_COMMITTING; -+ break; -+ } -+ /*FALLTHROUGH*/ -+ -+ case DTRACESPEC_ACTIVEMANY: -+ new = DTRACESPEC_COMMITTINGMANY; -+ break; -+ -+ default: -+ ASSERT(0); -+ } -+ } while (cmpxchg((uint32_t *)&spec->dtsp_state, curr, new) != -+ curr); -+ -+ /* -+ * We have set the state to indicate that we are committing this -+ * speculation. Now reserve the necessary space in the destination -+ * buffer. -+ */ -+ offs = dtrace_buffer_reserve(dest, src->dtb_offset, sizeof(uint64_t), -+ state, NULL); -+ if (offs < 0) { -+ dtrace_buffer_drop(dest); -+ goto out; -+ } -+ -+ /* -+ * We have the space; copy the buffer across. (Note that this is a -+ * highly subobtimal bcopy(); in the unlikely event that this becomes -+ * a serious performance issue, a high-performance DTrace-specific -+ * bcopy() should obviously be invented.) -+ */ -+ daddr = (uintptr_t)dest->dtb_tomax + offs; -+ dlimit = daddr + src->dtb_offset; -+ saddr = (uintptr_t)src->dtb_tomax; -+ -+ /* -+ * First, the aligned portion. -+ */ -+ while (dlimit - daddr >= sizeof(uint64_t)) { -+ *((uint64_t *)daddr) = *((uint64_t *)saddr); -+ *((uint64_t *)daddr) = *((uint64_t *)saddr); -+ -+ daddr += sizeof(uint64_t); -+ saddr += sizeof(uint64_t); -+ } -+ -+ /* -+ * Now any left-over bit... -+ */ -+ while (dlimit - daddr) -+ *((uint8_t *)daddr++) = *((uint8_t *)saddr++); -+ -+ /* -+ * Finally, commit the reserved space in the destination buffer. -+ */ -+ dest->dtb_offset = offs + src->dtb_offset; -+ -+out: -+ /* -+ * If we're lucky enough to be the only active CPU on this speculation -+ * buffer, we can just set the state back to DTRACESPEC_INACTIVE. -+ */ -+ if (curr == DTRACESPEC_ACTIVE || -+ (curr == DTRACESPEC_ACTIVEONE && new == DTRACESPEC_COMMITTING)) { -+ /* -+ * Will cause unused warning if DEBUG is not defined. -+ */ -+ uint32_t rval = -+ cmpxchg((uint32_t *)&spec->dtsp_state, -+ DTRACESPEC_COMMITTING, -+ DTRACESPEC_INACTIVE); -+ -+ ASSERT(rval == DTRACESPEC_COMMITTING); -+ rval = 0; /* Avoid warning about unused variable if !DEBUG */ -+ } -+ -+ src->dtb_offset = 0; -+ src->dtb_xamot_drops += src->dtb_drops; -+ src->dtb_drops = 0; -+} -+ -+/* -+ * This routine discards an active speculation. If the specified speculation -+ * is not in a valid state to perform a discard(), this routine will silently -+ * do nothing. The state of the specified speculation is transitioned -+ * according to the state transition diagram outlined in <sys/dtrace_impl.h> -+ */ -+void dtrace_speculation_discard(struct dtrace_state *state, processorid_t cpu, -+ dtrace_specid_t which) -+{ -+ struct dtrace_speculation *spec; -+ enum dtrace_speculation_state curr, new = 0; -+ struct dtrace_buffer *buf; -+ -+ if (which == 0) -+ return; -+ -+ if (which > state->dts_nspeculations) { -+ per_cpu_core(cpu)->cpuc_dtrace_flags |= CPU_DTRACE_ILLOP; -+ return; -+ } -+ -+ spec = &state->dts_speculations[which - 1]; -+ buf = &spec->dtsp_buffer[cpu]; -+ -+ do { -+ curr = spec->dtsp_state; -+ -+ switch (curr) { -+ case DTRACESPEC_INACTIVE: -+ case DTRACESPEC_COMMITTINGMANY: -+ case DTRACESPEC_COMMITTING: -+ case DTRACESPEC_DISCARDING: -+ return; -+ -+ case DTRACESPEC_ACTIVE: -+ case DTRACESPEC_ACTIVEMANY: -+ new = DTRACESPEC_DISCARDING; -+ break; -+ -+ case DTRACESPEC_ACTIVEONE: -+ if (buf->dtb_offset != 0) -+ new = DTRACESPEC_INACTIVE; -+ else -+ new = DTRACESPEC_DISCARDING; -+ -+ break; -+ -+ default: -+ ASSERT(0); -+ } -+ } while (cmpxchg((uint32_t *)&spec->dtsp_state, curr, new) != curr); -+ -+ buf->dtb_offset = 0; -+ buf->dtb_drops = 0; -+} -+ -+/* -+ * Note: not called from probe context. This function is called -+ * asynchronously from cross call context to clean any speculations that are -+ * in the COMMITTINGMANY or DISCARDING states. These speculations may not be -+ * transitioned back to the INACTIVE state until all CPUs have cleaned the -+ * speculation. -+ */ -+void dtrace_speculation_clean_here(struct dtrace_state *state) -+{ -+ dtrace_icookie_t cookie; -+ processorid_t cpu = smp_processor_id(); -+ struct dtrace_buffer *dest = &state->dts_buffer[cpu]; -+ dtrace_specid_t i; -+ uint32_t re_entry; -+ -+ DTRACE_SYNC_ENTER_CRITICAL(cookie, re_entry); -+ -+ if (dest->dtb_tomax == NULL) { -+ DTRACE_SYNC_EXIT_CRITICAL(cookie, re_entry); -+ return; -+ } -+ -+ for (i = 0; i < state->dts_nspeculations; i++) { -+ struct dtrace_speculation *spec = &state->dts_speculations[i]; -+ struct dtrace_buffer *src = &spec->dtsp_buffer[cpu]; -+ -+ if (src->dtb_tomax == NULL) -+ continue; -+ -+ if (spec->dtsp_state == DTRACESPEC_DISCARDING) { -+ src->dtb_offset = 0; -+ continue; -+ } -+ -+ if (spec->dtsp_state != DTRACESPEC_COMMITTINGMANY) -+ continue; -+ -+ if (src->dtb_offset == 0) -+ continue; -+ -+ dtrace_speculation_commit(state, cpu, i + 1); -+ } -+ -+ DTRACE_SYNC_EXIT_CRITICAL(cookie, re_entry); -+} -+ -+void dtrace_speculation_clean(struct dtrace_state *state) -+{ -+ int work = 0, rv; -+ dtrace_specid_t i; -+ -+ for (i = 0; i < state->dts_nspeculations; i++) { -+ struct dtrace_speculation *spec = &state->dts_speculations[i]; -+ -+ ASSERT(!spec->dtsp_cleaning); -+ -+ if (spec->dtsp_state != DTRACESPEC_DISCARDING && -+ spec->dtsp_state != DTRACESPEC_COMMITTINGMANY) -+ continue; -+ -+ work++; -+ spec->dtsp_cleaning = 1; -+ } -+ -+ if (!work) -+ return; -+ -+ dtrace_xcall(DTRACE_CPUALL, -+ (dtrace_xcall_t)dtrace_speculation_clean_here, state); -+ -+ /* -+ * We now know that all CPUs have committed or discarded their -+ * speculation buffers, as appropriate. We can now set the state -+ * to inactive. -+ */ -+ for (i = 0; i < state->dts_nspeculations; i++) { -+ struct dtrace_speculation *spec = -+ &state->dts_speculations[i]; -+ enum dtrace_speculation_state curr, new; -+ -+ if (!spec->dtsp_cleaning) -+ continue; -+ -+ curr = spec->dtsp_state; -+ ASSERT(curr == DTRACESPEC_DISCARDING || -+ curr == DTRACESPEC_COMMITTINGMANY); -+ -+ new = DTRACESPEC_INACTIVE; -+ -+ rv = cmpxchg((uint32_t *)&spec->dtsp_state, curr, new); -+ ASSERT(rv == curr); -+ spec->dtsp_cleaning = 0; -+ } -+} -+ -+/* -+ * Called as part of a speculate() to get the speculative buffer associated -+ * with a given speculation. Returns NULL if the specified speculation is not -+ * in an ACTIVE state. If the speculation is in the ACTIVEONE state -- and -+ * the active CPU is not the specified CPU -- the speculation will be -+ * atomically transitioned into the ACTIVEMANY state. -+ */ -+struct dtrace_buffer *dtrace_speculation_buffer(struct dtrace_state *state, -+ processorid_t cpu, -+ dtrace_specid_t which) -+{ -+ struct dtrace_speculation *spec; -+ enum dtrace_speculation_state curr, new = 0; -+ struct dtrace_buffer *buf; -+ -+ if (which == 0) -+ return NULL; -+ -+ if (which > state->dts_nspeculations) { -+ per_cpu_core(cpu)->cpuc_dtrace_flags |= CPU_DTRACE_ILLOP; -+ return NULL; -+ } -+ -+ spec = &state->dts_speculations[which - 1]; -+ buf = &spec->dtsp_buffer[cpu]; -+ -+ do { -+ curr = spec->dtsp_state; -+ -+ switch (curr) { -+ case DTRACESPEC_INACTIVE: -+ case DTRACESPEC_COMMITTINGMANY: -+ case DTRACESPEC_DISCARDING: -+ return NULL; -+ -+ case DTRACESPEC_COMMITTING: -+ ASSERT(buf->dtb_offset == 0); -+ return NULL; -+ -+ case DTRACESPEC_ACTIVEONE: -+ /* -+ * This speculation is currently active on one CPU. -+ * Check the offset in the buffer; if it's non-zero, -+ * that CPU must be us (and we leave the state alone). -+ * If it's zero, assume that we're starting on a new -+ * CPU -- and change the state to indicate that the -+ * speculation is active on more than one CPU. -+ */ -+ if (buf->dtb_offset != 0) -+ return buf; -+ -+ new = DTRACESPEC_ACTIVEMANY; -+ break; -+ -+ case DTRACESPEC_ACTIVEMANY: -+ return buf; -+ -+ case DTRACESPEC_ACTIVE: -+ new = DTRACESPEC_ACTIVEONE; -+ break; -+ -+ default: -+ ASSERT(0); -+ } -+ } while (cmpxchg((uint32_t *)&spec->dtsp_state, curr, new) != curr); -+ -+ ASSERT(new == DTRACESPEC_ACTIVEONE || new == DTRACESPEC_ACTIVEMANY); -+ -+ return buf; -+} -diff --git a/dtrace/dtrace_state.c b/dtrace/dtrace_state.c -new file mode 100644 -index 0000000000000000000000000000000000000000..7fb696e8f1a9d80fe98643c183018a1b4633911e ---- /dev/null -+++ b/dtrace/dtrace_state.c -@@ -0,0 +1,1108 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_state.c -+ * DESCRIPTION: DTrace - consumer state implementation -+ * -+ * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/cyclic.h> -+#include <linux/fs.h> -+#include <linux/idr.h> -+#include <linux/slab.h> -+#include <linux/smp.h> -+#include <linux/vmalloc.h> -+#include <asm/cmpxchg.h> -+ -+#include "dtrace.h" -+ -+int dtrace_destructive_disallow = 0; -+dtrace_optval_t dtrace_nspec_default = 1; -+dtrace_optval_t dtrace_specsize_default = 32 * 1024; -+dtrace_optval_t dtrace_dstate_defsize = 1 * 1024 * 1024; -+size_t dtrace_strsize_default = 256; -+dtrace_optval_t dtrace_stackframes_default = 20; -+dtrace_optval_t dtrace_ustackframes_default = 100; -+dtrace_optval_t dtrace_cleanrate_default = 9900990; -+dtrace_optval_t dtrace_cleanrate_min = 20000; -+dtrace_optval_t dtrace_cleanrate_max = (uint64_t)60 * NANOSEC; -+dtrace_optval_t dtrace_aggrate_default = NANOSEC; -+dtrace_optval_t dtrace_switchrate_default = NANOSEC; -+dtrace_optval_t dtrace_statusrate_default = NANOSEC; -+dtrace_optval_t dtrace_statusrate_max = (uint64_t)10 * NANOSEC; -+dtrace_optval_t dtrace_jstackframes_default = 50; -+dtrace_optval_t dtrace_jstackstrsize_default = 512; -+ktime_t dtrace_deadman_interval = KTIME_INIT(1, 0); -+ktime_t dtrace_deadman_timeout = KTIME_INIT(10, 0); -+ktime_t dtrace_deadman_user = KTIME_INIT(30, 0); -+ -+ /* Sampling before counting */ -+uint64_t dtrace_sync_sample_count = 100; -+ -+dtrace_id_t dtrace_probeid_begin; -+dtrace_id_t dtrace_probeid_end; -+dtrace_id_t dtrace_probeid_error; -+ -+struct dtrace_dynvar dtrace_dynhash_sink; -+ -+#define DTRACE_DYNHASH_FREE 0 -+#define DTRACE_DYNHASH_SINK 1 -+#define DTRACE_DYNHASH_VALID 2 -+ -+#define DTRACE_DYNVAR_CHUNKSIZE 256 -+ -+static void dtrace_dynvar_clean(struct dtrace_dstate *dstate) -+{ -+ struct dtrace_dynvar *dirty; -+ struct dtrace_dstate_percpu *dcpu; -+ int i, work = 0; -+ -+ for (i = 0; i < NR_CPUS; i++) { -+ dcpu = &dstate->dtds_percpu[i]; -+ -+ ASSERT(dcpu->dtdsc_rinsing == NULL); -+ -+ /* -+ * If the dirty list is NULL, there is no dirty work to do. -+ */ -+ if (dcpu->dtdsc_dirty == NULL) -+ continue; -+ -+ /* -+ * If the clean list is non-NULL, then we're not going to do -+ * any work for this CPU -- it means that there has not been -+ * a dtrace_dynvar() allocation on this CPU (or from this CPU) -+ * since the last time we cleaned house. -+ */ -+ if (dcpu->dtdsc_clean != NULL) -+ continue; -+ -+ work = 1; -+ -+ /* -+ * Atomically move the dirty list aside. -+ */ -+ do { -+ dirty = dcpu->dtdsc_dirty; -+ -+ /* -+ * Before we zap the dirty list, set the rinsing list. -+ * (This allows for a potential assertion in -+ * dtrace_dynvar(): if a free dynamic variable appears -+ * on a hash chain, either the dirty list or the -+ * rinsing list for some CPU must be non-NULL.) -+ */ -+ dcpu->dtdsc_rinsing = dirty; -+ dtrace_membar_producer(); -+ } while (cmpxchg(&dcpu->dtdsc_dirty, dirty, NULL) != dirty); -+ } -+ -+ /* -+ * No work to do; return. -+ */ -+ if (!work) -+ return; -+ -+ dtrace_sync(); -+ -+ for (i = 0; i < NR_CPUS; i++) { -+ dcpu = &dstate->dtds_percpu[i]; -+ -+ if (dcpu->dtdsc_rinsing == NULL) -+ continue; -+ -+ /* -+ * We are now guaranteed that no hash chain contains a pointer -+ * into this dirty list; we can make it clean. -+ */ -+ ASSERT(dcpu->dtdsc_clean == NULL); -+ dcpu->dtdsc_clean = dcpu->dtdsc_rinsing; -+ dcpu->dtdsc_rinsing = NULL; -+ } -+ -+ /* -+ * Before we actually set the state to be DTRACE_DSTATE_CLEAN, make -+ * sure that all CPUs have seen all of the dtdsc_clean pointers. -+ * This prevents a race whereby a CPU incorrectly decides that -+ * the state should be something other than DTRACE_DSTATE_CLEAN -+ * after dtrace_dynvar_clean() has completed. -+ */ -+ dtrace_sync(); -+ -+ dstate->dtds_state = DTRACE_DSTATE_CLEAN; -+} -+ -+int dtrace_dstate_init(struct dtrace_dstate *dstate, size_t size) -+{ -+ size_t hashsize, maxper, min, -+ chunksize = dstate->dtds_chunksize; -+ void *base, *percpu; -+ uintptr_t limit; -+ struct dtrace_dynvar *dvar, *next, *start; -+ int i; -+ -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ ASSERT(dstate->dtds_base == NULL && dstate->dtds_percpu == NULL); -+ -+ memset(dstate, 0, sizeof(struct dtrace_dstate)); -+ -+ dstate->dtds_chunksize = chunksize; -+ if (dstate->dtds_chunksize == 0) -+ dstate->dtds_chunksize = DTRACE_DYNVAR_CHUNKSIZE; -+ -+ min = dstate->dtds_chunksize + sizeof(struct dtrace_dynhash); -+ if (size < min) -+ size = min; -+ -+ base = dtrace_vzalloc_try(size); -+ if (base == NULL) -+ return -ENOMEM; -+ percpu = kmem_cache_alloc(dtrace_state_cachep, GFP_KERNEL); -+ if (percpu == NULL) { -+ vfree(base); -+ return -ENOMEM; -+ } -+ -+ dstate->dtds_size = size; -+ dstate->dtds_base = base; -+ dstate->dtds_percpu = percpu; -+ memset(dstate->dtds_percpu, 0, -+ NR_CPUS * sizeof(struct dtrace_dstate_percpu)); -+ -+ hashsize = size / -+ (dstate->dtds_chunksize + sizeof(struct dtrace_dynhash)); -+ -+ if (hashsize != 1 && (hashsize & 1)) -+ hashsize--; -+ -+ dstate->dtds_hashsize = hashsize; -+ dstate->dtds_hash = dstate->dtds_base; -+ -+ /* -+ * Set all of our hash buckets to point to the single sink, and (if -+ * it hasn't already been set), set the sink's hash value to be the -+ * sink sentinel value. The sink is needed for dynamic variable -+ * lookups to know that they have iterated over an entire, valid hash -+ * chain. -+ */ -+ for (i = 0; i < hashsize; i++) -+ dstate->dtds_hash[i].dtdh_chain = &dtrace_dynhash_sink; -+ -+ if (dtrace_dynhash_sink.dtdv_hashval != DTRACE_DYNHASH_SINK) -+ dtrace_dynhash_sink.dtdv_hashval = DTRACE_DYNHASH_SINK; -+ -+ /* -+ * Determine number of active CPUs. Divide free list evenly among -+ * active CPUs. -+ */ -+ start = (struct dtrace_dynvar *)((uintptr_t)base + -+ hashsize * sizeof(struct dtrace_dynhash)); -+ limit = (uintptr_t)base + size; -+ -+ maxper = (limit - (uintptr_t)start) / NR_CPUS; -+ maxper = (maxper / dstate->dtds_chunksize) * dstate->dtds_chunksize; -+ -+ for (i = 0; i < NR_CPUS; i++) { -+ dstate->dtds_percpu[i].dtdsc_free = dvar = start; -+ -+ /* -+ * If we don't even have enough chunks to make it once through -+ * NCPUs, we're just going to allocate everything to the first -+ * CPU. And if we're on the last CPU, we're going to allocate -+ * whatever is left over. In either case, we set the limit to -+ * be the limit of the dynamic variable space. -+ */ -+ if (maxper == 0 || i == NR_CPUS - 1) { -+ limit = (uintptr_t)base + size; -+ start = NULL; -+ } else { -+ limit = (uintptr_t)start + maxper; -+ start = (struct dtrace_dynvar *)limit; -+ } -+ -+ ASSERT(limit <= (uintptr_t)base + size); -+ -+ for (;;) { -+ next = (struct dtrace_dynvar *)((uintptr_t)dvar + -+ dstate->dtds_chunksize); -+ -+ if ((uintptr_t)next + dstate->dtds_chunksize >= limit) -+ break; -+ -+ dvar->dtdv_next = next; -+ dvar = next; -+ } -+ -+ if (maxper == 0) -+ break; -+ } -+ -+ return 0; -+} -+ -+void dtrace_dstate_fini(struct dtrace_dstate *dstate) -+{ -+ ASSERT(MUTEX_HELD(&cpu_lock)); -+ -+ if (dstate->dtds_base == NULL) -+ return; -+ -+ vfree(dstate->dtds_base); -+ kmem_cache_free(dtrace_state_cachep, dstate->dtds_percpu); -+} -+ -+void dtrace_vstate_fini(struct dtrace_vstate *vstate) -+{ -+ /* -+ * If only there was a logical XOR operator... -+ */ -+ ASSERT((vstate->dtvs_nglobals == 0) ^ (vstate->dtvs_globals != NULL)); -+ -+ if (vstate->dtvs_nglobals > 0) -+ vfree(vstate->dtvs_globals); -+ -+ if (vstate->dtvs_ntlocals > 0) -+ vfree(vstate->dtvs_tlocals); -+ -+ ASSERT((vstate->dtvs_nlocals == 0) ^ (vstate->dtvs_locals != NULL)); -+ -+ if (vstate->dtvs_nlocals > 0) -+ vfree(vstate->dtvs_locals); -+} -+ -+static void dtrace_state_clean(struct dtrace_state *state) -+{ -+ dtrace_optval_t *opt = state->dts_options; -+ -+ if (state->dts_activity != DTRACE_ACTIVITY_ACTIVE && -+ state->dts_activity != DTRACE_ACTIVITY_DRAINING) -+ return; -+ -+ dtrace_dynvar_clean(&state->dts_vstate.dtvs_dynvars); -+ dtrace_speculation_clean(state); -+ -+ cyclic_reprogram(state->dts_cleaner, ns_to_ktime( -+ opt[DTRACEOPT_CLEANRATE])); -+} -+ -+static void dtrace_state_deadman(struct dtrace_state *state) -+{ -+ ktime_t now; -+ -+ dtrace_sync(); -+ -+ now = dtrace_gethrtime(); -+ if (state != dtrace_anon.dta_state && -+ ktime_ge(ktime_sub(now, state->dts_laststatus), -+ dtrace_deadman_user)) -+ return; -+ -+ /* -+ * We must be sure that dts_alive never appears to be less than the -+ * value upon entry to dtrace_state_deadman(), and because we lack a -+ * dtrace_cas64(), we cannot store to it atomically. We thus instead -+ * store KTIME_MAX to it, followed by a memory barrier, followed by -+ * the new value. This assures that dts_alive never appears to be -+ * less than its true value, regardless of the order in which the -+ * stores to the underlying storage are issued. -+ */ -+ state->dts_alive = ktime_set(KTIME_SEC_MAX, 0); -+ dtrace_membar_producer(); -+ state->dts_alive = now; -+} -+ -+struct dtrace_state *dtrace_state_create(struct file *file) -+{ -+ struct dtrace_state *state; -+ dtrace_optval_t *opt; -+ int bufsize = NR_CPUS * sizeof(struct dtrace_buffer), i; -+#ifdef FIXME -+ const struct cred *cr = file->f_cred; -+#endif -+ dtrace_aggid_t aggid; -+ -+ ASSERT(MUTEX_HELD(&cpu_lock)); -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ -+ state = kzalloc(sizeof(struct dtrace_state), GFP_KERNEL); -+ if (state == NULL) -+ return NULL; -+ -+ state->dts_epid = DTRACE_EPIDNONE + 1; -+ state->dts_buffer = vzalloc(bufsize); -+ if (state->dts_buffer == NULL) { -+ kfree(state); -+ return NULL; -+ } -+ -+ state->dts_aggbuffer = vzalloc(bufsize); -+ if (state->dts_aggbuffer == NULL) { -+ vfree(state->dts_buffer); -+ kfree(state); -+ return NULL; -+ } -+ -+ idr_init(&state->dts_agg_idr); -+ state->dts_naggs = 0; -+ state->dts_cleaner = 0; -+ state->dts_deadman = 0; -+ state->dts_vstate.dtvs_state = state; -+ -+ /* -+ * Create a first entry in the aggregation IDR, so that ID 0 is used as -+ * that gets used as meaning 'none'. -+ */ -+ idr_preload(GFP_KERNEL); -+ aggid = idr_alloc_cyclic(&state->dts_agg_idr, NULL, 0, 0, GFP_NOWAIT); -+ idr_preload_end(); -+ -+ ASSERT(aggid == 0); -+ -+ for (i = 0; i < DTRACEOPT_MAX; i++) -+ state->dts_options[i] = DTRACEOPT_UNSET; -+ -+ /* -+ * Set the default options. -+ */ -+ opt = state->dts_options; -+ opt[DTRACEOPT_BUFPOLICY] = DTRACEOPT_BUFPOLICY_SWITCH; -+ opt[DTRACEOPT_BUFRESIZE] = DTRACEOPT_BUFRESIZE_AUTO; -+ opt[DTRACEOPT_NSPEC] = dtrace_nspec_default; -+ opt[DTRACEOPT_SPECSIZE] = dtrace_specsize_default; -+ opt[DTRACEOPT_CPU] = (dtrace_optval_t)DTRACE_CPUALL; -+ opt[DTRACEOPT_STRSIZE] = dtrace_strsize_default; -+ opt[DTRACEOPT_STACKFRAMES] = dtrace_stackframes_default; -+ opt[DTRACEOPT_USTACKFRAMES] = dtrace_ustackframes_default; -+ opt[DTRACEOPT_CLEANRATE] = dtrace_cleanrate_default; -+ opt[DTRACEOPT_AGGRATE] = dtrace_aggrate_default; -+ opt[DTRACEOPT_SWITCHRATE] = dtrace_switchrate_default; -+ opt[DTRACEOPT_STATUSRATE] = dtrace_statusrate_default; -+ opt[DTRACEOPT_JSTACKFRAMES] = dtrace_jstackframes_default; -+ opt[DTRACEOPT_JSTACKSTRSIZE] = dtrace_jstackstrsize_default; -+ -+ state->dts_activity = DTRACE_ACTIVITY_INACTIVE; -+ -+#ifdef FIXME -+ /* -+ * Set probe visibility and destructiveness based on user credential -+ * information. For actual anonymous tracing or if all privileges are -+ * set, checks are bypassed. -+ */ -+ if (cr == NULL || -+ PRIV_POLICY_ONLY(cr, PRIV_ALL, FALSE)) { -+ state->dts_cred.dcr_visible = DTRACE_CRV_ALL; -+ state->dts_cred.dcr_action = DTRACE_CRA_ALL; -+ } else { -+ state->dts_cred.dcr_cred = get_cred(cr); -+ -+ /* -+ * CRA_PROC means "we have *some* privilege for dtrace" and -+ * it unlocks the use of variables like pid, etc. -+ */ -+ if (PRIV_POLICY_ONLY(cr, PRIV_DTRACE_USER, FALSE) || -+ PRIV_POLICY_ONLY(cr, PRIV_DTRACE_PROC, FALSE)) -+ state->dts_cred.dcr_action |= DTRACE_CRA_PROC; -+ -+ /* -+ * The DTRACE_USER privilege allows the use of syscall and -+ * profile providers. If the user also has PROC_OWNER, we -+ * extend the scope to include additional visibility and -+ * destructive power. -+ */ -+ if (PRIV_POLICY_ONLY(cr, PRIV_DTRACE_USER, FALSE)) { -+ if (PRIV_POLICY_ONLY(cr, PRIV_PROC_OWNER, FALSE)) -+ state->dts_cred.dcr_visible |= -+ DTRACE_CRV_ALLPROC; -+ -+ state->dts_cred.dcr_action |= -+ DTRACE_CRA_PROC_DESTRUCTIVE_ALLUSER; -+ } -+ -+ /* -+ * Holding the DTRACE_KERNEL privilege also implies that -+ * the user has the DTRACE_USER privilege from a visibility -+ * perspective. But without further privileges, some -+ * destructive actions are not available. -+ */ -+ if (PRIV_POLICY_ONLY(cr, PRIV_DTRACE_KERNEL, FALSE)) { -+ /* -+ * Make all probes in all zones visible. However, -+ * this doesn't mean that all actions become available -+ * to all zones. -+ */ -+ state->dts_cred.dcr_visible |= DTRACE_CRV_KERNEL | -+ DTRACE_CRV_ALLPROC; -+ state->dts_cred.dcr_action |= DTRACE_CRA_KERNEL | -+ DTRACE_CRA_PROC; -+ -+ /* -+ * Holding PROC_OWNER means that destructive actions -+ * are allowed. -+ */ -+ if (PRIV_POLICY_ONLY(cr, PRIV_PROC_OWNER, FALSE)) -+ state->dts_cred.dcr_action |= -+ DTRACE_CRA_PROC_DESTRUCTIVE_ALLUSER; -+ } -+ -+ /* -+ * Holding the DTRACE_PROC privilege gives control over the -+ * fasttrap and pid providers. We need to grant wider -+ * destructive privileges in the event that the user has -+ * PROC_OWNER . -+ */ -+ if (PRIV_POLICY_ONLY(cr, PRIV_DTRACE_PROC, FALSE)) { -+ if (PRIV_POLICY_ONLY(cr, PRIV_PROC_OWNER, FALSE)) -+ state->dts_cred.dcr_action |= -+ DTRACE_CRA_PROC_DESTRUCTIVE_ALLUSER; -+ } -+ } -+#else -+ state->dts_cred.dcr_visible = DTRACE_CRV_ALLPROC | DTRACE_CRV_KERNEL; -+ state->dts_cred.dcr_action = DTRACE_CRA_ALL; -+#endif -+ -+ return state; -+} -+ -+static int dtrace_state_buffer(struct dtrace_state *state, -+ struct dtrace_buffer *buf, int which) -+{ -+ dtrace_optval_t *opt = state->dts_options, size; -+ processorid_t cpu = DTRACE_CPUALL; -+ int flags = 0, rval; -+ -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ ASSERT(MUTEX_HELD(&cpu_lock)); -+ ASSERT(which < DTRACEOPT_MAX); -+ ASSERT(state->dts_activity == DTRACE_ACTIVITY_INACTIVE || -+ (state == dtrace_anon.dta_state && -+ state->dts_activity == DTRACE_ACTIVITY_ACTIVE)); -+ -+ if (opt[which] == DTRACEOPT_UNSET || opt[which] == 0) -+ return 0; -+ -+ if (opt[DTRACEOPT_CPU] != DTRACEOPT_UNSET) -+ cpu = opt[DTRACEOPT_CPU]; -+ -+ if (which == DTRACEOPT_SPECSIZE) -+ flags |= DTRACEBUF_NOSWITCH; -+ -+ if (which == DTRACEOPT_BUFSIZE) { -+ if (opt[DTRACEOPT_BUFPOLICY] == DTRACEOPT_BUFPOLICY_RING) -+ flags |= DTRACEBUF_RING; -+ -+ if (opt[DTRACEOPT_BUFPOLICY] == DTRACEOPT_BUFPOLICY_FILL) -+ flags |= DTRACEBUF_FILL; -+ -+ if (state != dtrace_anon.dta_state || -+ state->dts_activity != DTRACE_ACTIVITY_ACTIVE) -+ flags |= DTRACEBUF_INACTIVE; -+ } -+ -+ for (size = opt[which]; size >= sizeof(uint64_t); size >>= 1) { -+ /* -+ * The size must be 8-byte aligned. If the size is not 8-byte -+ * aligned, drop it down by the difference. -+ */ -+ if (size & (sizeof(uint64_t) - 1)) -+ size -= size & (sizeof(uint64_t) - 1); -+ -+ if (size < state->dts_reserve) { -+ /* -+ * Buffers always must be large enough to accommodate -+ * their prereserved space. We return -E2BIG instead -+ * of ENOMEM in this case to allow for user-level -+ * software to differentiate the cases. -+ */ -+ return -E2BIG; -+ } -+ -+ rval = dtrace_buffer_alloc(buf, size, flags, cpu); -+ if (rval != -ENOMEM) { -+ opt[which] = size; -+ return rval; -+ } -+ -+ if (opt[DTRACEOPT_BUFRESIZE] == DTRACEOPT_BUFRESIZE_MANUAL) -+ return rval; -+ } -+ -+ return -ENOMEM; -+} -+ -+static int dtrace_state_buffers(struct dtrace_state *state) -+{ -+ struct dtrace_speculation *spec = state->dts_speculations; -+ int rval, i; -+ -+ rval = dtrace_state_buffer(state, state->dts_buffer, DTRACEOPT_BUFSIZE); -+ if (rval != 0) -+ return rval; -+ -+ rval = dtrace_state_buffer(state, state->dts_aggbuffer, -+ DTRACEOPT_AGGSIZE); -+ if (rval != 0) -+ return rval; -+ -+ for (i = 0; i < state->dts_nspeculations; i++) { -+ rval = dtrace_state_buffer(state, spec[i].dtsp_buffer, -+ DTRACEOPT_SPECSIZE); -+ if (rval != 0) -+ return rval; -+ } -+ -+ return 0; -+} -+ -+static void dtrace_begin_probe(struct dtrace_state *state) -+{ -+ processorid_t cpuid = smp_processor_id(); -+ -+ ASSERT(state->dts_buffer[cpuid].dtb_flags & DTRACEBUF_INACTIVE); -+ state->dts_buffer[cpuid].dtb_flags &= ~DTRACEBUF_INACTIVE; -+ -+ dtrace_probe(dtrace_probeid_begin, (uint64_t)(uintptr_t)state, 0, 0, 0, -+ 0, 0, 0); -+ -+ /* -+ * We may have had an exit action from a BEGIN probe; only change our -+ * state to ACTIVE if we're still in WARMUP. -+ */ -+ ASSERT(state->dts_activity == DTRACE_ACTIVITY_WARMUP || -+ state->dts_activity == DTRACE_ACTIVITY_DRAINING); -+ -+ if (state->dts_activity == DTRACE_ACTIVITY_WARMUP) -+ state->dts_activity = DTRACE_ACTIVITY_ACTIVE; -+ -+ dtrace_membar_enter(); -+} -+ -+static void dtrace_state_prereserve(struct dtrace_state *state) -+{ -+ struct dtrace_ecb *ecb; -+ struct dtrace_probe *probe; -+ -+ state->dts_reserve = 0; -+ -+ if (state->dts_options[DTRACEOPT_BUFPOLICY] != DTRACEOPT_BUFPOLICY_FILL) -+ return; -+ -+ /* -+ * If our buffer policy is a "fill" buffer policy, we need to set the -+ * prereserved space to be the space required by the END probes. -+ */ -+ probe = dtrace_probe_lookup_id(dtrace_probeid_end); -+ ASSERT(probe != NULL); -+ -+ for (ecb = probe->dtpr_ecb; ecb != NULL; ecb = ecb->dte_next) { -+ if (ecb->dte_state != state) -+ continue; -+ -+ state->dts_reserve += ecb->dte_needed + ecb->dte_alignment; -+ } -+} -+ -+int dtrace_state_go(struct dtrace_state *state, processorid_t *cpu) -+{ -+ dtrace_optval_t *opt = state->dts_options, sz, nspec; -+ struct dtrace_speculation *spec; -+ struct dtrace_buffer *buf; -+ struct cyc_handler hdlr; -+ struct cyc_time when; -+ processorid_t cpuid; -+ int rval = 0, i, bufsize = NR_CPUS * sizeof(struct dtrace_buffer); -+ -+ mutex_lock(&cpu_lock); -+ mutex_lock(&dtrace_lock); -+ -+ if (state->dts_activity != DTRACE_ACTIVITY_INACTIVE) { -+ rval = -EBUSY; -+ goto out; -+ } -+ -+ /* -+ * Before we can perform any checks, we must prime all of the -+ * retained enablings that correspond to this state. -+ */ -+ dtrace_enabling_prime(state); -+ -+ if (state->dts_destructive && !state->dts_cred.dcr_destructive) { -+ rval = -EACCES; -+ goto out; -+ } -+ -+ dtrace_state_prereserve(state); -+ -+ /* -+ * If a cpu has been selected check if its value is valid and -+ * the cpu is online. -+ */ -+ cpuid = opt[DTRACEOPT_CPU]; -+ if (cpuid != DTRACE_CPUALL && -+ (cpuid < 0 || cpuid >= NR_CPUS || !cpu_online(cpuid))) { -+ rval = -ENXIO; -+ goto out; -+ } -+ -+ /* -+ * Now we want to do is try to allocate our speculations. -+ * We do not automatically resize the number of speculations; if -+ * this fails, we will fail the operation. -+ */ -+ nspec = opt[DTRACEOPT_NSPEC]; -+ ASSERT(nspec != DTRACEOPT_UNSET); -+ -+ if (nspec > INT_MAX) { -+ rval = -ENOMEM; -+ goto out; -+ } -+ -+ spec = vzalloc(nspec * sizeof(struct dtrace_speculation)); -+ if (spec == NULL) { -+ rval = -ENOMEM; -+ goto out; -+ } -+ -+ state->dts_speculations = spec; -+ state->dts_nspeculations = (int)nspec; -+ -+ for (i = 0; i < nspec; i++) { -+ buf = vzalloc(bufsize); -+ if (buf == NULL) { -+ rval = -ENOMEM; -+ goto err; -+ } -+ -+ spec[i].dtsp_buffer = buf; -+ } -+ -+ if (opt[DTRACEOPT_GRABANON] != DTRACEOPT_UNSET) { -+ if (dtrace_anon.dta_state == NULL) { -+ rval = -ENOENT; -+ goto out; -+ } -+ -+ if (state->dts_necbs != 0) { -+ rval = -EALREADY; -+ goto out; -+ } -+ -+ state->dts_anon = dtrace_anon_grab(); -+ ASSERT(state->dts_anon != NULL); -+ state = state->dts_anon; -+ -+ /* -+ * We want "grabanon" to be set in the grabbed state, so we'll -+ * copy that option value from the grabbing state into the -+ * grabbed state. -+ */ -+ state->dts_options[DTRACEOPT_GRABANON] = -+ opt[DTRACEOPT_GRABANON]; -+ -+ *cpu = dtrace_anon.dta_beganon; -+ -+ /* -+ * If the anonymous state is active (as it almost certainly -+ * is if the anonymous enabling ultimately matched anything), -+ * we don't allow any further option processing -- but we -+ * don't return failure. -+ */ -+ if (state->dts_activity != DTRACE_ACTIVITY_INACTIVE) -+ goto out; -+ } -+ -+ if (opt[DTRACEOPT_AGGSIZE] != DTRACEOPT_UNSET && -+ opt[DTRACEOPT_AGGSIZE] != 0) { -+ if (state->dts_naggs == 0) { -+ /* -+ * We're not going to create an aggregation buffer -+ * because we don't have any ECBs that contain -+ * aggregations -- set this option to 0. -+ */ -+ opt[DTRACEOPT_AGGSIZE] = 0; -+ } else { -+ /* -+ * If we have an aggregation buffer, we must also have -+ * a buffer to use as scratch. -+ */ -+ if (opt[DTRACEOPT_BUFSIZE] == DTRACEOPT_UNSET || -+ opt[DTRACEOPT_BUFSIZE] < state->dts_needed) -+ opt[DTRACEOPT_BUFSIZE] = state->dts_needed; -+ } -+ } -+ -+ if (opt[DTRACEOPT_SPECSIZE] != DTRACEOPT_UNSET && -+ opt[DTRACEOPT_SPECSIZE] != 0) { -+ /* -+ * We are not going to create speculation buffers if we do not -+ * have any ECBs that actually speculate. -+ */ -+ if (!state->dts_speculates) -+ opt[DTRACEOPT_SPECSIZE] = 0; -+ } -+ -+ /* -+ * The bare minimum size for any buffer that we're actually going to -+ * do anything to is sizeof (uint64_t). -+ */ -+ sz = sizeof(uint64_t); -+ -+ if ((state->dts_needed != 0 && opt[DTRACEOPT_BUFSIZE] < sz) || -+ (state->dts_speculates && opt[DTRACEOPT_SPECSIZE] < sz) || -+ (state->dts_naggs != 0 && opt[DTRACEOPT_AGGSIZE] < sz)) { -+ /* -+ * A buffer size has been explicitly set to 0 (or to a size -+ * that will be adjusted to 0) and we need the space -- we -+ * need to return failure. We return -ENOSPC to differentiate -+ * it from failing to allocate a buffer due to failure to meet -+ * the reserve (for which we return -E2BIG). -+ */ -+ rval = -ENOSPC; -+ goto out; -+ } -+ -+ rval = dtrace_state_buffers(state); -+ if (rval != 0) -+ goto err; -+ -+ sz = opt[DTRACEOPT_DYNVARSIZE]; -+ if (sz == DTRACEOPT_UNSET) -+ sz = dtrace_dstate_defsize; -+ -+ do { -+ rval = dtrace_dstate_init(&state->dts_vstate.dtvs_dynvars, sz); -+ -+ if (rval == 0) -+ break; -+ -+ if (opt[DTRACEOPT_BUFRESIZE] == DTRACEOPT_BUFRESIZE_MANUAL) -+ goto err; -+ } while (sz >>= 1); -+ -+ opt[DTRACEOPT_DYNVARSIZE] = sz; -+ -+ if (rval != 0) -+ goto err; -+ -+ if (opt[DTRACEOPT_STATUSRATE] > dtrace_statusrate_max) -+ opt[DTRACEOPT_STATUSRATE] = dtrace_statusrate_max; -+ -+ if (opt[DTRACEOPT_CLEANRATE] == 0) -+ opt[DTRACEOPT_CLEANRATE] = dtrace_cleanrate_max; -+ -+ if (opt[DTRACEOPT_CLEANRATE] < dtrace_cleanrate_min) -+ opt[DTRACEOPT_CLEANRATE] = dtrace_cleanrate_min; -+ -+ if (opt[DTRACEOPT_CLEANRATE] > dtrace_cleanrate_max) -+ opt[DTRACEOPT_CLEANRATE] = dtrace_cleanrate_max; -+ -+ hdlr.cyh_func = (cyc_func_t)dtrace_state_clean; -+ hdlr.cyh_arg = (uintptr_t)state; -+ hdlr.cyh_level = CY_LOW_LEVEL; -+ -+ when.cyt_when = ktime_set(0, 0); -+ when.cyt_interval = CY_INTERVAL_INF; -+ -+ state->dts_cleaner = cyclic_add(&hdlr, &when); -+ cyclic_reprogram(state->dts_cleaner, ns_to_ktime( -+ opt[DTRACEOPT_CLEANRATE])); -+ -+ hdlr.cyh_func = (cyc_func_t)dtrace_state_deadman; -+ hdlr.cyh_arg = (uintptr_t)state; -+ hdlr.cyh_level = CY_LOW_LEVEL; -+ -+ when.cyt_when = ktime_set(0, 0); -+ when.cyt_interval = dtrace_deadman_interval; -+ -+ state->dts_alive = state->dts_laststatus = dtrace_gethrtime(); -+ state->dts_deadman = cyclic_add(&hdlr, &when); -+ -+ state->dts_activity = DTRACE_ACTIVITY_WARMUP; -+ -+ /* -+ * Issue xcall even when the BEGIN probe fires on current CPU. The -+ * underlying implementation of SMP will turn it into direct function -+ * call. It is not allowed to turn off interrupts so we need to pick -+ * a cpu first and then xcall it. This way a begin probe will always -+ * fire on the expected cpu. -+ */ -+ *cpu = (cpuid == DTRACE_CPUALL) ? smp_processor_id() : cpuid; -+ dtrace_xcall(*cpu, (dtrace_xcall_t)dtrace_begin_probe, state); -+ -+ /* -+ * Regardless of whether or not now we're in ACTIVE or DRAINING, we -+ * want each CPU to transition its principal buffer out of the -+ * INACTIVE state. Doing this assures that no CPU will suddenly begin -+ * processing an ECB halfway down a probe's ECB chain; all CPUs will -+ * atomically transition from processing none of a state's ECBs to -+ * processing all of them. -+ */ -+ dtrace_xcall(DTRACE_CPUALL, (dtrace_xcall_t)dtrace_buffer_activate, -+ state); -+ goto out; -+ -+err: -+ dtrace_buffer_free(state->dts_buffer); -+ dtrace_buffer_free(state->dts_aggbuffer); -+ -+ nspec = state->dts_nspeculations; -+ if (nspec == 0) { -+ ASSERT(state->dts_speculations == NULL); -+ goto out; -+ } -+ -+ spec = state->dts_speculations; -+ ASSERT(spec != NULL); -+ -+ for (i = 0; i < state->dts_nspeculations; i++) { -+ buf = spec[i].dtsp_buffer; -+ if (buf == NULL) -+ break; -+ -+ dtrace_buffer_free(buf); -+ vfree(buf); -+ } -+ -+ vfree(spec); -+ state->dts_nspeculations = 0; -+ state->dts_speculations = NULL; -+ -+out: -+ mutex_unlock(&dtrace_lock); -+ mutex_unlock(&cpu_lock); -+ -+ return rval; -+} -+ -+static void dtrace_end_probe(struct dtrace_state *state) -+{ -+ dtrace_probe(dtrace_probeid_end, (uint64_t)(uintptr_t)state, 0, 0, 0, -+ 0, 0, 0); -+ -+ state->dts_activity = DTRACE_ACTIVITY_STOPPED; -+ -+ dtrace_membar_enter(); -+} -+ -+int dtrace_state_stop(struct dtrace_state *state, processorid_t *cpu) -+{ -+ processorid_t cpuid = state->dts_options[DTRACEOPT_CPU]; -+ -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ -+ if (state->dts_activity != DTRACE_ACTIVITY_ACTIVE && -+ state->dts_activity != DTRACE_ACTIVITY_DRAINING) -+ return -EINVAL; -+ -+ /* -+ * We'll set the activity to DTRACE_ACTIVITY_DRAINING, and issue a sync -+ * to be sure that every CPU has seen it. See below for the details -+ * on why this is done. -+ */ -+ state->dts_activity = DTRACE_ACTIVITY_DRAINING; -+ dtrace_sync(); -+ -+ /* -+ * By this point, it is impossible for any CPU to be still processing -+ * with DTRACE_ACTIVITY_ACTIVE. We can thus set our activity to -+ * DTRACE_ACTIVITY_COOLDOWN and know that we're not racing with any -+ * other CPU in dtrace_buffer_reserve(). This allows dtrace_probe() -+ * and callees to know that the activity is DTRACE_ACTIVITY_COOLDOWN -+ * iff we're in the END probe. -+ */ -+ state->dts_activity = DTRACE_ACTIVITY_COOLDOWN; -+ dtrace_sync(); -+ ASSERT(state->dts_activity == DTRACE_ACTIVITY_COOLDOWN); -+ -+ /* -+ * Finally, we can release the reserve and call the END probe. We -+ * disable interrupts across calling the END probe to allow us to -+ * return the CPU on which we actually called the END probe. This -+ * allows user-land to be sure that this CPU's principal buffer is -+ * processed last. -+ */ -+ state->dts_reserve = 0; -+ -+ /* -+ * Same as for BEGIN probe in dtrace_state_go(). The END probe must -+ * also fire on the enabled cpu. -+ */ -+ *cpu = (cpuid == DTRACE_CPUALL) ? smp_processor_id() : cpuid; -+ dtrace_xcall(*cpu, (dtrace_xcall_t)dtrace_end_probe, state); -+ -+ dtrace_sync(); -+ return 0; -+} -+ -+int dtrace_state_option(struct dtrace_state *state, dtrace_optid_t option, -+ dtrace_optval_t val) -+{ -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ -+ if (state->dts_activity != DTRACE_ACTIVITY_INACTIVE) -+ return -EBUSY; -+ -+ if (option >= DTRACEOPT_MAX) -+ return -EINVAL; -+ -+ if (option != DTRACEOPT_CPU && val < 0) -+ return -EINVAL; -+ -+ switch (option) { -+ case DTRACEOPT_DESTRUCTIVE: -+ if (dtrace_destructive_disallow) -+ return -EACCES; -+ -+ state->dts_cred.dcr_destructive = 1; -+ break; -+ -+ case DTRACEOPT_BUFSIZE: -+ case DTRACEOPT_DYNVARSIZE: -+ case DTRACEOPT_AGGSIZE: -+ case DTRACEOPT_SPECSIZE: -+ case DTRACEOPT_STRSIZE: -+ if (val < 0) -+ return -EINVAL; -+ -+ /* -+ * If this is an otherwise negative value, set it to the -+ * highest multiple of 128m less than LONG_MAX. Technically, -+ * we're adjusting the size without regard to the buffer -+ * resizing policy, but in fact, this has no effect -- if we -+ * set the buffer size to ~LONG_MAX and the buffer policy is -+ * ultimately set to be "manual", the buffer allocation is -+ * guaranteed to fail, if only because the allocation requires -+ * two buffers. (We set the the size to the highest multiple -+ * of 128m because it ensures that the size will remain a -+ * multiple of a megabyte when repeatedly halved -- all the -+ * way down to 15m.) -+ */ -+ if (val >= LONG_MAX) -+ val = LONG_MAX - (1 << 27) + 1; -+ } -+ -+ state->dts_options[option] = val; -+ -+ return 0; -+} -+ -+void dtrace_state_destroy(struct dtrace_state *state) -+{ -+ struct dtrace_ecb *ecb; -+ struct dtrace_vstate *vstate = &state->dts_vstate; -+ int i; -+ struct dtrace_speculation *spec = state->dts_speculations; -+ int nspec = state->dts_nspeculations; -+ uint32_t match; -+ -+ ASSERT(MUTEX_HELD(&dtrace_lock)); -+ ASSERT(MUTEX_HELD(&cpu_lock)); -+ -+ /* -+ * First, retract any retained enablings for this state. -+ */ -+ dtrace_enabling_retract(state); -+ ASSERT(state->dts_nretained == 0); -+ -+ if (state->dts_activity == DTRACE_ACTIVITY_ACTIVE || -+ state->dts_activity == DTRACE_ACTIVITY_DRAINING) { -+ /* -+ * We have managed to come into dtrace_state_destroy() on a -+ * hot enabling -- almost certainly because of a disorderly -+ * shutdown of a consumer. (That is, a consumer that is -+ * exiting without having called dtrace_stop().) In this case, -+ * we're going to set our activity to be KILLED, and then -+ * issue a sync to be sure that everyone is out of probe -+ * context before we start blowing away ECBs. -+ */ -+ state->dts_activity = DTRACE_ACTIVITY_KILLED; -+ dtrace_sync(); -+ } -+ -+ /* -+ * Release the credential hold we took in dtrace_state_create(). -+ */ -+ if (state->dts_cred.dcr_cred != NULL) -+ put_cred(state->dts_cred.dcr_cred); -+ -+ /* -+ * Now we can safely disable and destroy any enabled probes. Because -+ * any DTRACE_PRIV_KERNEL probes may actually be slowing our progress -+ * (especially if they're all enabled), we take two passes through the -+ * ECBs: in the first, we disable just DTRACE_PRIV_KERNEL probes, and -+ * in the second we disable whatever is left over. -+ */ -+ for (match = DTRACE_PRIV_KERNEL; ; match = 0) { -+ for (i = 0; i < state->dts_necbs; i++) { -+ ecb = state->dts_ecbs[i]; -+ if (ecb == NULL) -+ continue; -+ -+ if (match && ecb->dte_probe != NULL) { -+ struct dtrace_probe *probe = -+ ecb->dte_probe; -+ struct dtrace_provider *prov = -+ probe->dtpr_provider; -+ -+ if (!(prov->dtpv_priv.dtpp_flags & match)) -+ continue; -+ } -+ -+ dtrace_ecb_disable(ecb); -+ dtrace_ecb_destroy(ecb); -+ } -+ -+ if (!match) -+ break; -+ } -+ -+ /* -+ * Before we free the buffers, perform one more sync to assure that -+ * every CPU is out of probe context. -+ */ -+ dtrace_sync(); -+ -+ dtrace_buffer_free(state->dts_buffer); -+ dtrace_buffer_free(state->dts_aggbuffer); -+ -+ for (i = 0; i < nspec; i++) -+ dtrace_buffer_free(spec[i].dtsp_buffer); -+ -+ if (state->dts_cleaner != CYCLIC_NONE) -+ cyclic_remove(state->dts_cleaner); -+ -+ if (state->dts_deadman != CYCLIC_NONE) -+ cyclic_remove(state->dts_deadman); -+ -+ dtrace_dstate_fini(&vstate->dtvs_dynvars); -+ dtrace_vstate_fini(vstate); -+ vfree(state->dts_ecbs); -+ -+ /* -+ * If there were aggregations allocated, they should have been cleaned -+ * up by now, so we can get rid of the idr. -+ */ -+ idr_destroy(&state->dts_agg_idr); -+ -+ vfree(state->dts_buffer); -+ vfree(state->dts_aggbuffer); -+ -+ for (i = 0; i < nspec; i++) -+ vfree(spec[i].dtsp_buffer); -+ -+ vfree(spec); -+ -+ dtrace_format_destroy(state); -+ -+ kfree(state); -+} -diff --git a/dtrace/dtrace_util.c b/dtrace/dtrace_util.c -new file mode 100644 -index 0000000000000000000000000000000000000000..76fdf2bd8b41d069de795b655ce1ea475aad81a2 ---- /dev/null -+++ b/dtrace/dtrace_util.c -@@ -0,0 +1,282 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_util.c -+ * DESCRIPTION: DTrace - utility functions -+ * -+ * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/dtrace_cpu.h> -+#include <linux/module.h> -+#include <linux/vmalloc.h> -+#include <asm/pgtable.h> -+ -+#include "dtrace.h" -+ -+int dtrace_isglob(const char *s) -+{ -+ char c; -+ -+ while ((c = *s++) != '\0') { -+ if (c == '[' || c == '?' || c == '*' || c == '\\') -+ return 1; -+ } -+ -+ return 0; -+} -+EXPORT_SYMBOL(dtrace_isglob); -+ -+int dtrace_gmatch(const char *s, const char *p) -+{ -+ const char *olds = s; -+ char sc; -+ char pc; -+ -+ sc = *s++; -+ pc = *p++; -+ -+ if (!pc) -+ return !sc; -+ -+ switch (pc) { -+ case '[': { -+ int ok = 0; -+ char lc = '\0'; -+ int inv = 0; -+ -+ if (!sc) -+ return 0; -+ -+ if (*p == '!') { -+ inv = 1; -+ p++; -+ } -+ -+ pc = *p++; -+ do { -+ if (pc == '-' && lc && *p != ']') { -+ pc = *p++; -+ if (pc == '\\') -+ pc = *p++; -+ -+ if (inv) { -+ if (sc < lc || sc > pc) -+ ok++; -+ else -+ return 0; -+ } else { -+ if (lc <= sc && sc <= pc) -+ ok++; -+ } -+ } else if (pc == '\\') { -+ pc = *p++; -+ } -+ -+ lc = sc; -+ -+ if (inv) { -+ if (sc != lc) -+ ok++; -+ else -+ return 0; -+ } else { -+ if (sc == lc) -+ ok++; -+ } -+ -+ pc = *p++; -+ } while (pc != ']'); -+ -+ return ok ? dtrace_gmatch(s, p) : 0; -+ } -+ case '\\': -+ pc = *p++; -+ if (!pc) -+ return 0; -+ -+ /* fall-through */ -+ default: -+ if (pc != sc) -+ return 0; -+ -+ /* fall-through */ -+ case '?': -+ return sc ? dtrace_gmatch(s, p) : 0; -+ case '*': -+ while (*p == '*') -+ p++; -+ -+ if (!*p) -+ return 1; -+ -+ s = olds; -+ while (*s) { -+ if (dtrace_gmatch(s, p)) -+ return 1; -+ -+ s++; -+ } -+ -+ return 0; -+ } -+} -+EXPORT_SYMBOL(dtrace_gmatch); -+ -+int dtrace_badattr(const struct dtrace_attribute *a) -+{ -+ return a->dtat_name > DTRACE_STABILITY_MAX || -+ a->dtat_data > DTRACE_STABILITY_MAX || -+ a->dtat_class > DTRACE_CLASS_MAX; -+} -+ -+/* -+ * Allocate a chunk of virtual memory in kernel space, and zero it out. This -+ * allocation might fail (which will report a backtrace in the kernel log, yet -+ * it is harmless). -+ */ -+void *dtrace_vzalloc_try(unsigned long size) -+{ -+ return __vmalloc(size, -+ GFP_NOWAIT | __GFP_FS | __GFP_IO | __GFP_NOMEMALLOC | -+ __GFP_NORETRY | __GFP_NOWARN | __GFP_ZERO); -+} -+EXPORT_SYMBOL(dtrace_vzalloc_try); -+ -+/* -+ * Return a duplicate copy of a string. If the specified string is NULL, this -+ * function returs a zero-length string. -+ */ -+char *dtrace_strdup(const char *str) -+{ -+ return kstrdup(str ? str : "", GFP_KERNEL); -+} -+ -+/* -+ * Compare two strings using safe loads. -+ */ -+int dtrace_strncmp(char *s1, char *s2, size_t limit) -+{ -+ uint8_t c1, c2; -+ volatile uint16_t *flags; -+ -+ if (s1 == s2 || limit == 0) -+ return 0; -+ -+ flags = (volatile uint16_t *)&this_cpu_core->cpuc_dtrace_flags; -+ -+ do { -+ if (s1 == NULL) -+ c1 = '\0'; -+ else -+ c1 = dtrace_load8((uintptr_t)s1++); -+ -+ if (s2 == NULL) -+ c2 = '\0'; -+ else -+ c2 = dtrace_load8((uintptr_t)s2++); -+ -+ if (c1 != c2) -+ return (c1 - c2); -+ } while (--limit && c1 != '\0' && !(*flags & CPU_DTRACE_FAULT)); -+ -+ return 0; -+} -+ -+/* -+ * Compute strlen(s) for a string using safe memory accesses. The additional -+ * len parameter is used to specify a maximum length to ensure completion. -+ */ -+size_t dtrace_strlen(const char *s, size_t lim) -+{ -+ uint_t len; -+ -+ for (len = 0; len != lim; len++) { -+ if (dtrace_load8((uintptr_t)s++) == '\0') -+ break; -+ } -+ -+ return len; -+} -+ -+#define DTRACE_ISALPHA(c) (((c) >= 'a' && (c) <= 'z') || \ -+ ((c) >= 'A' && (c) <= 'Z')) -+int dtrace_badname(const char *s) -+{ -+ char c; -+ -+ if (s == NULL) -+ return 0; -+ -+ c = *s++; -+ if (c == '\0') -+ return 0; -+ -+ if (!DTRACE_ISALPHA(c) && c != '-' && c != '_' && c != '.') -+ return 1; -+ -+ while ((c = *s++) != '\0') { -+ if (!DTRACE_ISALPHA(c) && (c < '0' || c > '9') && -+ c != '-' && c != '_' && c != '.' && c != '`') -+ return 1; -+ } -+ -+ return 0; -+} -+ -+void dtrace_cred2priv(const struct cred *cr, uint32_t *privp, kuid_t *uidp) -+{ -+#ifdef FIXME -+/* -+ * This should probably be rewritten based on capabilities in the struct cred. -+ */ -+ uint32_t priv; -+ -+ if (cr == NULL) -+ priv = DTRACE_PRIV_ALL; -+ else { -+ const struct cred *lcr = get_cred(cr); -+ -+ if (PRIV_POLICY_ONLY(lcr, PRIV_ALL, FALSE)) -+ priv = DTRACE_PRIV_ALL; -+ else { -+ *uidp = lcr->uid; -+ priv = 0; -+ -+ if (PRIV_POLICY_ONLY(lcr, PRIV_DTRACE_KERNEL, FALSE)) -+ priv |= DTRACE_PRIV_KERNEL | DTRACE_PRIV_USER; -+ else if (PRIV_POLICY_ONLY(lcr, PRIV_DTRACE_USER, -+ FALSE)) -+ priv |= DTRACE_PRIV_USER; -+ -+ if (PRIV_POLICY_ONLY(lcr, PRIV_DTRACE_PROC, FALSE)) -+ priv |= DTRACE_PRIV_PROC; -+ if (PRIV_POLICY_ONLY(lcr, PRIV_PROC_OWNER, FALSE)) -+ priv |= DTRACE_PRIV_OWNER; -+ } -+ -+ put_cred(cr); -+ } -+ -+ *privp = priv; -+#else -+ *privp = DTRACE_PRIV_ALL; -+ -+ if (cr != NULL) { -+ const struct cred *lcr = get_cred(cr); -+ -+ *uidp = lcr->uid; -+ put_cred(cr); -+ } -+#endif -+} -+ --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/dtrace-patches/0006-dtrace-systrace-provider-core-components.patch b/sys-kernel/cairn-sources/files/5.10.14/dtrace-patches/0006-dtrace-systrace-provider-core-components.patch deleted file mode 100644 index 82a4f079a525..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/dtrace-patches/0006-dtrace-systrace-provider-core-components.patch +++ /dev/null @@ -1,326 +0,0 @@ -From a71a23031f2c3ae2e9b4a560bf5ed11e6d237003 Mon Sep 17 00:00:00 2001 -From: Kris Van Hees <kris.van.hees@oracle.com> -Date: Mon, 19 Nov 2018 16:55:11 +0000 -Subject: [PATCH 06/19] dtrace: systrace provider core components - -This implements the core (linked-in) components of the DTrace systrace -provider, which intercepts system call invocations. As previously, -the arch-dependent pieces needed for x86 are also provided. - -Signed-off-by: Nick Alcock <nick.alcock@oracle.com> -Signed-off-by: Kris Van Hees <kris.van.hees@oracle.com> -Signed-off-by: Tomas Jedlicka <tomas.jedlicka@oracle.com> -Signed-off-by: Eugene Loh <eugene.loh@oracle.com> -Signed-off-by: David Mc Lean <david.mclean@oracle.com> -Signed-off-by: Vincent Lim <vincent.lim@oracle.com> ---- - arch/x86/entry/syscall_32.c | 4 + - arch/x86/entry/syscall_64.c | 4 + - arch/x86/include/asm/dtrace_syscall.h | 3 + - arch/x86/include/asm/dtrace_syscall_types.h | 11 +++ - arch/x86/include/asm/syscall.h | 8 ++ - arch/x86/kernel/dtrace_syscall.c | 97 +++++++++++++++++++++ - arch/x86/kernel/dtrace_syscall_stubs.S | 0 - include/linux/dtrace_syscall.h | 60 +++++++++++++ - kernel/dtrace/Kconfig | 9 ++ - kernel/dtrace/Makefile | 1 + - 10 files changed, 197 insertions(+) - create mode 100644 arch/x86/include/asm/dtrace_syscall.h - create mode 100644 arch/x86/include/asm/dtrace_syscall_types.h - create mode 100644 arch/x86/kernel/dtrace_syscall.c - create mode 100644 arch/x86/kernel/dtrace_syscall_stubs.S - create mode 100644 include/linux/dtrace_syscall.h - -diff --git a/arch/x86/entry/syscall_32.c b/arch/x86/entry/syscall_32.c -index 86eb0d89d46fa5244b766272bc5d0fd6411588a3..66381ebd6a9f4628416dd40be15ccfa230b1c15a 100644 ---- a/arch/x86/entry/syscall_32.c -+++ b/arch/x86/entry/syscall_32.c -@@ -15,7 +15,11 @@ - - #define __SYSCALL_I386(nr, sym) [nr] = __ia32_##sym, - -+#if IS_ENABLED(CONFIG_DT_SYSTRACE) -+__visible sys_call_ptr_t ia32_sys_call_table[__NR_ia32_syscall_max+1] = { -+#else - __visible const sys_call_ptr_t ia32_sys_call_table[__NR_ia32_syscall_max+1] = { -+#endif /* CONFIG_DT_SYSTRACE || CONFIG_DT_SYSTRACE_MODULE */ - /* - * Smells like a compiler bug -- it doesn't work - * when the & below is removed. -diff --git a/arch/x86/entry/syscall_64.c b/arch/x86/entry/syscall_64.c -index 1594ec72bcbb7183512f087acd29160443802683..42587831ef04e801399cf58e1068212d2d15e53e 100644 ---- a/arch/x86/entry/syscall_64.c -+++ b/arch/x86/entry/syscall_64.c -@@ -17,7 +17,11 @@ - - #define __SYSCALL_64(nr, sym) [nr] = __x64_##sym, - -+#if IS_ENABLED(CONFIG_DT_SYSTRACE) -+asmlinkage sys_call_ptr_t sys_call_table[__NR_syscall_max+1] = { -+#else - asmlinkage const sys_call_ptr_t sys_call_table[__NR_syscall_max+1] = { -+#endif /* CONFIG_DT_SYSTRACE || CONFIG_DT_SYSTRACE_MODULE */ - /* - * Smells like a compiler bug -- it doesn't work - * when the & below is removed. -diff --git a/arch/x86/include/asm/dtrace_syscall.h b/arch/x86/include/asm/dtrace_syscall.h -new file mode 100644 -index 0000000000000000000000000000000000000000..402826562478213976f122510d4082af23028fd3 ---- /dev/null -+++ b/arch/x86/include/asm/dtrace_syscall.h -@@ -0,0 +1,3 @@ -+/* -+ * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. -+ */ -diff --git a/arch/x86/include/asm/dtrace_syscall_types.h b/arch/x86/include/asm/dtrace_syscall_types.h -new file mode 100644 -index 0000000000000000000000000000000000000000..2b3ee563ad143daab95cc6256e02e12ce15a4436 ---- /dev/null -+++ b/arch/x86/include/asm/dtrace_syscall_types.h -@@ -0,0 +1,11 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+#include <linux/types.h> -+#include <linux/dtrace_types.h> -+ -+typedef asmlinkage long (*dt_sys_call_t)(const struct pt_regs *regs); -+ -+#define DTRACE_SYSCALL_WRAP_PREFIX "__x64_" -diff --git a/arch/x86/include/asm/syscall.h b/arch/x86/include/asm/syscall.h -index 7cbf733d11afd9fe150cbd8676065821a928d9ad..3d1bce850b7494381a2127bf526eab11ff7e5029 100644 ---- a/arch/x86/include/asm/syscall.h -+++ b/arch/x86/include/asm/syscall.h -@@ -17,15 +17,23 @@ - #include <asm/unistd.h> - - typedef long (*sys_call_ptr_t)(const struct pt_regs *); -+#if IS_ENABLED(CONFIG_DT_SYSTRACE) -+extern sys_call_ptr_t sys_call_table[]; -+#else - extern const sys_call_ptr_t sys_call_table[]; -+#endif - - #if defined(CONFIG_X86_32) - #define ia32_sys_call_table sys_call_table - #endif - - #if defined(CONFIG_IA32_EMULATION) -+#if IS_ENABLED(CONFIG_DT_SYSTRACE) -+extern sys_call_ptr_t ia32_sys_call_table[]; -+#else - extern const sys_call_ptr_t ia32_sys_call_table[]; - #endif -+#endif - - #ifdef CONFIG_X86_X32_ABI - extern const sys_call_ptr_t x32_sys_call_table[]; -diff --git a/arch/x86/kernel/dtrace_syscall.c b/arch/x86/kernel/dtrace_syscall.c -new file mode 100644 -index 0000000000000000000000000000000000000000..3328710e7050714930851dc2bf3e5b1a2de32f5b ---- /dev/null -+++ b/arch/x86/kernel/dtrace_syscall.c -@@ -0,0 +1,97 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_syscall.c -+ * DESCRIPTION: Dynamic Tracing: system call tracing support (arch-specific) -+ * -+ * Copyright (C) 2010-2018 Oracle Corporation -+ */ -+ -+#include <linux/dtrace_cpu.h> -+#include <linux/dtrace_os.h> -+#include <linux/dtrace_syscall.h> -+#include <linux/fs.h> -+#include <linux/module.h> -+#include <linux/namei.h> -+#include <linux/sched.h> -+#include <asm/insn.h> -+#include <asm/stacktrace.h> -+#include <asm/syscalls.h> -+ -+/* -+ * SYSTEM CALL TRACING SUPPORT -+ */ -+void (*systrace_probe)(dtrace_id_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, -+ uintptr_t, uintptr_t, uintptr_t); -+ -+void systrace_stub(dtrace_id_t id, uintptr_t arg0, uintptr_t arg1, -+ uintptr_t arg2, uintptr_t arg3, uintptr_t arg4, -+ uintptr_t arg5, uintptr_t arg6) -+{ -+} -+ -+asmlinkage long systrace_syscall(const struct pt_regs *regs); -+ -+asmlinkage long dtrace_stub_ptregs(uintptr_t, uintptr_t, uintptr_t, uintptr_t, -+ uintptr_t, uintptr_t, uintptr_t); -+ -+static struct systrace_info systrace_info = -+{ -+ &systrace_probe, -+ systrace_stub, -+ systrace_syscall, -+ {}, -+ { -+#define __SYSCALL_64(nr, sym) [nr] { __stringify(sym), }, -+#define __SYSCALL_COMMON(nr, sym) __SYSCALL_64(nr, sym) -+#define __SYSCALL_X32(nt, sym) -+#include <asm/syscalls_64.h> -+ } -+}; -+ -+asmlinkage long systrace_syscall(const struct pt_regs *regs) -+{ -+ long rc = 0; -+ unsigned long sysnum; -+ dtrace_id_t id; -+ struct dtrace_syscalls *sc; -+ -+ sysnum = syscall_get_nr(current, (struct pt_regs *) regs); -+ sc = &systrace_info.sysent[sysnum]; -+ -+ /* -+ * Note: 64-bit syscall-specific. -+ */ -+ id = sc->stsy_entry; -+ if (id != DTRACE_IDNONE) -+ (*systrace_probe)(id, regs->di, regs->si, regs->dx, -+ regs->r10, regs->r8, regs->r9, 0); -+ -+ /* -+ * FIXME: Add stop functionality for DTrace. -+ */ -+ -+ if (sc->stsy_underlying != NULL) -+ rc = (*sc->stsy_underlying)(regs); -+ -+ id = sc->stsy_return; -+ if (id != DTRACE_IDNONE) -+ (*systrace_probe)(id, (uintptr_t)rc, (uintptr_t)rc, -+ (uintptr_t)((uint64_t)rc >> 32), 0, 0, 0, 0); -+ -+ return rc; -+} -+ -+struct systrace_info *dtrace_syscalls_init(void) -+{ -+ int i; -+ -+ for (i = 0; i < NR_syscalls; i++) { -+ systrace_info.sysent[i].stsy_tblent = -+ (dt_sys_call_t *)&sys_call_table[i]; -+ systrace_info.sysent[i].stsy_underlying = -+ (dt_sys_call_t)sys_call_table[i]; -+ } -+ -+ return &systrace_info; -+} -+EXPORT_SYMBOL(dtrace_syscalls_init); -diff --git a/arch/x86/kernel/dtrace_syscall_stubs.S b/arch/x86/kernel/dtrace_syscall_stubs.S -new file mode 100644 -index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 -diff --git a/include/linux/dtrace_syscall.h b/include/linux/dtrace_syscall.h -new file mode 100644 -index 0000000000000000000000000000000000000000..7f9e351f3783ec92d36c6984233723f95cdbcaa7 ---- /dev/null -+++ b/include/linux/dtrace_syscall.h -@@ -0,0 +1,60 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+#ifndef _LINUX_DTRACE_SYSCALL_H_ -+#define _LINUX_DTRACE_SYSCALL_H_ -+ -+#include <linux/types.h> -+#include <linux/dtrace_os.h> -+#include <asm/syscall.h> -+ -+#define DTRACE_SYSCALL_STUB(t, n) SCE_##t, -+enum dtrace_sce_id { -+ SCE_NONE = 0, -+#include <asm/dtrace_syscall.h> -+ SCE_nr_stubs -+}; -+#undef DTRACE_SYSCALL_STUB -+ -+#define DTRACE_SYSCALL_STUB(t, n) \ -+ asmlinkage long dtrace_stub_##n(uintptr_t, uintptr_t, uintptr_t, \ -+ uintptr_t, uintptr_t, uintptr_t, \ -+ uintptr_t); -+#include <asm/dtrace_syscall.h> -+#undef DTRACE_SYSCALL_STUB -+ -+#ifndef CONFIG_ARCH_HAS_SYSCALL_WRAPPER -+typedef asmlinkage long (*dt_sys_call_t)(uintptr_t, uintptr_t, uintptr_t, -+ uintptr_t, uintptr_t, uintptr_t, -+ uintptr_t); -+ -+#define DTRACE_SYSCALL_WRAP_PREFIX "" -+#else -+#include <asm/dtrace_syscall_types.h> -+#endif -+ -+struct dtrace_syscalls { -+ const char *name; -+ dtrace_id_t stsy_entry; -+ dtrace_id_t stsy_return; -+ dt_sys_call_t stsy_underlying; -+ dt_sys_call_t *stsy_tblent; -+}; -+ -+typedef void (*dtrace_systrace_probe_t)(dtrace_id_t, uintptr_t, uintptr_t, -+ uintptr_t, uintptr_t, uintptr_t, -+ uintptr_t, uintptr_t); -+ -+struct systrace_info { -+ dtrace_systrace_probe_t *probep; -+ dtrace_systrace_probe_t stub; -+ dt_sys_call_t syscall; -+ dt_sys_call_t stubs[SCE_nr_stubs]; -+ struct dtrace_syscalls sysent[NR_syscalls]; -+}; -+ -+extern struct systrace_info *dtrace_syscalls_init(void); -+ -+#endif /* _LINUX_DTRACE_SYSCALL_H_ */ -diff --git a/kernel/dtrace/Kconfig b/kernel/dtrace/Kconfig -index 854e4411343f9f7c773bf7fd54349fa46e6de5cb..d04ca0ab7ac9c14f4450927423b30784311a3cbd 100644 ---- a/kernel/dtrace/Kconfig -+++ b/kernel/dtrace/Kconfig -@@ -23,6 +23,15 @@ config DT_CORE - - if DT_CORE - -+config DT_SYSTRACE -+ tristate "System Call Tracing" -+ default m -+ select FTRACE -+ select FTRACE_SYSCALLS -+ help -+ Provides DTrace probes at the entry and exit of all system calls, -+ in the syscall provider. -+ - config DT_DT_TEST - tristate "DTrace Test Probe" - default m -diff --git a/kernel/dtrace/Makefile b/kernel/dtrace/Makefile -index 872785327c3d8d9f1ec0e5555b86fd470e9d1fc2..68fc3861e5d1175006494f12758ff1f0304d10fa 100644 ---- a/kernel/dtrace/Makefile -+++ b/kernel/dtrace/Makefile -@@ -3,6 +3,7 @@ - # - - DT_CORE_ARCH_OBJS = $(addprefix ../../arch/$(SRCARCH)/kernel/, \ -+ dtrace_syscall.o dtrace_syscall_stubs.o \ - dtrace_util.o) - - ifdef CONFIG_DT_CORE --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/dtrace-patches/0007-dtrace-systrace-provider.patch b/sys-kernel/cairn-sources/files/5.10.14/dtrace-patches/0007-dtrace-systrace-provider.patch deleted file mode 100644 index 77058c80bbe1..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/dtrace-patches/0007-dtrace-systrace-provider.patch +++ /dev/null @@ -1,374 +0,0 @@ -From 5d684eeadb4a16c417cfc365180a4b6a9364866f Mon Sep 17 00:00:00 2001 -From: Kris Van Hees <kris.van.hees@oracle.com> -Date: Mon, 19 Nov 2018 17:58:09 +0000 -Subject: [PATCH 07/19] dtrace: systrace provider - -This implements the DTrace systrace provider, which intercepts system -call invocations. - -Signed-off-by: Nick Alcock <nick.alcock@oracle.com> -Signed-off-by: Kris Van Hees <kris.van.hees@oracle.com> -Signed-off-by: Tomas Jedlicka <tomas.jedlicka@oracle.com> -Signed-off-by: Eugene Loh <eugene.loh@oracle.com> -Signed-off-by: David Mc Lean <david.mclean@oracle.com> -Signed-off-by: Vincent Lim <vincent.lim@oracle.com> ---- - dtrace/Makefile | 2 + - dtrace/systrace.h | 33 +++++++ - dtrace/systrace_dev.c | 224 ++++++++++++++++++++++++++++++++++++++++++ - dtrace/systrace_mod.c | 52 ++++++++++ - 4 files changed, 311 insertions(+) - create mode 100644 dtrace/systrace.h - create mode 100644 dtrace/systrace_dev.c - create mode 100644 dtrace/systrace_mod.c - -diff --git a/dtrace/Makefile b/dtrace/Makefile -index 36a4b97b922c4d2baecb0679e41b2d384f56a5b5..b91bc69d38020d8c872483f894349f02a8eb58e6 100644 ---- a/dtrace/Makefile -+++ b/dtrace/Makefile -@@ -3,6 +3,7 @@ - # - - obj-$(CONFIG_DT_CORE) += dtrace.o -+obj-$(CONFIG_DT_SYSTRACE) += systrace.o - obj-$(CONFIG_DT_DT_TEST) += dt_test.o - - dtrace-y := dtrace_mod.o dtrace_dev.o \ -@@ -14,6 +15,7 @@ dtrace-y := dtrace_mod.o dtrace_dev.o \ - dtrace_probe.o dtrace_probe_ctx.o \ - dtrace_ptofapi.o dtrace_predicate.o \ - dtrace_spec.o dtrace_state.o dtrace_util.o -+systrace-y := systrace_mod.o systrace_dev.o - dt_test-y := dt_test_mod.o dt_test_dev.o - - -include arch/$(SRCARCH)/dtrace/Makefile.arch -diff --git a/dtrace/systrace.h b/dtrace/systrace.h -new file mode 100644 -index 0000000000000000000000000000000000000000..832bc613b966c5ecaf53f8c4b602306ccc955d73 ---- /dev/null -+++ b/dtrace/systrace.h -@@ -0,0 +1,33 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Dynamic Tracing for Linux - syscall tracing provider -+ * -+ * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#ifndef _SYSTRACE_H_ -+#define _SYSTRACE_H_ -+ -+#include "dtrace.h" -+ -+extern void systrace_provide(void *, const struct dtrace_probedesc *); -+extern int systrace_enable(void *arg, dtrace_id_t, void *); -+extern void systrace_disable(void *arg, dtrace_id_t, void *); -+extern void systrace_destroy(void *, dtrace_id_t, void *); -+ -+extern dtrace_provider_id_t syscall_id; -+ -+extern int syscall_dev_init(void); -+extern void syscall_dev_exit(void); -+ -+#endif /* _SYSTRACE_H_ */ -diff --git a/dtrace/systrace_dev.c b/dtrace/systrace_dev.c -new file mode 100644 -index 0000000000000000000000000000000000000000..2ff3ba4329a524ba9ad2687da2e83260475b37da ---- /dev/null -+++ b/dtrace/systrace_dev.c -@@ -0,0 +1,224 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: systrace_dev.c -+ * DESCRIPTION: DTrace - systrace provider device driver -+ * -+ * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/dtrace_syscall.h> -+#include <linux/fs.h> -+#include <linux/miscdevice.h> -+#include <asm/unistd.h> -+ -+#include "dtrace.h" -+#include "dtrace_dev.h" -+#include "systrace.h" -+ -+#define SYSTRACE_ARTIFICIAL_FRAMES 1 -+ -+#define SYSTRACE_SHIFT 16 -+#define SYSTRACE_ENTRY(id) ((1 << SYSTRACE_SHIFT) | (id)) -+#define SYSTRACE_RETURN(id) (id) -+#define SYSTRACE_SYSNUM(x) ((int)(x) & ((1 << SYSTRACE_SHIFT) - 1)) -+#define SYSTRACE_ISENTRY(x) ((int)(x) >> SYSTRACE_SHIFT) -+ -+#if ((1 << SYSTRACE_SHIFT) <= NR_syscalls) -+# error 1 << SYSTRACE_SHIFT must exceed number of system calls -+#endif -+ -+static struct systrace_info *systrace_info; -+ -+void systrace_provide(void *arg, const struct dtrace_probedesc *desc) -+{ -+ int failed_count = 0; -+ int i; -+ -+ ASSERT(systrace_info != NULL); -+ -+ if (desc != NULL) -+ return; -+ -+ for (i = 0; i < NR_syscalls; i++) { -+ const char *nm = systrace_info->sysent[i].name; -+ dtrace_id_t id; -+ int sz; -+ size_t wrap_len; -+ -+ if (nm == NULL) -+ continue; -+ -+ if (systrace_info->sysent[i].stsy_underlying == NULL) -+ continue; -+ -+ wrap_len = strlen(DTRACE_SYSCALL_WRAP_PREFIX); -+ sz = strlen(nm); -+ if (sz > wrap_len && -+ memcmp(nm, DTRACE_SYSCALL_WRAP_PREFIX, wrap_len) == 0) { -+ nm += wrap_len; -+ sz -= wrap_len; -+ } -+ if (sz > 4 && memcmp(nm, "sys_", 4) == 0) -+ nm += 4; -+ else if (sz > 5 && memcmp(nm, "stub_", 5) == 0) -+ nm += 5; -+ -+ id = dtrace_probe_lookup(syscall_id, dtrace_kmod->name, nm, -+ "entry"); -+ if (id == DTRACE_IDNONE) { -+ id = dtrace_probe_create(syscall_id, dtrace_kmod->name, -+ nm, "entry", -+ SYSTRACE_ARTIFICIAL_FRAMES, -+ (void *)((uintptr_t)SYSTRACE_ENTRY(i))); -+ if (id == DTRACE_IDNONE) -+ failed_count++; -+ -+ systrace_info->sysent[i].stsy_entry = DTRACE_IDNONE; -+ } -+ -+ id = dtrace_probe_lookup(syscall_id, dtrace_kmod->name, nm, -+ "return"); -+ if (id == DTRACE_IDNONE) { -+ id = dtrace_probe_create(syscall_id, dtrace_kmod->name, -+ nm, "return", -+ SYSTRACE_ARTIFICIAL_FRAMES, -+ (void *)((uintptr_t)SYSTRACE_RETURN(i))); -+ if (id == DTRACE_IDNONE) -+ failed_count++; -+ -+ systrace_info->sysent[i].stsy_return = DTRACE_IDNONE; -+ } -+ } -+ -+ if (failed_count > 0) -+ pr_warn("systrace: Failed to provide %d probes (out of memory)\n", failed_count); -+} -+ -+static dt_sys_call_t get_intercept(int sysnum) -+{ -+ switch (sysnum) { -+ default: -+ return systrace_info->syscall; -+#define DTRACE_SYSCALL_STUB(t, n) \ -+ case __NR_##n: \ -+ return systrace_info->stubs[SCE_##t]; -+#include <asm/dtrace_syscall.h> -+#undef DTRACE_SYSCALL_STUB -+ } -+} -+ -+int systrace_enable(void *arg, dtrace_id_t id, void *parg) -+{ -+ int sysnum = SYSTRACE_SYSNUM((uintptr_t)parg); -+ struct dtrace_syscalls *sc = &systrace_info->sysent[sysnum]; -+ int enabled = sc->stsy_entry != DTRACE_IDNONE || -+ sc->stsy_return != DTRACE_IDNONE; -+ dt_sys_call_t intercept = get_intercept(sysnum); -+ -+ if (!enabled) { -+ if (cmpxchg(sc->stsy_tblent, sc->stsy_underlying, -+ intercept) != sc->stsy_underlying) -+ return 1; -+ } else -+ ASSERT(*sc->stsy_tblent == intercept); -+ -+ if (SYSTRACE_ISENTRY((uintptr_t)parg)) -+ sc->stsy_entry = id; -+ else -+ sc->stsy_return = id; -+ -+ return 0; -+} -+ -+void systrace_disable(void *arg, dtrace_id_t id, void *parg) -+{ -+ int sysnum = SYSTRACE_SYSNUM((uintptr_t)parg); -+ struct dtrace_syscalls *sc = &systrace_info->sysent[sysnum]; -+ int enabled = -+ (sc->stsy_entry != DTRACE_IDNONE ? 1 : 0) + -+ (sc->stsy_return != DTRACE_IDNONE ? 1 : 0); -+ dt_sys_call_t intercept = get_intercept(sysnum); -+ -+ /* -+ * Every syscall can have 2 probes associated with it. We need to keep -+ * the interceptor in place until the last probe is getting disabled. -+ */ -+ if (enabled == 1) -+ (void)cmpxchg(sc->stsy_tblent, intercept, sc->stsy_underlying); -+ -+ if (SYSTRACE_ISENTRY((uintptr_t)parg)) -+ sc->stsy_entry = DTRACE_IDNONE; -+ else -+ sc->stsy_return = DTRACE_IDNONE; -+} -+ -+void systrace_destroy(void *arg, dtrace_id_t id, void *parg) -+{ -+ int sysnum = SYSTRACE_SYSNUM((uintptr_t)parg); -+ -+ /* -+ * Nothing to be done here - just ensure our probe has been disabled. -+ */ -+ if (SYSTRACE_ISENTRY((uintptr_t)parg)) -+ ASSERT(systrace_info->sysent[sysnum].stsy_entry == -+ DTRACE_IDNONE); -+ else -+ ASSERT(systrace_info->sysent[sysnum].stsy_return == -+ DTRACE_IDNONE); -+} -+ -+static int systrace_open(struct inode *inode, struct file *file) -+{ -+ return -EAGAIN; -+} -+ -+static int systrace_close(struct inode *inode, struct file *file) -+{ -+ return 0; -+} -+ -+static const struct file_operations systrace_fops = { -+ .owner = THIS_MODULE, -+ .open = systrace_open, -+ .release = systrace_close, -+}; -+ -+static struct miscdevice systrace_dev = { -+ .minor = DT_DEV_SYSTRACE_MINOR, -+ .name = "systrace", -+ .nodename = "dtrace/provider/systrace", -+ .fops = &systrace_fops, -+}; -+ -+int syscall_dev_init(void) -+{ -+ int ret = 0; -+ -+ systrace_info = dtrace_syscalls_init(); -+ -+ ret = misc_register(&systrace_dev); -+ if (ret) -+ pr_err("%s: Can't register misc device %d\n", -+ systrace_dev.name, systrace_dev.minor); -+ -+ *(systrace_info->probep) = (dtrace_systrace_probe_t)dtrace_probe; -+ -+ return ret; -+} -+ -+void syscall_dev_exit(void) -+{ -+ *(systrace_info->probep) = systrace_info->stub; -+ -+ misc_deregister(&systrace_dev); -+} -diff --git a/dtrace/systrace_mod.c b/dtrace/systrace_mod.c -new file mode 100644 -index 0000000000000000000000000000000000000000..d286f7d9d47aba259de63da3b0391a4f0075906c ---- /dev/null -+++ b/dtrace/systrace_mod.c -@@ -0,0 +1,52 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: systrace_mod.c -+ * DESCRIPTION: DTrace - systrace provider kernel module -+ * -+ * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/module.h> -+ -+#include "dtrace.h" -+#include "dtrace_dev.h" -+#include "systrace.h" -+ -+MODULE_AUTHOR("Kris Van Hees (kris.van.hees@oracle.com)"); -+MODULE_DESCRIPTION("System Call Tracing"); -+MODULE_VERSION("v0.1"); -+MODULE_LICENSE("GPL"); -+ -+static const struct dtrace_pattr syscall_attr = { -+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA }, -+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA }, -+}; -+ -+static struct dtrace_pops syscall_pops = { -+ .dtps_provide = systrace_provide, -+ .dtps_provide_module = NULL, -+ .dtps_destroy_module = NULL, -+ .dtps_enable = systrace_enable, -+ .dtps_disable = systrace_disable, -+ .dtps_suspend = NULL, -+ .dtps_resume = NULL, -+ .dtps_getargdesc = NULL, -+ .dtps_getargval = NULL, -+ .dtps_usermode = NULL, -+ .dtps_destroy = systrace_destroy -+}; -+ -+DT_PROVIDER_MODULE(syscall, DTRACE_PRIV_USER) --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/dtrace-patches/0008-dtrace-sdt-provider-core-components.patch b/sys-kernel/cairn-sources/files/5.10.14/dtrace-patches/0008-dtrace-sdt-provider-core-components.patch deleted file mode 100644 index f2045b15e4d8..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/dtrace-patches/0008-dtrace-sdt-provider-core-components.patch +++ /dev/null @@ -1,3112 +0,0 @@ -From 0bf2a2a85df13740247a26e7b217f39eda237b0c Mon Sep 17 00:00:00 2001 -From: Kris Van Hees <kris.van.hees@oracle.com> -Date: Mon, 19 Nov 2018 22:03:10 +0000 -Subject: [PATCH 08/19] dtrace: sdt provider core components - -This implements the core (linked-in) machinery needed for SDT -tracepoints: - - - generate empty stub function calls __dtrace_probe_* for each probe - point and perf-event probe point, and record their section-relative - offset in tables in special symbols in the output; calls to - is-enabling probes (conditionals of the form - if (DTRACE_FOO_ENABLED(probe-name))) are translated as well - - similarly record the names and types of arguments to probes in - special sections - - parse both of these at load time, and substitute in nops over the top - of the stub functions, remembering their locations: is-enabled probes - get 0-returns patched over the top - - on probe enabling, patch invalid-operation traps over the top of - those stub functions; handle these by calling the probe, then return - as if the trap had never happened - -The provider module itself is added in the next commit. - -Signed-off-by: Nick Alcock <nick.alcock@oracle.com> -Signed-off-by: Kris Van Hees <kris.van.hees@oracle.com> -Signed-off-by: Tomas Jedlicka <tomas.jedlicka@oracle.com> -Signed-off-by: Eugene Loh <eugene.loh@oracle.com> -Signed-off-by: David Mc Lean <david.mclean@oracle.com> -Signed-off-by: Vincent Lim <vincent.lim@oracle.com> ---- - .gitignore | 6 + - Makefile | 1 + - arch/x86/dtrace/include/dtrace/sdt_arch.h | 28 ++ - arch/x86/include/asm/dtrace_arch.h | 8 +- - arch/x86/include/asm/dtrace_sdt_arch.h | 11 + - arch/x86/include/asm/dtrace_util.h | 13 + - arch/x86/include/asm/spinlock.h | 1 + - arch/x86/include/asm/text-patching.h | 1 + - arch/x86/kernel/alternative.c | 2 +- - arch/x86/kernel/dtrace_sdt.c | 76 +++ - arch/x86/kernel/dtrace_util.c | 214 +++++++- - arch/x86/kernel/vmlinux.lds.S | 3 +- - include/asm-generic/vmlinux.lds.h | 16 + - include/linux/dtrace_os.h | 3 + - include/linux/dtrace_sdt.h | 32 ++ - include/linux/module.h | 5 + - include/linux/sdt.h | 191 +++++++ - include/linux/sdt_internal.h | 276 ++++++++++ - include/linux/tracepoint.h | 8 +- - kernel/dtrace/Kconfig | 16 + - kernel/dtrace/Makefile | 3 +- - kernel/dtrace/dtrace_os.c | 83 +++ - kernel/dtrace/dtrace_sdt_core.c | 364 ++++++++++++++ - kernel/module.c | 14 + - scripts/.gitignore | 1 + - scripts/Makefile | 6 + - scripts/Makefile.modfinal | 52 +- - scripts/dtrace_sdt.sh | 588 ++++++++++++++++++++++ - scripts/kmodsdt.c | 410 +++++++++++++++ - scripts/link-vmlinux.sh | 69 ++- - scripts/mod/modpost.c | 19 +- - 31 files changed, 2500 insertions(+), 20 deletions(-) - create mode 100644 arch/x86/dtrace/include/dtrace/sdt_arch.h - create mode 100644 arch/x86/include/asm/dtrace_sdt_arch.h - create mode 100644 arch/x86/kernel/dtrace_sdt.c - create mode 100644 include/linux/dtrace_sdt.h - create mode 100644 include/linux/sdt.h - create mode 100644 include/linux/sdt_internal.h - create mode 100644 kernel/dtrace/dtrace_sdt_core.c - create mode 100755 scripts/dtrace_sdt.sh - create mode 100644 scripts/kmodsdt.c - -diff --git a/.gitignore b/.gitignore -index 1c10cd7ce03399a97367d56dbefd66dea1823859..13954b4624a9009197acbd538f654dbdf54affde 100644 ---- a/.gitignore -+++ b/.gitignore -@@ -158,3 +158,9 @@ x509.genkey - - # Documentation toolchain - sphinx_*/ -+# -+# Generated DTrace SDT files -+# -+*.sdtinfo.c -+*.sdtinfo.h -+*.sdtstub.S -diff --git a/Makefile b/Makefile -index 4b25be692ac15ae9f6eb52c4a5f135da70598b05..e3f113b646818a2250cb6a14203b12e3b38ce26c 100644 ---- a/Makefile -+++ b/Makefile -@@ -1883,6 +1883,7 @@ clean: $(clean-dirs) - -o -name '*.dtb' -o -name '*.dtb.S' -o -name '*.dt.yaml' \ - -o -name '*.dwo' -o -name '*.lst' \ - -o -name '*.su' -o -name '*.mod' \ -+ -o -name '*.sdtinfo.c' -o -name '*.sdtinfo.h' -o -name '*.sdtstub.S' \ - -o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \ - -o -name '*.lex.c' -o -name '*.tab.[ch]' \ - -o -name '*.asn1.[ch]' \ -diff --git a/arch/x86/dtrace/include/dtrace/sdt_arch.h b/arch/x86/dtrace/include/dtrace/sdt_arch.h -new file mode 100644 -index 0000000000000000000000000000000000000000..d8616b44079b57f41466cea603ecc7b9be0d13e6 ---- /dev/null -+++ b/arch/x86/dtrace/include/dtrace/sdt_arch.h -@@ -0,0 +1,28 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Dynamic Tracing for Linux - SDT Implementation defines -+ * -+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _X86_64_SDT_ARCH_H -+#define _X86_64_SDT_ARCH_H -+ -+#define SDT_AFRAMES 4 -+ -+#endif /* _X86_64_SDT_ARCH_H */ -diff --git a/arch/x86/include/asm/dtrace_arch.h b/arch/x86/include/asm/dtrace_arch.h -index 74e27f08a873c9cd3ed329d911e8e18505ae5b62..88beb8e4db0b545085974560a9383a703bb5a790 100644 ---- a/arch/x86/include/asm/dtrace_arch.h -+++ b/arch/x86/include/asm/dtrace_arch.h -@@ -12,16 +12,22 @@ - - typedef uint8_t asm_instr_t; - -+#define ASM_CALL_SIZE 5 -+ - typedef int (*prov_exit_f)(void); - - /* - * Structure to hold DTrace specific information about modules (including the - * core kernel module). Note that each module (and the main kernel) already -- * has one field that relates to probing: -+ * has three fields that relate to probing: -+ * - sdt_probes: description of SDT probes in the module -+ * - sdt_probec: number of SDT probes in the module - * - pdata: pointer to a dtrace_module struct (for DTrace) - */ - struct dtrace_module { - int enabled_cnt; -+ size_t sdt_probe_cnt; -+ size_t fbt_probe_cnt; - prov_exit_f prov_exit; /* Called with module_mutex held */ - }; - -diff --git a/arch/x86/include/asm/dtrace_sdt_arch.h b/arch/x86/include/asm/dtrace_sdt_arch.h -new file mode 100644 -index 0000000000000000000000000000000000000000..59f57cb489abd5499bdf3a1ab5961181623aa789 ---- /dev/null -+++ b/arch/x86/include/asm/dtrace_sdt_arch.h -@@ -0,0 +1,11 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+ -+/* Copyright (C) 2016 Oracle, Inc. */ -+ -+#ifndef _X86_DTRACE_SDT_ARCH_H -+#define _X86_DTRACE_SDT_ARCH_H -+ -+#define __DTRACE_SDT_ISENABLED_PROTO void -+#define __DTRACE_SDT_ISENABLED_ARGS -+ -+#endif /* _X86_DTRACE_SDT_ARCH_H */ -diff --git a/arch/x86/include/asm/dtrace_util.h b/arch/x86/include/asm/dtrace_util.h -index 4d9843bbc95b92dcc3c20d4aa1d2b762b7376d91..ce28bf42a59daeeb9070a42c37e98cb5519ad814 100644 ---- a/arch/x86/include/asm/dtrace_util.h -+++ b/arch/x86/include/asm/dtrace_util.h -@@ -6,11 +6,24 @@ - #ifndef _X86_DTRACE_UTIL_H - #define _X86_DTRACE_UTIL_H - -+#define DTRACE_INVOP_NOPS 0x0f /* 5-byte NOP sequence */ -+#define DTRACE_INVOP_MOV_RSP_RBP 0x48 /* mov %rsp, %rbp = 48 89 e5 */ -+#define DTRACE_INVOP_PUSH_BP 0x55 /* push %rbp = 55 */ -+#define DTRACE_INVOP_NOP 0x90 /* nop = 90 */ -+#define DTRACE_INVOP_LEAVE 0xc9 /* leave = c9 */ -+#define DTRACE_INVOP_RET 0xc3 /* ret = c3 */ -+ - #ifndef __ASSEMBLY__ - - #include <asm/dtrace_arch.h> - #include <asm/ptrace.h> - -+extern int dtrace_invop_add(uint8_t (*func)(struct pt_regs *)); -+extern void dtrace_invop_remove(uint8_t (*func)(struct pt_regs *)); -+ -+extern void dtrace_invop_enable(asm_instr_t *, asm_instr_t); -+extern void dtrace_invop_disable(asm_instr_t *, asm_instr_t); -+ - #endif - - #endif /* _X86_DTRACE_UTIL_H */ -diff --git a/arch/x86/include/asm/spinlock.h b/arch/x86/include/asm/spinlock.h -index 5b6bc7016c223e7496fc2645ae8b3434ef83b96b..79e017f90c6040c6927ab0f2485ba45b0401b1bd 100644 ---- a/arch/x86/include/asm/spinlock.h -+++ b/arch/x86/include/asm/spinlock.h -@@ -9,6 +9,7 @@ - #include <linux/compiler.h> - #include <asm/paravirt.h> - #include <asm/bitops.h> -+#include <linux/sdt.h> - - /* - * Your basic SMP spinlocks, allowing only a single CPU anywhere -diff --git a/arch/x86/include/asm/text-patching.h b/arch/x86/include/asm/text-patching.h -index b7421780e4e92959689646cb425485c9deeabfc3..127a59c41e6d51f4bea3297403e9481e923955e4 100644 ---- a/arch/x86/include/asm/text-patching.h -+++ b/arch/x86/include/asm/text-patching.h -@@ -25,6 +25,7 @@ static inline void apply_paravirt(struct paravirt_patch_site *start, - */ - #define POKE_MAX_OPCODE_SIZE 5 - -+extern void add_nops(void *insns, unsigned int len); - extern void text_poke_early(void *addr, const void *opcode, size_t len); - - /* -diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c -index 2400ad62f330b9f518b3bcfa3462f5fd2e659e78..389c3870ce48534b92c76d3b9fce606394755160 100644 ---- a/arch/x86/kernel/alternative.c -+++ b/arch/x86/kernel/alternative.c -@@ -256,7 +256,7 @@ void __init arch_init_ideal_nops(void) - } - - /* Use this to add nops to a buffer, then text_poke the whole buffer. */ --static void __init_or_module add_nops(void *insns, unsigned int len) -+void __init_or_module add_nops(void *insns, unsigned int len) - { - while (len > 0) { - unsigned int noplen = len; -diff --git a/arch/x86/kernel/dtrace_sdt.c b/arch/x86/kernel/dtrace_sdt.c -new file mode 100644 -index 0000000000000000000000000000000000000000..31bb962573fb15443a2e5d4a7fbb0516cad29262 ---- /dev/null -+++ b/arch/x86/kernel/dtrace_sdt.c -@@ -0,0 +1,76 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_sdt.c -+ * DESCRIPTION: Dynamic Tracing: SDT registration code (arch-specific) -+ * -+ * Copyright (c) 2010, 2020, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/memory.h> -+#include <linux/module.h> -+#include <linux/dtrace_os.h> -+#include <linux/sdt.h> -+#include <linux/slab.h> -+#include <linux/sync_core.h> -+#include <linux/vmalloc.h> -+#include <asm/nmi.h> -+#include <asm/nops.h> -+#include <asm/dtrace_arch.h> -+#include <asm/text-patching.h> -+ -+static uint8_t nops[ASM_CALL_SIZE]; -+static uint8_t movs[ASM_CALL_SIZE]; -+ -+#define DT_OP_REX_RAX 0x48 -+#define DT_OP_XOR_EAX_0 0x33 -+#define DT_OP_XOR_EAX_1 0xc0 -+ -+/* This code is based on apply_alternatives and text_poke_early. It needs to -+ * run before SMP is initialized in order to avoid SMP problems with patching -+ * code that might be accessed on another CPU. -+ */ -+void __init_or_module dtrace_sdt_nop_multi(asm_instr_t **addrs, -+ int *is_enabled, int cnt) -+{ -+ int i; -+ asm_instr_t *addr; -+ unsigned long flags; -+ -+ stop_nmi(); -+ local_irq_save(flags); -+ -+ for (i = 0; i < cnt; i++) { -+ addr = addrs[i]; -+ if (likely(!is_enabled[i])) -+ memcpy(addr, nops, sizeof(nops)); -+ else -+ memcpy(addr, movs, sizeof(movs)); -+ } -+ -+ sync_core(); -+ local_irq_restore(flags); -+ restart_nmi(); -+} -+ -+void __init dtrace_sdt_init_arch(void) -+{ -+ /* -+ * A little unusual, but potentially necessary. While we could use a -+ * single NOP sequence of length ASM_CALL_SIZE, we need to consider the -+ * fact that when a SDT probe point is enabled, a single invalid opcode -+ * is written on the first byte of this NOP sequence. By using a -+ * sequence of a 1-byte NOP, followed by a (ASM_CALL_SIZE - 1) byte NOP -+ * sequence, we play it pretty safe. -+ */ -+ add_nops(nops, 1); -+ add_nops(nops + 1, ASM_CALL_SIZE - 1); -+ -+ /* -+ * Is-enabled probe points contain an "xor %rax, %rax" when disabled. -+ */ -+ movs[0] = DT_OP_REX_RAX; -+ movs[1] = DT_OP_XOR_EAX_0; -+ movs[2] = DT_OP_XOR_EAX_1; -+ add_nops(movs + 3, ASM_CALL_SIZE - 3); -+} -diff --git a/arch/x86/kernel/dtrace_util.c b/arch/x86/kernel/dtrace_util.c -index d3d552c062f7ea425567cdb867b31f65d0242cac..f138fd62f555c8d6b3599287b18846fe8017db53 100644 ---- a/arch/x86/kernel/dtrace_util.c -+++ b/arch/x86/kernel/dtrace_util.c -@@ -61,6 +61,13 @@ void dtrace_handle_badaddr(struct pt_regs *regs) - dtrace_skip_instruction(regs); - } - -+struct dtrace_invop_hdlr { -+ uint8_t (*dtih_func)(struct pt_regs *); -+ struct dtrace_invop_hdlr *dtih_next; -+}; -+ -+static struct dtrace_invop_hdlr *dtrace_invop_hdlrs; -+ - /* - * Trap notification handler. - */ -@@ -68,6 +75,7 @@ int dtrace_die_notifier(struct notifier_block *nb, unsigned long val, - void *args) - { - struct die_args *dargs = args; -+ int orig_trapnr = 0; - - switch (val) { - case DIE_PAGE_FAULT: { -@@ -79,12 +87,141 @@ int dtrace_die_notifier(struct notifier_block *nb, unsigned long val, - return NOTIFY_OK | NOTIFY_STOP_MASK; - } - case DIE_GPF: { -- if (!DTRACE_CPUFLAG_ISSET(CPU_DTRACE_NOFAULT)) -+ /* -+ * This gets messy... For one, some versions of Xen deliver -+ * the invalid opcode generated by the LOCK prefix (0xf0) as a -+ * GP fault rather than a UD fault. So, we need to figure out -+ * whether the GP we're processing here is one of those -+ * misreported faults. -+ * -+ * But, it is possible that the instruction that caused the -+ * fault (0xf0) gets overwritten by a different CPU with the -+ * original valid opcode before we get to look at it here, -+ * which makes it kind of hard to recognize. -+ * -+ * So... we're going to assume that a GP fault that gets -+ * triggered for the LOCK prefix opcode (0xf0) *or* for an -+ * opcode that can get overwritten with the LOCK prefix for -+ * probing is actually a UD fault. -+ * -+ * If we are wrong, the handlers will simply see a fault that -+ * isn't theirs, and return without consuming it. And in that -+ * case, the kernel will report a UD fault that may have been -+ * a real GP fault... Sorry. -+ */ -+ asm_instr_t opc = *(asm_instr_t *)dargs->regs->ip; -+ -+ if (opc != 0xf0 && opc != 0x55 && opc != 0xc3) { -+ if (!DTRACE_CPUFLAG_ISSET(CPU_DTRACE_NOFAULT)) -+ return NOTIFY_DONE; -+ -+ dtrace_handle_badaddr(dargs->regs); -+ -+ return NOTIFY_OK | NOTIFY_STOP_MASK; -+ } -+ -+ /* -+ * ... and instead treat them as the SDT probe point traps that -+ * they are. -+ */ -+ orig_trapnr = dargs->trapnr; -+ dargs->trapnr = 6; -+ } -+ /* fallthrough */ -+ case DIE_TRAP: { -+ struct dtrace_invop_hdlr *hdlr; -+ int rval = 0; -+ -+ if (dargs->trapnr != 6) - return NOTIFY_DONE; - -- dtrace_handle_badaddr(dargs->regs); -+ for (hdlr = dtrace_invop_hdlrs; hdlr != NULL; -+ hdlr = hdlr->dtih_next) { -+ rval = hdlr->dtih_func(dargs->regs); -+ if (rval != 0) -+ break; -+ } - -- return NOTIFY_OK | NOTIFY_STOP_MASK; -+ switch (rval) { -+ case DTRACE_INVOP_NOPS: -+ /* -+ * SDT probe points are encoded as either: -+ * - a 1-byte NOP followed by a multi-byte NOP -+ * - a multi-byte code sequence (to set AX to 0), -+ * followed by a multi-byte NOP -+ * In both cases, the total length of the probe point -+ * instruction is ASM_CALL_SITE bytes, so we can safely -+ * skip that number of bytes here. -+ */ -+ dargs->regs->ip += ASM_CALL_SIZE; -+ return NOTIFY_OK | NOTIFY_STOP_MASK; -+ case DTRACE_INVOP_MOV_RSP_RBP: -+ case DTRACE_INVOP_NOP: -+ case DTRACE_INVOP_PUSH_BP: -+ case DTRACE_INVOP_RET: -+ return notifier_from_errno(-rval); -+ default: -+ /* -+ * This must not have been a trap triggered from a -+ * probe point. Let someone else deal with it... -+ * -+ * If we got here because of a GPF that we thought -+ * was a UD (due to a bug in some versions of Xen), -+ * undo our change to dargs->trapnr. -+ */ -+ if (unlikely(orig_trapnr)) -+ dargs->trapnr = orig_trapnr; -+ -+ return NOTIFY_DONE; -+ } -+ } -+ case DIE_INT3: { -+ struct dtrace_invop_hdlr *hdlr; -+ int rval = 0; -+ -+ /* -+ * Let's assume that this is a DTrace probe firing, so we need -+ * to adjust the IP (to be consistent with #UD processing) so -+ * that it reflects the address of the #BP rather than the -+ * following intruction. -+ * -+ * If it turns out that this was not DTrace related, we'll have -+ * to reverse this adjustment. -+ */ -+ dargs->regs->ip--; -+ for (hdlr = dtrace_invop_hdlrs; hdlr != NULL; -+ hdlr = hdlr->dtih_next) { -+ rval = hdlr->dtih_func(dargs->regs); -+ if (rval != 0) -+ break; -+ } -+ -+ switch (rval) { -+ case DTRACE_INVOP_NOPS: -+ /* -+ * SDT probe points are encoded as either: -+ * - a 1-byte NOP followed by a multi-byte NOP -+ * - a multi-byte code sequence (to set AX to 0), -+ * followed by a multi-byte NOP -+ * In both cases, the total length of the probe point -+ * instruction is ASM_CALL_SITE bytes, so we can safely -+ * skip that number of bytes here. -+ */ -+ dargs->regs->ip += ASM_CALL_SIZE; -+ return NOTIFY_OK | NOTIFY_STOP_MASK; -+ case DTRACE_INVOP_MOV_RSP_RBP: -+ case DTRACE_INVOP_NOP: -+ case DTRACE_INVOP_PUSH_BP: -+ case DTRACE_INVOP_RET: -+ return notifier_from_errno(-rval); -+ default: -+ /* -+ * This must not have been a trap triggered from a -+ * probe point. Re-adjust the instruction pointer -+ * and let someone else deal with it... -+ */ -+ dargs->regs->ip++; -+ } - } - /* fallthrough */ - default: -@@ -92,6 +229,77 @@ int dtrace_die_notifier(struct notifier_block *nb, unsigned long val, - } - } - -+/* -+ * Add an INVOP trap handler. -+ */ -+int dtrace_invop_add(uint8_t (*func)(struct pt_regs *)) -+{ -+ struct dtrace_invop_hdlr *hdlr; -+ -+ hdlr = kmalloc(sizeof(struct dtrace_invop_hdlr), GFP_KERNEL); -+ if (hdlr == NULL) { -+ pr_warn("Failed to add invop handler: out of memory\n"); -+ return -ENOMEM; -+ } -+ -+ hdlr->dtih_func = func; -+ hdlr->dtih_next = dtrace_invop_hdlrs; -+ dtrace_invop_hdlrs = hdlr; -+ -+ return 0; -+} -+EXPORT_SYMBOL(dtrace_invop_add); -+ -+/* -+ * Remove an INVOP trap handler. -+ */ -+void dtrace_invop_remove(uint8_t (*func)(struct pt_regs *)) -+{ -+ struct dtrace_invop_hdlr *hdlr = dtrace_invop_hdlrs, *prev = NULL; -+ -+ for (;;) { -+ if (hdlr == NULL) -+ return; -+ -+ if (hdlr->dtih_func == func) -+ break; -+ -+ prev = hdlr; -+ hdlr = hdlr->dtih_next; -+ } -+ -+ if (prev == NULL) -+ dtrace_invop_hdlrs = hdlr->dtih_next; -+ else -+ prev->dtih_next = hdlr->dtih_next; -+ -+ kfree(hdlr); -+} -+EXPORT_SYMBOL(dtrace_invop_remove); -+ -+/* -+ * Enable an INVOP-based probe, i.e. ensure that an INVOP trap is triggered at -+ * the specified address. -+ */ -+void dtrace_invop_enable(asm_instr_t *addr, asm_instr_t opcode) -+{ -+ mutex_lock(&text_mutex); -+ text_poke(addr, ((unsigned char []){opcode}), 1); -+ mutex_unlock(&text_mutex); -+} -+EXPORT_SYMBOL(dtrace_invop_enable); -+ -+/* -+ * Disable an INVOP-based probe. -+ */ -+void dtrace_invop_disable(asm_instr_t *addr, asm_instr_t opcode) -+{ -+ mutex_lock(&text_mutex); -+ text_poke(addr, ((unsigned char []){opcode}), 1); -+ mutex_unlock(&text_mutex); -+} -+EXPORT_SYMBOL(dtrace_invop_disable); -+ - static inline int dtrace_bad_address(void *addr) - { - unsigned long dummy; -diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S -index bf9e0adb5b7ec25fd078fcf85f4c2c38f409175d..970b6cd011f69e33dcefeb4e5efa4214ab32467f 100644 ---- a/arch/x86/kernel/vmlinux.lds.S -+++ b/arch/x86/kernel/vmlinux.lds.S -@@ -473,7 +473,8 @@ INIT_PER_CPU(irq_stack_backing_store); - /* - * Build-time check on the image size: - */ --. = ASSERT((_end - _text <= KERNEL_IMAGE_SIZE), -+. = ASSERT(((_end < _text) ? (_end < KERNEL_IMAGE_SIZE) -+ : (_end - _text <= KERNEL_IMAGE_SIZE)), - "kernel image bigger than KERNEL_IMAGE_SIZE"); - - #ifdef CONFIG_SMP -diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h -index b2b3d81b1535a5abbf6803f3dfbb29058a979bc4..7d1517f97db21f0821d5dedc866a40dc71865453 100644 ---- a/include/asm-generic/vmlinux.lds.h -+++ b/include/asm-generic/vmlinux.lds.h -@@ -214,6 +214,20 @@ - #define ERROR_INJECT_WHITELIST() - #endif - -+#ifdef CONFIG_DTRACE -+#define DTRACE_SDT_NAMES() . = ALIGN(8); \ -+ __start_dtrace_sdt_names = .; \ -+ KEEP(*(_dtrace_sdt_names)) \ -+ __stop_dtrace_sdt_names = .; -+#define DTRACE_SDT_ARGS() . = ALIGN(8); \ -+ __start_dtrace_sdt_args = .; \ -+ KEEP(*(_dtrace_sdt_args)) \ -+ __stop_dtrace_sdt_args = .; -+#else -+#define DTRACE_SDT_NAMES() -+#define DTRACE_SDT_ARGS() -+#endif -+ - #ifdef CONFIG_EVENT_TRACING - #define FTRACE_EVENTS() . = ALIGN(8); \ - __start_ftrace_events = .; \ -@@ -721,6 +735,8 @@ - FTRACE_EVENTS() \ - TRACE_SYSCALLS() \ - KPROBE_BLACKLIST() \ -+ DTRACE_SDT_NAMES() \ -+ DTRACE_SDT_ARGS() \ - ERROR_INJECT_WHITELIST() \ - MEM_DISCARD(init.rodata) \ - CLK_OF_TABLES() \ -diff --git a/include/linux/dtrace_os.h b/include/linux/dtrace_os.h -index 5bcd77e08a14e8502cbadb53004dbbeb711dc953..f2921ce039a76dd29f93c8183073b8d750681fe6 100644 ---- a/include/linux/dtrace_os.h -+++ b/include/linux/dtrace_os.h -@@ -25,6 +25,9 @@ extern void __init dtrace_os_init(void); - extern void __init dtrace_psinfo_os_init(void); - extern void __init dtrace_task_os_init(void); - -+extern void *dtrace_alloc_text(struct module *, unsigned long); -+extern void dtrace_free_text(void *); -+ - extern void dtrace_mod_pdata_alloc(struct module *); - extern void dtrace_mod_pdata_free(struct module *); - extern int dtrace_destroy_prov(struct module *); -diff --git a/include/linux/dtrace_sdt.h b/include/linux/dtrace_sdt.h -new file mode 100644 -index 0000000000000000000000000000000000000000..3a4d608bc3fa3de46fded719352e12e9b2f9f2f0 ---- /dev/null -+++ b/include/linux/dtrace_sdt.h -@@ -0,0 +1,32 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+#ifndef _DTRACE_SDT_H_ -+#define _DTRACE_SDT_H_ -+ -+#ifdef CONFIG_DTRACE -+#include <linux/module.h> -+#include <asm/dtrace_arch.h> -+ -+extern void __init dtrace_sdt_init(void); -+extern void __init dtrace_sdt_register(struct module *); -+extern void dtrace_sdt_register_module(struct module *, -+ void *sdt_names_addr, size_t, -+ void *sdt_args_addr, size_t); -+extern void dtrace_sdt_exit(void); -+ -+/* -+ * Functions to be defined in arch/<arch>/kernel/dtrace_sdt.c -+ */ -+extern void __init_or_module dtrace_sdt_nop_multi(asm_instr_t **, int *, int); -+ -+#ifdef CONFIG_X86_64 -+extern void __init dtrace_sdt_init_arch(void); -+#else -+#define dtrace_sdt_init_arch() -+#endif /* CONFIG_X86_64 */ -+ -+#endif /* CONFIG_DTRACE */ -+#endif /* _DTRACE_SDT_H_ */ -diff --git a/include/linux/module.h b/include/linux/module.h -index 44915ed85337f8ef9931afaee5b78f9961ac112e..7abbaeb5d659fa3711c0cd845219366894152ffc 100644 ---- a/include/linux/module.h -+++ b/include/linux/module.h -@@ -30,6 +30,8 @@ - #include <linux/percpu.h> - #include <asm/module.h> - -+#include <linux/sdt.h> -+ - /* Not Yet Implemented */ - #define MODULE_SUPPORTED_DEVICE(name) - -@@ -513,8 +515,11 @@ struct module { - #endif - - #ifdef CONFIG_DTRACE -+ struct sdt_probedesc *sdt_probes; -+ unsigned int sdt_probec; - void *pdata; - #endif -+ - #ifdef CONFIG_MODULE_UNLOAD - /* What modules depend on me? */ - struct list_head source_list; -diff --git a/include/linux/sdt.h b/include/linux/sdt.h -new file mode 100644 -index 0000000000000000000000000000000000000000..8efb63cff1ac608f809fe8f4dc55409099d23543 ---- /dev/null -+++ b/include/linux/sdt.h -@@ -0,0 +1,191 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+#ifndef _LINUX_SDT_H_ -+#define _LINUX_SDT_H_ -+ -+#include <linux/sdt_internal.h> -+ -+#if IS_ENABLED(CONFIG_DT_SDT) -+ -+#include <asm/dtrace_sdt_arch.h> -+#include <linux/stringify.h> -+ -+#define DTRACE_PROBE(name, ...) { \ -+ extern int __dtrace_probe_##name(__DTRACE_TYPE_APPLY_DEFAULT(__DTRACE_UINTPTR_EACH, void, ## __VA_ARGS__)); \ -+ (void)__dtrace_probe_##name(__DTRACE_ARG_APPLY(__DTRACE_UINTCAST_EACH, ## __VA_ARGS__)); \ -+ asm volatile(".pushsection _dtrace_sdt_names, \"a\", @progbits\n" \ -+ ".ascii \"" __stringify(name) "\"\n" \ -+ ".byte 0\n" \ -+ ".popsection\n" \ -+ ".pushsection _dtrace_sdt_args, \"a\", @progbits\n" \ -+ __DTRACE_TYPE_APPLY_NOCOMMA(__DTRACE_TYPE_EACH, ## __VA_ARGS__) \ -+ ".byte 0\n" \ -+ ".popsection\n"); \ -+} -+ -+#define DTRACE_PROBE_ENABLED(name) unlikely(({ \ -+ extern int __dtrace_isenabled_##name(__DTRACE_SDT_ISENABLED_PROTO); \ -+ __dtrace_isenabled_##name(__DTRACE_SDT_ISENABLED_ARGS); \ -+})) -+ -+#ifdef CONFIG_DT_SDT_PERF -+ -+#define __DTRACE_UINTPTR_CAST_EACH(x) ({ \ -+ union { \ -+ typeof((x)) __val; \ -+ unsigned char __c; \ -+ unsigned short __s; \ -+ unsigned int __i; \ -+ unsigned long __l; \ -+ unsigned long long __ll; } __u = { .__val = (x) }; \ -+ __builtin_choose_expr(sizeof(__u.__val) == sizeof(__u.__c), __u.__c, \ -+ __builtin_choose_expr(sizeof(__u.__val) == sizeof(__u.__s), __u.__s, \ -+ __builtin_choose_expr(sizeof(__u.__val) == sizeof(__u.__i), __u.__i, \ -+ __builtin_choose_expr(sizeof(__u.__val) == sizeof(__u.__l), __u.__l, \ -+ __builtin_choose_expr(sizeof(__u.__val) == sizeof(__u.__ll), __u.__ll, \ -+ (uintptr_t)&(__u.__val)))))); }) -+ -+#define DTRACE_PROBE_TRACEPOINT(name, ...) { \ -+ extern void __dtrace_probe___perf_##name(__DTRACE_APPLY(__DTRACE_UINTPTR_EACH, ## __VA_ARGS__)); \ -+ __dtrace_probe___perf_##name(__DTRACE_APPLY(__DTRACE_UINTPTR_CAST_EACH, ## __VA_ARGS__)); \ -+} -+ -+#define DTRACE_PROTO_TRACEPOINT(name, ...) { \ -+ asm volatile(".pushsection _dtrace_sdt_names, \"a\", @progbits\n"\ -+ ".ascii \"" __stringify(__perf_##name) "\"\n" \ -+ ".byte 0\n" \ -+ ".popsection\n" \ -+ ".pushsection _dtrace_sdt_args, \"a\", @progbits\n" \ -+ ".ascii \"" __stringify(__VA_ARGS__) "\"\n" \ -+ ".byte 0\n" \ -+ ".popsection\n"); \ -+} -+#else -+ -+#define DTRACE_PROBE_TRACEPOINT(name, ...) -+#define DTRACE_PROTO_TRACEPOINT(name, ...) -+ -+#endif -+ -+#else /* ! IS_ENABLED(CONFIG_DT_SDT) */ -+ -+/* -+ * This apparently redundant call serves to validate the DTRACE_PROBE has the -+ * right number of args even when dtrace is turned off. -+ */ -+#define DTRACE_PROBE(name, ...) \ -+ __DTRACE_DOUBLE_APPLY_NOCOMMA(__DTRACE_NONE, __DTRACE_NONE, ## __VA_ARGS__) \ -+ do { } while (0) -+#define DTRACE_PROBE_ENABLED(name) 0 -+#define DTRACE_PROBE_TRACEPOINT(name, ...) -+#define DTRACE_PROTO_TRACEPOINT(name, ...) -+ -+#endif /* IS_ENABLED(CONFIG_DT_SDT) */ -+ -+#ifdef CONFIG_DTRACE -+ -+struct sdt_probedesc { -+ char *sdpd_name; /* probe name */ -+ char *sdpd_func; /* probe function */ -+#ifndef __GENKSYMS__ -+ const char *sdpd_args; /* arg string */ -+#endif -+ unsigned long sdpd_offset; /* offset of call in text */ -+ struct sdt_probedesc *sdpd_next; /* next static probe */ -+}; -+ -+#endif /* CONFIG_DTRACE */ -+ -+#define DTRACE_SCHED(name, ...) \ -+ DTRACE_PROBE(__sched_##name, ## __VA_ARGS__); -+ -+#define DTRACE_PROC(name, ...) \ -+ DTRACE_PROBE(__proc_##name, ## __VA_ARGS__); -+ -+#define DTRACE_IO(name, ...) \ -+ DTRACE_PROBE(__io_##name, ## __VA_ARGS__); -+ -+#define DTRACE_IO_ENABLED(name) \ -+ DTRACE_PROBE_ENABLED(__io_##name) -+ -+#define DTRACE_ISCSI(name, ...) \ -+ DTRACE_PROBE(__iscsi_##name, ## __VA_ARGS__); -+ -+#define DTRACE_NFSV3(name, ...) \ -+ DTRACE_PROBE(__nfsv3_##name, ## __VA_ARGS__); -+ -+#define DTRACE_NFSV4(name, ...) \ -+ DTRACE_PROBE(__nfsv4_##name, ## __VA_ARGS__); -+ -+#define DTRACE_SMB(name, ...) \ -+ DTRACE_PROBE(__smb_##name, ## __VA_ARGS__); -+ -+/* -+ * These definitions are used at probe points to specify the traffic direction; -+ * this helps simplify argument translation. -+ */ -+#define DTRACE_NET_PROBE_OUTBOUND 0x0 -+#define DTRACE_NET_PROBE_INBOUND 0x1 -+ -+#define DTRACE_IP(name, ...) \ -+ DTRACE_PROBE(__ip_##name, ## __VA_ARGS__); -+ -+/* -+ * Default DTRACE_TCP() and DTRACE_UDP() provider definitions specify the -+ * probe point within an is-enabled predicate. This is to avoid the overhead -+ * incurred during argument dereferencing (e.g. calls to ip_hdr(skb)), along -+ * with any conditional evaluation (which would require branching) when the -+ * probe is disabled. -+ * -+ * Because some TCP probe points require additional argument preparation, -+ * we also define the is-enabled predicate directly as -+ * DTRACE_TCP_ENABLED(probename) along with a probe point which does not -+ * the probe in an is-enabled predicate; this allows us to handle cases such -+ * as this: -+ * -+ * if (DTRACE_TCP_ENABLED(state__change)) { -+ * ...argument preparation... -+ * DTRACE_TCP_NOCHECK(state__change, ...); -+ * } -+ */ -+ -+#define DTRACE_TCP(name, ...) \ -+ if (DTRACE_PROBE_ENABLED(__tcp_##name)) \ -+ DTRACE_PROBE(__tcp_##name, ## __VA_ARGS__) -+#define DTRACE_TCP_ENABLED(name) \ -+ DTRACE_PROBE_ENABLED(__tcp_##name) -+#define DTRACE_TCP_NOCHECK(name, ...) \ -+ DTRACE_PROBE(__tcp_##name, ## __VA_ARGS__); -+ -+#define DTRACE_UDP(name, ...) \ -+ if (DTRACE_PROBE_ENABLED(__udp_##name)) \ -+ DTRACE_PROBE(__udp_##name, ## __VA_ARGS__); -+ -+#define DTRACE_SYSEVENT(name, ...) \ -+ DTRACE_PROBE(__sysevent_##name, ## __VA_ARGS__); -+ -+#define DTRACE_XPV(name, ...) \ -+ DTRACE_PROBE(__xpv_##name, ## __VA_ARGS__); -+ -+#define DTRACE_FC(name, ...) \ -+ DTRACE_PROBE(__fc_##name, ## __VA_ARGS__); -+ -+#define DTRACE_SRP(name, ...) \ -+ DTRACE_PROBE(__srp_##name, ## __VA_ARGS__); -+ -+#define DTRACE_LOCKSTAT_ENABLED(name) \ -+ DTRACE_PROBE_ENABLED(__lockstat_##name) -+ -+#define DTRACE_LOCKSTAT(name, ...) \ -+ DTRACE_PROBE(__lockstat_##name, ## __VA_ARGS__) -+ -+#define DTRACE_LOCKSTAT_RW_WRITER 0 -+#define DTRACE_LOCKSTAT_RW_READER 1 -+ -+/* Needed for lockstat probes where we cannot include ktime.h */ -+extern u64 dtrace_gethrtime_ns(void); -+ -+#endif /* _LINUX_SDT_H_ */ -diff --git a/include/linux/sdt_internal.h b/include/linux/sdt_internal.h -new file mode 100644 -index 0000000000000000000000000000000000000000..b544f8e619cff9052620af1ec4f1478032c98d66 ---- /dev/null -+++ b/include/linux/sdt_internal.h -@@ -0,0 +1,276 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Hide away all the terrible macro magic. -+ * -+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+#ifndef _LINUX_SDT_INTERNAL_H_ -+#define _LINUX_SDT_INTERNAL_H_ -+ -+#include <linux/types.h> -+ -+/* -+ * This counts the number of args. -+ */ -+#define __DTRACE_NARGS_SEQ(dummy, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ -+ _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, \ -+ _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, \ -+ _31, _32, _33, _34, _35, _36, N, ...) N -+#define __DTRACE_NARGS(...) \ -+ __DTRACE_NARGS_SEQ(dummy, ##__VA_ARGS__, 36, 35, 34, 33, 32, 31, \ -+ 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, \ -+ 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, \ -+ 8, 7, 6, 5, 4, 3, 2, 1, 0) -+ -+/* -+ * This will let macros expand before concatting them. -+ */ -+#define __DTRACE_PRIMITIVE_CAT(x, y) x ## y -+#define __DTRACE_CAT(x, y) __DTRACE_PRIMITIVE_CAT(x, y) -+ -+#define __DTRACE_COMMA , -+#define __DTRACE_NO_COMMA -+#define __DTRACE_NONE(x) -+ -+/* -+ * This will call two macros on each argument-pair passed in (the first two args -+ * are the names of the macros to call). Its TYPE and NAME variants will throw -+ * away the name and type arguments, respectively. __DTRACE_*_APPLY_NOCOMMA -+ * are like DTRACE_*_APPLY, but also omit the comma between arguments in the -+ * expansion of the macro. DTRACE_TYPE_APPLY_DEFAULT lets you specify a default -+ * if no variadic args are provided. -+ */ -+#define __DTRACE_DOUBLE_APPLY(type_macro, arg_macro, ...) \ -+ __DTRACE_CAT(__DTRACE_DOUBLE_APPLY_, \ -+ __DTRACE_NARGS(__VA_ARGS__))(type_macro, \ -+ arg_macro, __DTRACE_COMMA, \ -+ __DTRACE_COMMA, , ## __VA_ARGS__) -+#define __DTRACE_DOUBLE_APPLY_NOCOMMA(type_macro, arg_macro, ...) \ -+ __DTRACE_CAT(__DTRACE_DOUBLE_APPLY_, \ -+ __DTRACE_NARGS(__VA_ARGS__))(type_macro, \ -+ arg_macro, __DTRACE_NO_COMMA, \ -+ __DTRACE_NO_COMMA, , ## __VA_ARGS__) -+#define __DTRACE_TYPE_APPLY(type_macro, ...) \ -+ __DTRACE_CAT(__DTRACE_DOUBLE_APPLY_, \ -+ __DTRACE_NARGS(__VA_ARGS__))(type_macro, \ -+ __DTRACE_NONE, __DTRACE_NO_COMMA, \ -+ __DTRACE_COMMA, , ## __VA_ARGS__) -+#define __DTRACE_TYPE_APPLY_NOCOMMA(type_macro, ...) \ -+ __DTRACE_CAT(__DTRACE_DOUBLE_APPLY_, \ -+ __DTRACE_NARGS(__VA_ARGS__))(type_macro, \ -+ __DTRACE_NONE, __DTRACE_NO_COMMA, \ -+ __DTRACE_NO_COMMA, , ## __VA_ARGS__) -+#define __DTRACE_TYPE_APPLY_DEFAULT(type_macro, def, ...) \ -+ __DTRACE_CAT(__DTRACE_DOUBLE_APPLY_, \ -+ __DTRACE_NARGS(__VA_ARGS__))(type_macro, \ -+ __DTRACE_NONE, __DTRACE_NO_COMMA, \ -+ __DTRACE_COMMA, def, ## __VA_ARGS__) -+#define __DTRACE_ARG_APPLY(arg_macro, ...) \ -+ __DTRACE_CAT(__DTRACE_DOUBLE_APPLY_, \ -+ __DTRACE_NARGS(__VA_ARGS__))(__DTRACE_NONE, \ -+ arg_macro, __DTRACE_NO_COMMA, \ -+ __DTRACE_COMMA, , ## __VA_ARGS__) -+#define __DTRACE_DOUBLE_APPLY_0(t, a, comma_t, comma_a, def) def -+#define __DTRACE_DOUBLE_APPLY_2(t, a, comma_t, comma_a, def, type1, arg1) \ -+ t(type1) comma_t a(arg1) -+#define __DTRACE_DOUBLE_APPLY_4(t, a, comma_t, comma_a, def, type1, arg1, \ -+ type2, arg2) \ -+ t(type1) comma_t a(arg1) comma_a t(type2) comma_t a(arg2) -+#define __DTRACE_DOUBLE_APPLY_6(t, a, comma_t, comma_a, def, type1, \ -+ arg1, type2, arg2, type3, arg3) \ -+ t(type1) comma_t a(arg1) comma_a t(type2) comma_t a(arg2) comma_a \ -+ t(type3) comma_t a(arg3) -+#define __DTRACE_DOUBLE_APPLY_8(t, a, comma_t, comma_a, def, type1, arg1, \ -+ type2, arg2, type3, arg3, type4, arg4) \ -+ t(type1) comma_t a(arg1) comma_a t(type2) comma_t a(arg2) comma_a \ -+ t(type3) comma_t a(arg3) comma_a t(type4) comma_t a(arg4) -+#define __DTRACE_DOUBLE_APPLY_10(t, a, comma_t, comma_a, def, type1, arg1,\ -+ type2, arg2, type3, arg3, type4, arg4, \ -+ type5, arg5) \ -+ t(type1) comma_t a(arg1) comma_a t(type2) comma_t a(arg2) comma_a \ -+ t(type3) comma_t a(arg3) comma_a t(type4) comma_t a(arg4) comma_a \ -+ t(type5) comma_t a(arg5) -+#define __DTRACE_DOUBLE_APPLY_12(t, a, comma_t, comma_a, def, type1, \ -+ arg1, type2, arg2, type3, arg3, type4, \ -+ arg4, type5, arg5, type6, arg6) \ -+ t(type1) comma_t a(arg1) comma_a t(type2) comma_t a(arg2) comma_a \ -+ t(type3) comma_t a(arg3) comma_a t(type4) comma_t a(arg4) comma_a \ -+ t(type5) comma_t a(arg5) comma_a t(type6) comma_t a(arg6) -+#define __DTRACE_DOUBLE_APPLY_14(t, a, comma_t, comma_a, def, type1, \ -+ arg1, type2, arg2, type3, arg3, type4, \ -+ arg4, type5, arg5, type6, arg6, type7, \ -+ arg7) \ -+ t(type1) comma_t a(arg1) comma_a t(type2) comma_t a(arg2) comma_a \ -+ t(type3) comma_t a(arg3) comma_a t(type4) comma_t a(arg4) comma_a \ -+ t(type5) comma_t a(arg5) comma_a t(type6) comma_t a(arg6) comma_a \ -+ t(type7) comma_t a(arg7) -+#define __DTRACE_DOUBLE_APPLY_16(t, a, comma_t, comma_a, def, type1, \ -+ arg1, type2, arg2, type3, arg3, type4, \ -+ arg4, type5, arg5, type6, arg6, type7, \ -+ arg7, type8, arg8) \ -+ t(type1) comma_t a(arg1) comma_a t(type2) comma_t a(arg2) comma_a \ -+ t(type3) comma_t a(arg3) comma_a t(type4) comma_t a(arg4) comma_a \ -+ t(type5) comma_t a(arg5) comma_a t(type6) comma_t a(arg6) comma_a \ -+ t(type7) comma_t a(arg7) comma_a t(type8) comma_t a(arg8) -+#define __DTRACE_DOUBLE_APPLY_18(t, a, comma_t, comma_a, def, type1, arg1, type2, arg2, type3, arg3, type4, arg4, type5, arg5, type6, arg6, type7, arg7, type8, arg8, type9, arg9) \ -+ t(type1) comma_t a(arg1) comma_a t(type2) comma_t a(arg2) comma_a \ -+ t(type3) comma_t a(arg3) comma_a t(type4) comma_t a(arg4) comma_a \ -+ t(type5) comma_t a(arg5) comma_a t(type6) comma_t a(arg6) comma_a \ -+ t(type7) comma_t a(arg7) comma_a t(type8) comma_t a(arg8) comma_a \ -+ t(type9) comma_t a(arg9) -+#define __DTRACE_DOUBLE_APPLY_20(t, a, comma_t, comma_a, def, type1, arg1, type2, arg2, type3, arg3, type4, arg4, type5, arg5, type6, arg6, type7, arg7, type8, arg8, type9, arg9, typea, arga) \ -+ t(type1) comma_t a(arg1) comma_a t(type2) comma_t a(arg2) comma_a \ -+ t(type3) comma_t a(arg3) comma_a t(type4) comma_t a(arg4) comma_a \ -+ t(type5) comma_t a(arg5) comma_a t(type6) comma_t a(arg6) comma_a \ -+ t(type7) comma_t a(arg7) comma_a t(type8) comma_t a(arg8) comma_a \ -+ t(type9) comma_t a(arg9) comma_a t(typea) comma_t a(arga) -+#define __DTRACE_DOUBLE_APPLY_22(t, a, comma_t, comma_a, def, type1, arg1, type2, arg2, type3, arg3, type4, arg4, type5, arg5, type6, arg6, type7, arg7, type8, arg8, type9, arg9, typea, arga, typeb, argb) \ -+ t(type1) comma_t a(arg1) comma_a t(type2) comma_t a(arg2) comma_a \ -+ t(type3) comma_t a(arg3) comma_a t(type4) comma_t a(arg4) comma_a \ -+ t(type5) comma_t a(arg5) comma_a t(type6) comma_t a(arg6) comma_a \ -+ t(type7) comma_t a(arg7) comma_a t(type8) comma_t a(arg8) comma_a \ -+ t(type9) comma_t a(arg9) comma_a t(typea) comma_t a(arga) comma_a \ -+ t(typeb) comma_t a(argb) -+#define __DTRACE_DOUBLE_APPLY_24(t, a, comma_t, comma_a, def, type1, arg1, type2, arg2, type3, arg3, type4, arg4, type5, arg5, type6, arg6, type7, arg7, type8, arg8, type9, arg9, typea, arga, typeb, argb, typec, argc) \ -+ t(type1) comma_t a(arg1) comma_a t(type2) comma_t a(arg2) comma_a \ -+ t(type3) comma_t a(arg3) comma_a t(type4) comma_t a(arg4) comma_a \ -+ t(type5) comma_t a(arg5) comma_a t(type6) comma_t a(arg6) comma_a \ -+ t(type7) comma_t a(arg7) comma_a t(type8) comma_t a(arg8) comma_a \ -+ t(type9) comma_t a(arg9) comma_a t(typea) comma_t a(arga) comma_a \ -+ t(typeb) comma_t a(argb) comma_a t(typec) comma_t a(argc) -+#define __DTRACE_DOUBLE_APPLY_26(t, a, comma_t, comma_a, def, type1, arg1, type2, arg2, type3, arg3, type4, arg4, type5, arg5, type6, arg6, type7, arg7, type8, arg8, type9, arg9, typea, arga, typeb, argb, typec, argc, typed, argd) \ -+ t(type1) comma_t a(arg1) comma_a t(type2) comma_t a(arg2) comma_a \ -+ t(type3) comma_t a(arg3) comma_a t(type4) comma_t a(arg4) comma_a \ -+ t(type5) comma_t a(arg5) comma_a t(type6) comma_t a(arg6) comma_a \ -+ t(type7) comma_t a(arg7) comma_a t(type8) comma_t a(arg8) comma_a \ -+ t(type9) comma_t a(arg9) comma_a t(typea) comma_t a(arga) comma_a \ -+ t(typeb) comma_t a(argb) comma_a t(typec) comma_t a(argc) comma_a \ -+ t(typed) comma_t a(argd) -+#define __DTRACE_DOUBLE_APPLY_28(t, a, comma_t, comma_a, def, type1, arg1, type2, arg2, type3, arg3, type4, arg4, type5, arg5, type6, arg6, type7, arg7, type8, arg8, type9, arg9, typea, arga, typeb, argb, typec, argc, typed, argd, typee, arge) \ -+ t(type1) comma_t a(arg1) comma_a t(type2) comma_t a(arg2) comma_a \ -+ t(type3) comma_t a(arg3) comma_a t(type4) comma_t a(arg4) comma_a \ -+ t(type5) comma_t a(arg5) comma_a t(type6) comma_t a(arg6) comma_a \ -+ t(type7) comma_t a(arg7) comma_a t(type8) comma_t a(arg8) comma_a \ -+ t(type9) comma_t a(arg9) comma_a t(typea) comma_t a(arga) comma_a \ -+ t(typeb) comma_t a(argb) comma_a t(typec) comma_t a(argc) comma_a \ -+ t(typed) comma_t a(argd) comma_a t(typee) comma_t a(arge) -+#define __DTRACE_DOUBLE_APPLY_30(t, a, comma_t, comma_a, def, type1, arg1, type2, arg2, type3, arg3, type4, arg4, type5, arg5, type6, arg6, type7, arg7, type8, arg8, type9, arg9, typea, arga, typeb, argb, typec, argc, typed, argd, typee, arge, typef, argf) \ -+ t(type1) comma_t a(arg1) comma_a t(type2) comma_t a(arg2) comma_a \ -+ t(type3) comma_t a(arg3) comma_a t(type4) comma_t a(arg4) comma_a \ -+ t(type5) comma_t a(arg5) comma_a t(type6) comma_t a(arg6) comma_a \ -+ t(type7) comma_t a(arg7) comma_a t(type8) comma_t a(arg8) comma_a \ -+ t(type9) comma_t a(arg9) comma_a t(typea) comma_t a(arga) comma_a \ -+ t(typeb) comma_t a(argb) comma_a t(typec) comma_t a(argc) comma_a \ -+ t(typed) comma_t a(argd) comma_a t(typee) comma_t a(arge) comma_a \ -+ t(typef) comma_t a(argf) -+#define __DTRACE_DOUBLE_APPLY_32(t, a, comma_t, comma_a, def, type1, arg1, type2, arg2, type3, arg3, type4, arg4, type5, arg5, type6, arg6, type7, arg7, type8, arg8, type9, arg9, typea, arga, typeb, argb, typec, argc, typed, argd, typee, arge, typef, argf, typeg, argg) \ -+ t(type1) comma_t a(arg1) comma_a t(type2) comma_t a(arg2) comma_a \ -+ t(type3) comma_t a(arg3) comma_a t(type4) comma_t a(arg4) comma_a \ -+ t(type5) comma_t a(arg5) comma_a t(type6) comma_t a(arg6) comma_a \ -+ t(type7) comma_t a(arg7) comma_a t(type8) comma_t a(arg8) comma_a \ -+ t(type9) comma_t a(arg9) comma_a t(typea) comma_t a(arga) comma_a \ -+ t(typeb) comma_t a(argb) comma_a t(typec) comma_t a(argc) comma_a \ -+ t(typed) comma_t a(argd) comma_a t(typee) comma_t a(arge) comma_a \ -+ t(typef) comma_t a(argf) comma_a t(typeg) comma_t a(argg) -+#define __DTRACE_DOUBLE_APPLY_34(t, a, comma_t, comma_a, def, type1, arg1, type2, arg2, type3, arg3, type4, arg4, type5, arg5, type6, arg6, type7, arg7, type8, arg8, type9, arg9, typea, arga, typeb, argb, typec, argc, typed, argd, typee, arge, typef, argf, typeg, argg, typeh, argh) \ -+ t(type1) comma_t a(arg1) comma_a t(type2) comma_t a(arg2) comma_a \ -+ t(type3) comma_t a(arg3) comma_a t(type4) comma_t a(arg4) comma_a \ -+ t(type5) comma_t a(arg5) comma_a t(type6) comma_t a(arg6) comma_a \ -+ t(type7) comma_t a(arg7) comma_a t(type8) comma_t a(arg8) comma_a \ -+ t(type9) comma_t a(arg9) comma_a t(typea) comma_t a(arga) comma_a \ -+ t(typeb) comma_t a(argb) comma_a t(typec) comma_t a(argc) comma_a \ -+ t(typed) comma_t a(argd) comma_a t(typee) comma_t a(arge) comma_a \ -+ t(typef) comma_t a(argf) comma_a t(typeg) comma_t a(argg) comma_a \ -+ t(typeh) comma_t a(argh) -+#define __DTRACE_DOUBLE_APPLY_36(t, a, comma_t, comma_a, def, type1, arg1, type2, arg2, type3, arg3, type4, arg4, type5, arg5, type6, arg6, type7, arg7, type8, arg8, type9, arg9, typea, arga, typeb, argb, typec, argc, typed, argd, typee, arge, typef, argf, typeg, argg, typeh, argh, typei, argi) \ -+ t(type1) comma_t a(arg1) comma_a t(type2) comma_t a(arg2) comma_a \ -+ t(type3) comma_t a(arg3) comma_a t(type4) comma_t a(arg4) comma_a \ -+ t(type5) comma_t a(arg5) comma_a t(type6) comma_t a(arg6) comma_a \ -+ t(type7) comma_t a(arg7) comma_a t(type8) comma_t a(arg8) comma_a \ -+ t(type9) comma_t a(arg9) comma_a t(typea) comma_t a(arga) comma_a \ -+ t(typeb) comma_t a(argb) comma_a t(typec) comma_t a(argc) comma_a \ -+ t(typed) comma_t a(argd) comma_a t(typee) comma_t a(arge) comma_a \ -+ t(typef) comma_t a(argf) comma_a t(typeg) comma_t a(argg) comma_a \ -+ t(typeh) comma_t a(argh) comma_a t(typei) comma_t a(argi) -+ -+#define __DTRACE_DOUBLE_APPLY_ERROR Error: type specified without arg. -+#define __DTRACE_DOUBLE_APPLY_1 __DTRACE_DOUBLE_APPLY_ERROR -+#define __DTRACE_DOUBLE_APPLY_3 __DTRACE_DOUBLE_APPLY_ERROR -+#define __DTRACE_DOUBLE_APPLY_5 __DTRACE_DOUBLE_APPLY_ERROR -+#define __DTRACE_DOUBLE_APPLY_7 __DTRACE_DOUBLE_APPLY_ERROR -+#define __DTRACE_DOUBLE_APPLY_9 __DTRACE_DOUBLE_APPLY_ERROR -+#define __DTRACE_DOUBLE_APPLY_11 __DTRACE_DOUBLE_APPLY_ERROR -+#define __DTRACE_DOUBLE_APPLY_13 __DTRACE_DOUBLE_APPLY_ERROR -+#define __DTRACE_DOUBLE_APPLY_15 __DTRACE_DOUBLE_APPLY_ERROR -+#define __DTRACE_DOUBLE_APPLY_17 __DTRACE_DOUBLE_APPLY_ERROR -+#define __DTRACE_DOUBLE_APPLY_19 __DTRACE_DOUBLE_APPLY_ERROR -+#define __DTRACE_DOUBLE_APPLY_21 __DTRACE_DOUBLE_APPLY_ERROR -+#define __DTRACE_DOUBLE_APPLY_23 __DTRACE_DOUBLE_APPLY_ERROR -+#define __DTRACE_DOUBLE_APPLY_25 __DTRACE_DOUBLE_APPLY_ERROR -+#define __DTRACE_DOUBLE_APPLY_27 __DTRACE_DOUBLE_APPLY_ERROR -+#define __DTRACE_DOUBLE_APPLY_29 __DTRACE_DOUBLE_APPLY_ERROR -+#define __DTRACE_DOUBLE_APPLY_31 __DTRACE_DOUBLE_APPLY_ERROR -+#define __DTRACE_DOUBLE_APPLY_33 __DTRACE_DOUBLE_APPLY_ERROR -+#define __DTRACE_DOUBLE_APPLY_35 __DTRACE_DOUBLE_APPLY_ERROR -+#define __DTRACE_DOUBLE_APPLY_37 __DTRACE_DOUBLE_APPLY_ERROR -+ -+#define __DTRACE_UINTPTR_EACH(x) uintptr_t -+ -+#define __DTRACE_UINTCAST_EACH(x) (uintptr_t)(x) -+#define __DTRACE_TYPE_EACH(x) ".ascii \"" __stringify(x) ",\"\n" -+ -+/* -+ * Convert everything to the appropriate integral type, unless too large to fit -+ * into any of them, in which case its address is taken instead. -+ */ -+ -+/* -+ * This will call a macro on each argument passed in, with optional default for -+ * zero args. -+ */ -+#define __DTRACE_APPLY(macro, ...) __DTRACE_CAT(__DTRACE_APPLY_, __DTRACE_NARGS(__VA_ARGS__))(macro, , ## __VA_ARGS__) -+#define __DTRACE_APPLY_DEFAULT(macro, def, ...) __DTRACE_CAT(__DTRACE_APPLY_, __DTRACE_NARGS(__VA_ARGS__))(macro, def, ## __VA_ARGS__) -+#define __DTRACE_APPLY_0(m, def) def -+#define __DTRACE_APPLY_1(m, def, x1) m(x1) -+#define __DTRACE_APPLY_2(m, def, x1, x2) m(x1), m(x2) -+#define __DTRACE_APPLY_3(m, def, x1, x2, x3) m(x1), m(x2), m(x3) -+#define __DTRACE_APPLY_4(m, def, x1, x2, x3, x4) m(x1), m(x2), m(x3), m(x4) -+#define __DTRACE_APPLY_5(m, def, x1, x2, x3, x4, x5) \ -+ m(x1), m(x2), m(x3), m(x4), m(x5) -+#define __DTRACE_APPLY_6(m, def, x1, x2, x3, x4, x5, x6) \ -+ m(x1), m(x2), m(x3), m(x4), m(x5), m(x6) -+#define __DTRACE_APPLY_7(m, def, x1, x2, x3, x4, x5, x6, x7) \ -+ m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7) -+#define __DTRACE_APPLY_8(m, def, x1, x2, x3, x4, x5, x6, x7, x8) \ -+ m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7), m(x8) -+#define __DTRACE_APPLY_9(m, def, x1, x2, x3, x4, x5, x6, x7, x8, x9) \ -+ m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7), m(x8), m(x9) -+#define __DTRACE_APPLY_10(m, def, x1, x2, x3, x4, x5, x6, x7, x8, x9, xa) \ -+ m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7), m(x8), m(x9), m(xa) -+#define __DTRACE_APPLY_11(m, def, x1, x2, x3, x4, x5, x6, x7, x8, x9, xa, xb) \ -+ m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7), m(x8), m(x9), m(xa), \ -+ m(xb) -+#define __DTRACE_APPLY_12(m, def, x1, x2, x3, x4, x5, x6, x7, x8, x9, xa, xb, xc) \ -+ m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7), m(x8), m(x9), m(xa), \ -+ m(xb), m(xc) -+#define __DTRACE_APPLY_13(m, def, x1, x2, x3, x4, x5, x6, x7, x8, x9, xa, xb, xc, xd) \ -+ m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7), m(x8), m(x9), m(xa), \ -+ m(xb), m(xc), m(xd) -+#define __DTRACE_APPLY_14(m, def, x1, x2, x3, x4, x5, x6, x7, x8, x9, xa, xb, xc, xd, xe) \ -+ m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7), m(x8), m(x9), m(xa), \ -+ m(xb), m(xc), m(xd), m(xe) -+#define __DTRACE_APPLY_15(m, def, x1, x2, x3, x4, x5, x6, x7, x8, x9, xa, xb, xc, xd, xe, xf) \ -+ m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7), m(x8), m(x9), m(xa), \ -+ m(xb), m(xc), m(xd), m(xe), m(xf) -+#define __DTRACE_APPLY_16(m, def, x1, x2, x3, x4, x5, x6, x7, x8, x9, xa, xb, xc, xd, xe, xf, xg) \ -+ m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7), m(x8), m(x9), m(xa), \ -+ m(xb), m(xc), m(xd), m(xe), m(xf), m(xg) -+#define __DTRACE_APPLY_17(m, def, x1, x2, x3, x4, x5, x6, x7, x8, x9, xa, xb, xc, xd, xe, xf, xg, xh) \ -+ m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7), m(x8), m(x9), m(xa), \ -+ m(xb), m(xc), m(xd), m(xe), m(xf), m(xg), m(xh) -+#define __DTRACE_APPLY_18(m, def, x1, x2, x3, x4, x5, x6, x7, x8, x9, xa, xb, xc, xd, xe, xf, xg, xh, xi) \ -+ m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7), m(x8), m(x9), m(xa), \ -+ m(xb), m(xc), m(xd), m(xe), m(xf), m(xg), m(xh), m(xi) -+ -+#endif /* _LINUX_SDT_INTERNAL_H */ -diff --git a/include/linux/tracepoint.h b/include/linux/tracepoint.h -index 0f21617f1a6689395d9caa86d8d2982ef9a3ea84..e847bbafd1234695a78008b77aa8d8740d21d0a0 100644 ---- a/include/linux/tracepoint.h -+++ b/include/linux/tracepoint.h -@@ -20,6 +20,7 @@ - #include <linux/rcupdate.h> - #include <linux/tracepoint-defs.h> - #include <linux/static_call.h> -+#include <linux/sdt.h> - - struct module; - struct tracepoint; -@@ -237,6 +238,8 @@ static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p) - extern struct tracepoint __tracepoint_##name; \ - static inline void trace_##name(proto) \ - { \ -+ DTRACE_PROBE_TRACEPOINT(name, args); \ -+ DTRACE_PROTO_TRACEPOINT(name, proto); \ - if (static_key_false(&__tracepoint_##name.key)) \ - __DO_TRACE(name, \ - TP_PROTO(data_proto), \ -@@ -332,7 +335,10 @@ static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p) - #else /* !TRACEPOINTS_ENABLED */ - #define __DECLARE_TRACE(name, proto, args, cond, data_proto, data_args) \ - static inline void trace_##name(proto) \ -- { } \ -+ { \ -+ DTRACE_PROBE_TRACEPOINT(name, args); \ -+ DTRACE_PROTO_TRACEPOINT(name, proto); \ -+ } \ - static inline void trace_##name##_rcuidle(proto) \ - { } \ - static inline int \ -diff --git a/kernel/dtrace/Kconfig b/kernel/dtrace/Kconfig -index d04ca0ab7ac9c14f4450927423b30784311a3cbd..c1ec55d8750edfbaf55ab9431b7c822b3dd2afae 100644 ---- a/kernel/dtrace/Kconfig -+++ b/kernel/dtrace/Kconfig -@@ -23,6 +23,22 @@ config DT_CORE - - if DT_CORE - -+config DT_SDT -+ tristate "Statically Defined Tracing" -+ default m -+ select KALLSYMS -+ help -+ Statically defined tracepoints in the kernel. -+ -+config DT_SDT_PERF -+ bool "DTrace perf-events Probes" -+ default y -+ depends on DT_SDT -+ select TRACEPOINTS -+ help -+ Provides the perf provider, containing a DTrace probe for each -+ perf-events tracepoint in the system. -+ - config DT_SYSTRACE - tristate "System Call Tracing" - default m -diff --git a/kernel/dtrace/Makefile b/kernel/dtrace/Makefile -index 68fc3861e5d1175006494f12758ff1f0304d10fa..06329cbe52cbfbd96c23e6838fc99e53cc5ec5d6 100644 ---- a/kernel/dtrace/Makefile -+++ b/kernel/dtrace/Makefile -@@ -4,10 +4,11 @@ - - DT_CORE_ARCH_OBJS = $(addprefix ../../arch/$(SRCARCH)/kernel/, \ - dtrace_syscall.o dtrace_syscall_stubs.o \ -- dtrace_util.o) -+ dtrace_sdt.o dtrace_util.o) - - ifdef CONFIG_DT_CORE - obj-y += cyclic.o dtrace_os.o dtrace_cpu.o \ -+ dtrace_sdt_core.o \ - dtrace_task.o dtrace_psinfo.o \ - $(DT_CORE_ARCH_OBJS) - endif -diff --git a/kernel/dtrace/dtrace_os.c b/kernel/dtrace/dtrace_os.c -index d023f3913323b42678aee5a7467a4b39c378c8cc..931cfd0d0fbfc05c7670f4c01f1cfef140dbf408 100644 ---- a/kernel/dtrace/dtrace_os.c -+++ b/kernel/dtrace/dtrace_os.c -@@ -19,6 +19,7 @@ - #include <linux/binfmts.h> - #include <linux/dtrace_cpu.h> - #include <linux/dtrace_os.h> -+#include <linux/dtrace_sdt.h> - #include <linux/fs.h> - #include <linux/hardirq.h> - #include <linux/interrupt.h> -@@ -66,6 +67,46 @@ void __init dtrace_os_init(void) - if (dtrace_pdata_cachep == NULL) - pr_debug("Can't allocate kmem cache for pdata\n"); - -+ /* -+ * A little bit of magic... -+ * We create a dummy module to represent the core Linux kernel. The -+ * only data we're interested in is the name, the SDT probe points data -+ * (to be filled in by dtrace_sdt_register()), and the probe data. -+ * DTrace uses an architecture-specific structure (hidden from us here) -+ * to hold some data. -+ */ -+ dtrace_kmod = kmalloc(sizeof(struct module), GFP_KERNEL | __GFP_ZERO); -+ if (dtrace_kmod == NULL) { -+ pr_warn("%s: cannot allocate kernel pseudo-module\n", -+ __func__); -+ return; -+ } -+ -+ strlcpy(dtrace_kmod->name, "vmlinux", MODULE_NAME_LEN); -+ -+ /* -+ * Some sizing info is required for kernel module. We are going to use -+ * modules VA range for trampoline anyway so lets pretend a kernel has -+ * no init section and VA range (0, MODULES_VADDR) is occupied by -+ * kernel itself -+ */ -+#ifdef CONFIG_X86_64 -+ dtrace_kmod->core_layout.base = (void *)__START_KERNEL_map; -+ dtrace_kmod->core_layout.size = KERNEL_IMAGE_SIZE; -+#elif defined(CONFIG_SPARC64) -+ /* Hardcoded see pgtable_64.h */ -+ dtrace_kmod->core_layout.base = (void *)0x4000000; -+ dtrace_kmod->core_layout.size = 0x2000000; -+#endif -+ -+ dtrace_kmod->state = MODULE_STATE_LIVE; -+ atomic_inc(&dtrace_kmod->refcnt); -+ -+ dtrace_mod_pdata_alloc(dtrace_kmod); -+ -+ INIT_LIST_HEAD(&dtrace_kmod->source_list); -+ INIT_LIST_HEAD(&dtrace_kmod->target_list); -+ - /* - * We need to set up a psinfo structure for PID 0 (swapper). - */ -@@ -73,7 +114,49 @@ void __init dtrace_os_init(void) - dtrace_psinfo_os_init(); - dtrace_task_init(&init_task); - dtrace_psinfo_alloc(&init_task); -+ -+ dtrace_sdt_init(); -+ dtrace_sdt_register(dtrace_kmod); -+} -+ -+#define MIN(a, b) (((a) < (b)) ? (a) : (b)) -+#define MAX(a, b) (((a) > (b)) ? (a) : (b)) -+#define TRAMP_RANGE 0x80000000 -+ -+void *dtrace_alloc_text(struct module *mp, unsigned long size) -+{ -+ unsigned long mp_start, mp_end; -+ unsigned long va_start, va_end; -+ void *trampoline; -+ -+ /* module range */ -+ mp_start = (unsigned long) mp->core_layout.base; -+ mp_end = mp_start + mp->core_layout.size; -+ -+ if (mp->init_layout.size) { -+ mp_start = MIN(mp_start, (unsigned long)mp->init_layout.base); -+ mp_end = MAX(mp_end, (unsigned long)mp->init_layout.base + -+ mp->init_layout.size); -+ } -+ -+ /* get trampoline range */ -+ va_end = MIN(mp_start + TRAMP_RANGE, MODULES_END); -+ va_start = (mp_end < TRAMP_RANGE) ? 0 : mp_end - TRAMP_RANGE; -+ va_start = MAX(va_start, MODULES_VADDR); -+ -+ trampoline = __vmalloc_node_range(size, 1, va_start, va_end, -+ GFP_KERNEL, PAGE_KERNEL, 0, NUMA_NO_NODE, -+ __builtin_return_address(0)); -+ -+ return trampoline; -+} -+EXPORT_SYMBOL(dtrace_alloc_text); -+ -+void dtrace_free_text(void *ptr) -+{ -+ return vfree(ptr); - } -+EXPORT_SYMBOL(dtrace_free_text); - - /* - * MODULE SUPPORT FUNCTIONS -diff --git a/kernel/dtrace/dtrace_sdt_core.c b/kernel/dtrace/dtrace_sdt_core.c -new file mode 100644 -index 0000000000000000000000000000000000000000..90b86726f195ff4a917c8f73ebb4bfa99fd669c6 ---- /dev/null -+++ b/kernel/dtrace/dtrace_sdt_core.c -@@ -0,0 +1,364 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_sdt_core.c -+ * DESCRIPTION: DTrace - SDT probes -+ * -+ * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/memory.h> -+#include <linux/module.h> -+#include <linux/dtrace_os.h> -+#include <linux/dtrace_sdt.h> -+#include <linux/jhash.h> -+#include <linux/sdt.h> -+#include <linux/slab.h> -+#include <linux/string.h> -+#include <linux/vmalloc.h> -+#include <asm-generic/bitsperlong.h> -+#include <asm-generic/sections.h> -+ -+const char *sdt_prefix = "__dtrace_probe_"; -+int dtrace_nosdt; -+ -+/* -+ * Compiled-in SDT probe data. -+ */ -+extern const unsigned long dtrace_sdt_probes[]; -+extern const char dtrace_sdt_strings[]; -+extern const unsigned long dtrace_sdt_nprobes; -+ -+/* -+ * Markers of core-kernel sdt_args and sdt_names sections. -+ */ -+extern const char __start_dtrace_sdt_args[]; -+extern const char __stop_dtrace_sdt_args[]; -+extern const char __start_dtrace_sdt_names[]; -+extern const char __stop_dtrace_sdt_names[]; -+ -+static int sdt_probe_set(struct sdt_probedesc *sdp, const char *name, -+ const char *func, uintptr_t addr, asm_instr_t **paddr, -+ struct sdt_probedesc *prv) -+{ -+ sdp->sdpd_name = kstrdup(name, GFP_KERNEL); -+ if (sdp->sdpd_name == NULL) { -+ kfree(sdp); -+ return 1; -+ } -+ -+ sdp->sdpd_func = kstrdup(func, GFP_KERNEL); -+ if (sdp->sdpd_func == NULL) { -+ kfree(sdp->sdpd_name); -+ kfree(sdp); -+ return 1; -+ } -+ -+ sdp->sdpd_args = NULL; -+ sdp->sdpd_offset = addr; -+ sdp->sdpd_next = NULL; -+ -+ *paddr = (asm_instr_t *)addr; -+ -+ if (prv && strcmp(prv->sdpd_name, sdp->sdpd_name) == 0 -+ && strcmp(prv->sdpd_func, sdp->sdpd_func) == 0) -+ prv->sdpd_next = sdp; -+ -+ return 0; -+} -+ -+/* -+ * Transfer the SDT args section into the sdpd_args field left NULL above. -+ * -+ * The memory pointed to by args_start must have a lifetime at least as long as -+ * that pointed to by sdpd. -+ */ -+void dtrace_sdt_stash_args(const char *module_name, -+ struct sdt_probedesc *sdpd, size_t nprobes, -+ const char *names_start, size_t names_len, -+ const char *args_start, size_t args_len) -+{ -+ struct probe_name_hashent_t { -+ const char *pnhe_name; -+ const char *pnhe_args; -+ } *args_by_name; -+ int i; -+ const char *namep, *argp; -+ size_t hashsize; -+ -+ /* -+ * We need to find the probes (and there may be many) in the sdpd -+ * corresponding to the probe with that name in the argtype section. -+ * -+ * Build a hashtable mapping from probe name -> args string, ignoring -+ * duplicate probe names except to check (in debugging mode) that they -+ * have the same args string as the first. Then cycle over the sdpd -+ * looking up each probe in turn and pointing to the same place. -+ * -+ * We don't know how many entries there are in the table, but we do know -+ * there cannot be more than nprobes (and are probably less). -+ */ -+ -+ hashsize = nprobes * 4; /* arbitrary expansion factor */ -+ args_by_name = vzalloc(hashsize * sizeof(struct probe_name_hashent_t)); -+ if (args_by_name == NULL) { -+ pr_warn("%s: cannot allocate hash for sdt args population\n", -+ __func__); -+ return; -+ } -+ -+ namep = names_start; -+ argp = args_start; -+ while ((namep < names_start + names_len) && -+ (argp < args_start + args_len)) { -+ -+ size_t l = strlen(namep); -+ u32 h = jhash(namep, l, 0) % hashsize; -+ -+ while (args_by_name[h].pnhe_name != NULL && -+ strcmp(args_by_name[h].pnhe_name, namep) != 0) { -+ h++; -+ h %= hashsize; -+ } -+ -+ if (args_by_name[h].pnhe_name == NULL) { -+ args_by_name[h].pnhe_name = namep; -+ args_by_name[h].pnhe_args = argp; -+ } -+#if defined(CONFIG_DT_DEBUG) -+ else if (strcmp(args_by_name[h].pnhe_name, namep) != 0) -+ pr_warn("%s: multiple distinct arg strings for probe " -+ "%s found: %s versus %s", -+ module_name, namep, -+ args_by_name[h].pnhe_args, -+ argp); -+#endif -+ namep += l + 1; -+ argp += strlen(argp) + 1; -+ } -+ -+#if defined(CONFIG_DT_DEBUG) -+ if ((namep < names_start + names_len) || (argp < args_start + args_len)) -+ pr_warn("%s: Not all SDT names or args consumed: %zi " -+ "bytes of names and %zi of args left over. " -+ "Some arg types will be mis-assigned.\n", module_name, -+ namep - (names_start + names_len), -+ argp - (args_start + args_len)); -+#endif -+ -+ for (i = 0; i < nprobes; i++) { -+ size_t l = strlen(sdpd[i].sdpd_name); -+ u32 h = jhash(sdpd[i].sdpd_name, l, 0) % hashsize; -+ -+ /* -+ * Is-enabled probes have no arg string. -+ */ -+ if (sdpd[i].sdpd_name[0] == '?') -+ continue; -+ -+ while (args_by_name[h].pnhe_name != NULL && -+ strcmp(sdpd[i].sdpd_name, -+ args_by_name[h].pnhe_name) != 0) { -+ h++; -+ h %= hashsize; -+ } -+ -+ if (args_by_name[h].pnhe_name == NULL) { -+ /* -+ * No arg string. Peculiar: report in debugging mode. -+ */ -+#if defined(CONFIG_DT_DEBUG) -+ pr_warn("%s: probe %s has no arg string.\n", -+ module_name, sdpd[i].sdpd_name); -+#endif -+ continue; -+ } -+ -+ sdpd[i].sdpd_args = args_by_name[h].pnhe_args; -+ } -+ vfree(args_by_name); -+} -+ -+/* -+ * Register the SDT probes for the core kernel, i.e. SDT probes that reside in -+ * vmlinux. For SDT probes in kernel modules, we use dtrace_mod_notifier(). -+ */ -+void __init dtrace_sdt_register(struct module *mp) -+{ -+ int i, cnt; -+ struct sdt_probedesc *sdps; -+ asm_instr_t **addrs; -+ int *is_enabled; -+ void *args; -+ size_t args_len; -+ -+ if (mp == NULL) { -+ pr_warn("%s: no module provided - nothing registered\n", -+ __func__); -+ return; -+ } -+ -+ /* -+ * Just in case we run into failures further on... -+ */ -+ mp->sdt_probes = NULL; -+ mp->sdt_probec = 0; -+ -+ if (dtrace_sdt_nprobes == 0 || dtrace_nosdt) -+ return; -+ -+ /* -+ * Allocate the array of SDT probe descriptions to be registered in the -+ * vmlinux pseudo-module. -+ */ -+ sdps = (struct sdt_probedesc *)vmalloc(dtrace_sdt_nprobes * -+ sizeof(struct sdt_probedesc)); -+ if (sdps == NULL) { -+ pr_warn("%s: cannot allocate SDT probe array\n", __func__); -+ return; -+ } -+ -+ /* -+ * Create a list of addresses (SDT probe locations) that need to be -+ * patched with a NOP instruction (or instruction sequence), and another -+ * array indicating whether each probe needs patching with an -+ * arch-dependent false return instead. -+ */ -+ addrs = (asm_instr_t **)vmalloc(dtrace_sdt_nprobes * -+ sizeof(asm_instr_t *)); -+ is_enabled = (int *)vmalloc(dtrace_sdt_nprobes * sizeof(int)); -+ if ((addrs == NULL) || (is_enabled == NULL)) { -+ pr_warn("%s: cannot allocate SDT probe address/is-enabled " -+ "lists\n", __func__); -+ vfree(sdps); -+ vfree(addrs); -+ vfree(is_enabled); -+ return; -+ } -+ -+ for (i = cnt = 0; i < dtrace_sdt_nprobes; i++) { -+ uintptr_t addr, poff, foff; -+ const char *fname = &dtrace_sdt_strings[foff]; -+ const char *pname; -+ -+ addr = dtrace_sdt_probes[i * 3]; /* address */ -+ poff = dtrace_sdt_probes[i * 3 + 1]; /* probe name offset */ -+ foff = dtrace_sdt_probes[i * 3 + 2]; /* func name offset */ -+ pname = &dtrace_sdt_strings[poff]; -+ fname = &dtrace_sdt_strings[foff]; -+ -+ is_enabled[cnt] = (pname[0] == '?'); -+ -+ if (sdt_probe_set(&sdps[cnt], pname, fname, addr, &addrs[cnt], -+ cnt > 0 ? &sdps[cnt - 1] : NULL)) -+ pr_warn("%s: failed to add SDT probe %s for %s\n", -+ __func__, pname, fname); -+ else -+ cnt++; -+ } -+ -+ mp->sdt_probes = sdps; -+ mp->sdt_probec = cnt; -+ -+ dtrace_sdt_nop_multi(addrs, is_enabled, cnt); -+ -+ /* -+ * Allocate space for the array of arg types, and copy it in from the -+ * (discardable) kernel section. We will need to keep it. (The -+ * identically-ordered array of probe names is not needed after -+ * initialization.) -+ */ -+ args_len = __stop_dtrace_sdt_args - __start_dtrace_sdt_args; -+ args = vmalloc(args_len); -+ if (args == NULL) { -+ pr_warn("%s: cannot allocate table of SDT arg types\n", -+ __func__); -+ goto end; -+ } -+ -+ memcpy(args, __start_dtrace_sdt_args, args_len); -+ -+ dtrace_sdt_stash_args("vmlinux", sdps, cnt, -+ __start_dtrace_sdt_names, -+ (__stop_dtrace_sdt_names - __start_dtrace_sdt_names), -+ args, args_len); -+ -+end: -+ vfree(addrs); -+ vfree(is_enabled); -+} -+ -+static int __init nosdt(char *str) -+{ -+ dtrace_nosdt = 1; -+ -+ return 0; -+} -+ -+early_param("nosdt", nosdt); -+ -+void dtrace_sdt_register_module(struct module *mp, -+ void *sdt_names_addr, size_t sdt_names_len, -+ void *sdt_args_addr, size_t sdt_args_len) -+{ -+ int i, cnt; -+ struct sdt_probedesc *sdp; -+ asm_instr_t **addrs; -+ int *is_enabled; -+ -+ if (mp->sdt_probec == 0 || mp->sdt_probes == NULL) -+ return; -+ -+ /* -+ * Create a list of addresses (SDT probe locations) that need to be -+ * patched with a NOP instruction (or instruction sequence). -+ */ -+ addrs = (asm_instr_t **)vmalloc(mp->sdt_probec * -+ sizeof(asm_instr_t *)); -+ is_enabled = (int *)vmalloc(mp->sdt_probec * sizeof(int)); -+ if ((addrs == NULL) || (is_enabled == NULL)) { -+ pr_warn("%s: cannot allocate SDT probe address list (%s)\n", -+ __func__, mp->name); -+ vfree(addrs); -+ vfree(is_enabled); -+ return; -+ } -+ -+ for (i = cnt = 0, sdp = mp->sdt_probes; i < mp->sdt_probec; -+ i++, sdp++) { -+ addrs[cnt] = (asm_instr_t *)sdp->sdpd_offset; -+ is_enabled[cnt++] = (sdp->sdpd_name[0] == '?'); -+ } -+ -+ dtrace_sdt_nop_multi(addrs, is_enabled, cnt); -+ -+ dtrace_sdt_stash_args(mp->name, mp->sdt_probes, mp->sdt_probec, -+ sdt_names_addr, sdt_names_len, -+ sdt_args_addr, sdt_args_len); -+ -+ vfree(addrs); -+ vfree(is_enabled); -+} -+ -+void __init dtrace_sdt_init(void) -+{ -+ dtrace_sdt_init_arch(); -+} -+ -+#if IS_ENABLED(CONFIG_DT_DT_PERF) -+void dtrace_sdt_perf(void) -+{ -+ DTRACE_PROBE(measure); -+} -+EXPORT_SYMBOL(dtrace_sdt_perf); -+#endif -diff --git a/kernel/module.c b/kernel/module.c -index f4269dabc63837a9055eeed1bab211e30422413e..2f214881ae30de2bfc913db89e618e3446e89cb3 100644 ---- a/kernel/module.c -+++ b/kernel/module.c -@@ -40,6 +40,7 @@ - #include <linux/string.h> - #include <linux/mutex.h> - #include <linux/rculist.h> -+#include <linux/sdt.h> - #include <linux/uaccess.h> - #include <asm/cacheflush.h> - #include <linux/set_memory.h> -@@ -47,6 +48,7 @@ - #include <linux/license.h> - #include <asm/sections.h> - #include <linux/dtrace_os.h> -+#include <linux/dtrace_sdt.h> - #include <linux/tracepoint.h> - #include <linux/ftrace.h> - #include <linux/livepatch.h> -@@ -3777,6 +3779,18 @@ static int complete_formation(struct module *mod, struct load_info *info) - { - int err; - -+#ifdef CONFIG_DTRACE -+ void *sdt_args, *sdt_names; -+ unsigned int sdt_args_len, sdt_names_len; -+ -+ sdt_names = section_objs(info, "_dtrace_sdt_names", 1, -+ &sdt_names_len); -+ sdt_args = section_objs(info, "_dtrace_sdt_args", 1, -+ &sdt_args_len); -+ dtrace_sdt_register_module(mod, sdt_names, sdt_names_len, -+ sdt_args, sdt_args_len); -+#endif -+ - mutex_lock(&module_mutex); - - /* Find duplicate symbols (must be called under lock). */ -diff --git a/scripts/.gitignore b/scripts/.gitignore -index a6c11316c9696751b12e3f0b9157d58a8233f613..8458568004eb7b30b825bea7e6d8b9efd5eb3309 100644 ---- a/scripts/.gitignore -+++ b/scripts/.gitignore -@@ -9,3 +9,4 @@ extract-cert - sign-file - insert-sys-cert - /module.lds -+kmodsdt -diff --git a/scripts/Makefile b/scripts/Makefile -index efa1ff4dff951222a8c98326c29f2146d7e4c587..509a73b6f2697e945c01cfb21785c7646a8f1142 100644 ---- a/scripts/Makefile -+++ b/scripts/Makefile -@@ -11,6 +11,7 @@ hostprogs-always-$(CONFIG_ASN1) += asn1_compiler - hostprogs-always-$(CONFIG_MODULE_SIG_FORMAT) += sign-file - hostprogs-always-$(CONFIG_SYSTEM_TRUSTED_KEYRING) += extract-cert - hostprogs-always-$(CONFIG_SYSTEM_EXTRA_CERTIFICATE) += insert-sys-cert -+hostprogs-always-$(CONFIG_DTRACE) += kmodsdt - - kallsyms-objs := kallsyms.o - -@@ -36,6 +37,11 @@ HOSTCFLAGS_sorttable.o += -DUNWINDER_ORC_ENABLED - HOSTLDLIBS_sorttable = -lpthread - endif - -+ifeq ($(CONFIG_DTRACE),y) -+HOSTCFLAGS_kmodsdt.o := -I$(srctree)/include/generated -+HOSTLDLIBS_kmodsdt := -lelf -+endif -+ - # The following programs are only built on demand - hostprogs += unifdef - -diff --git a/scripts/Makefile.modfinal b/scripts/Makefile.modfinal -index 920545d75da9b3248ef47ff1cdc81c981d3637ba..50c464f248ef7318d089de8719d9766b5964e11a 100644 ---- a/scripts/Makefile.modfinal -+++ b/scripts/Makefile.modfinal -@@ -2,7 +2,7 @@ - # =========================================================================== - # Module final link and CTF generation - # =========================================================================== --# 1) compile all <module>.mod.c files -+# 1) compute SDT offsets, generate SDT stubs, and compile all .mod.c files - # 2) for external modules, generate CTF for the module (there is an extra, - # externally-invoked target that does this for the entire kernel but does - # not invoke the rst of the module-building process) -@@ -32,11 +32,52 @@ modname = $(notdir $(@:.mod.o=)) - part-of-module = y - - quiet_cmd_cc_o_c = CC [M] $@ -- cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $< -+ cmd_cc_o_c = $(CC) $(c_flags) -I$(dir $@) -c -o $@ $< -+ -+quiet_cmd_as_o_S = AS $@ -+ cmd_as_o_S = $(CC) $(a_flags) -c -o $@ $< -+ -+ifdef CONFIG_DTRACE -+ -+sdtgen = $(srctree)/scripts/dtrace_sdt.sh -+ -+quiet_cmd_sdtinfo = SDTINF $@ -+ cmd_sdtinfo = $(sdtgen) sdtinfo $@ $< kmod $(@:.c=.h) -+ -+quiet_cmd_sdtstub = SDTSTB $@ -+ cmd_sdtstub = $(sdtgen) sdtstub $@ $< -+ -+# We depend on the .mod.c file to ensure that modpost runs before sdtinfo. -+$(modules:.ko=.sdtinfo.c): %.sdtinfo.c: %.o %.mod.c -+ $(call cmd,sdtinfo) -+ -+# We depend on the sdtinfo file because info generation rewrites the .o, -+# while sdtstubs reads it. -+$(modules:.ko=.sdtstub.S) : %.sdtstub.S: %.o %.sdtinfo.c -+ $(call cmd,sdtstub) -+ -+%.sdtinfo.o : %.sdtinfo.c -+ $(call if_changed_dep,cc_o_c) -+ -+%.mod.o: %.mod.c %.sdtinfo.c FORCE -+ $(call if_changed_dep,cc_o_c) -+ -+$(modules:.ko=.sdtstub.o): %.sdtstub.o: %.sdtstub.S -+ $(call if_changed,as_o_S) -+ -+module-sdt-modular-prereq = %.sdtstub.o -+sdtinfo-prereq = $(modules:.ko=.sdtinfo.c) -+ -+else - - %.mod.o: %.mod.c FORCE - $(call if_changed_dep,cc_o_c) - -+module-sdt-modular-prereq = -+sdtinfo-prereq = -+ -+endif -+ - # Generate CTF for the entire kernel, or for the module alone if this is a - # build of an external module. - -@@ -95,7 +136,7 @@ $(1) $(wordlist 1,1024,$(2)) - $(if $(word 1025,$(2)),$(call xargs,$(1),$(wordlist 1025,$(words $(2)),$(2)))) - endef - --$(ctf-filelist-raw): $(ctf-builtins-prereq) $(ctf-modules) -+$(ctf-filelist-raw): $(ctf-builtins-prereq) $(ctf-modules) | $(sdtinfo-prereq) - @rm -f $(ctf-filelist-raw); - @if [ -n "$(ctf-dir-mk)" ]; then \ - mkdir -p "$(ctf-dir-mk)"; \ -@@ -123,7 +164,8 @@ vmlinux.ctfa: $(ctf-filelist) - else - - # The CTF depends on the output CTF file list, and that depends --# on the .o files for the modules -+# on the .o files for the modules, and on the sdtinfo files, if any -+# (for the same reason that the sdtstub does). - $(ctf-stamp): $(ctf-filelist) - $(call if_changed,ctf) - @shopt -s nullglob; \ -@@ -170,7 +212,7 @@ quiet_cmd_ld_ko_o = LD [M] $@ - $(OBJCOPY) $(module-ctf-flags) $@.tmp $@ && rm -f $@.tmp ; \ - $(if $(ARCH_POSTLINK), $(MAKE) -f $(ARCH_POSTLINK) $@, true) - --$(modules): %.ko: %.o %.mod.o scripts/module.lds $(module-ctfs-modular-prereq) FORCE -+$(modules): %.ko: %.o %.mod.o %.sdtinfo.o scripts/module.lds $(module-sdt-modular-prereq) $(module-ctfs-modular-prereq) FORCE - $(call cmd_touch_ctf) - +$(call if_changed,ld_ko_o) - -diff --git a/scripts/dtrace_sdt.sh b/scripts/dtrace_sdt.sh -new file mode 100755 -index 0000000000000000000000000000000000000000..2dd7ea1aebd8fed2d5632f438a4e406c91906520 ---- /dev/null -+++ b/scripts/dtrace_sdt.sh -@@ -0,0 +1,588 @@ -+#!/bin/sh -+# SPDX-License-Identifier: GPL-2.0 -+ -+LANG=C -+ -+# -+# Syntax: -+# dtrace_sdt.sh sdtstub <S-file> <o-file>+ -+# This is used to generate DTrace SDT probe stubs based on one -+# or more object file(s). The stubs are written to <S-file>. -+# dtrace_sdt.sh sdtinfo <c-file> <o-file> kmod <h-file> -+# This is used to generate DTrace SDT probe definitions for a -+# kmod .o file. The output is written to <c-file> and <h-file>. -+# dtrace_sdt.sh sdtinfo <S-file> <l-file> -+# This is used to generate DTrace SDT probe definitions for a -+# linked kernel image file <l-file>. The output is written to -+# <S-file>. -+# -+ -+opr="$1" -+shift -+if [ -z "$opr" ]; then -+ echo "ERROR: Missing operation" > /dev/stderr -+ exit 1 -+fi -+ -+tfn="$1" -+shift -+if [ -z "$tfn" ]; then -+ echo "ERROR: Missing target filename" > /dev/stderr -+ exit 1 -+fi -+ -+ofn="$1" -+tok="$2" -+ -+if [ -z "$ofn" ]; then -+ echo "ERROR: Missing object file argument" > /dev/stderr -+ exit 1 -+fi -+ -+if [ "$opr" = "sdtstub" ]; then -+ ${NM} -u $* | grep -E '__dtrace_(probe|isenabled)_' | sort | uniq | \ -+ gawk -v arch=${ARCH} \ -+ '{ -+ printf("\t.globl %s\n\t.type %s,@function\n%s:\n", -+ $2, $2, $2); -+ count++; -+ } -+ -+ END { -+ if (count) { -+ if (arch == "x86" || arch == "x86_64") { -+ print "\txor %eax,%eax"; -+ print "\tretq"; -+ } else if (arch == "sparc" || arch == "sparc64") { -+ print "\tretl"; -+ print "\tnop"; -+ } else if (arch == "arm" || arch == "arm64") { -+ print "\tmov w0, #0x0"; -+ print "\tret"; -+ } -+ } -+ }' > $tfn -+ exit $? -+fi -+ -+if [ "$opr" != "sdtinfo" ]; then -+ echo "ERROR: Invalid operation, should be sdtstub or sdtinfo" > /dev/stderr -+ exit 1 -+fi -+ -+if [ "$tok" = "kmod" ]; then -+ hfile="$3" -+ -+ # Pre-process the object file to handle any local functions that contain -+ # SDT probes. -+ scripts/kmodsdt ${ofn} -+ -+ # Output all function symbols in the symbol table of the object file. -+ # Subsequently, output all relocation records for DTrace SDT probes. The -+ # probes are identified by either a __dtrace_probe_ or __dtrace_isenabled_ -+ # prefix. -+ # -+ # We sort the output primarily based on the section, using the value (or -+ # offset) as secondary sort criterion The overall result is that the -+ # output will be structured as a list of functions, and for any functions -+ # that contain DTrace SDT probes, relocation records will follow the -+ # function entry they are associated with. -+ # -+ # Relocations are reported by objdump per section, with a header line -+ # documenting the specific section being reported: -+ # RELOCATION RECORDS FOR [<section>]: -+ # This is followed by a column header line, and a list of relocations. -+ # The relocations are listed with 3 tokens per line: -+ # <offset> <type> <value> -+ # -+ # Three different types can show up in the output (all with 4 tokens): -+ # <section> <offset> F <value> -+ # Function within a section at a specific offset. -+ # (See STAGE 3a below.) -+ # <section> <offset> G <value> -+ # Global alias for a local function within a section at a specific -+ # offset. A function can only have one alias, and there cannot be -+ # an alias without its respective function. -+ # (See STAGE 3a below.) -+ # <section> <offset> R <value> -+ # Relocation within a section at a specific offset. -+ # (See STAGE 3b below.) -+ # -+ ${OBJDUMP} -tr ${ofn} | \ -+ gawk '/^RELOC/ { -+ sect = substr($4, 2, length($4) - 3); -+ if (sect ~ /^\.(exit|init|meminit)\.text/) -+ sect = 0; -+ -+ next; -+ } -+ -+ sect && /__dtrace_probe_/ { -+ $3 = substr($3, 16); -+ sub(/[\-+].*$/, "", $3); -+ print sect " " $1 " R " $3; -+ next; -+ } -+ -+ sect && /__dtrace_isenabled_/ { -+ $3 = substr($3, 20); -+ sub(/[\-+].*$/, "", $3); -+ print sect " " $1 " R ?" $3; -+ next; -+ } -+ -+ /file format/ { -+ next; -+ } -+ -+ / F / { -+ if ($4 ~ /^\.(exit|init|meminit)\.text/) -+ next; -+ -+ if ($6 == ".hidden") -+ print $4 " " $1 " G " $7; -+ else -+ print $4 " " $1 " F " $6; -+ }' | \ -+ sort -k1,2 | \ -+ gawk -v arch=${ARCH} -v hfile=${hfile} \ -+ 'function subl(v0, v1, v0h, v0l, v1h, v1l, d, tmp) { -+ tmp = $0; -+ if (length(v0) > 8) { -+ d = length(v0); -+ v0h = strtonum("0x"substr(v0, 1, d - 8)); -+ v0l = strtonum("0x"substr(v0, d - 8 + 1)); -+ d = length(v1); -+ v1h = strtonum("0x"substr(v1, 1, d - 8)); -+ v1l = strtonum("0x"substr(v1, d - 8 + 1)); -+ -+ if (v0l >= v1l) { -+ if (v0h >= v1h) { -+ d = sprintf("%08x%08x", v0h - v1h, v0l - v1l); -+ } else { -+ printf "#error Invalid addresses: %s - %s\n", v0, v1 \ -+ >"/dev/stderr"; -+ errc++; -+ } -+ } else { -+ if (v0h > v1h) { -+ v0h--; -+ v0l += 4294967296; -+ d = sprintf("%08x%08x", v0h - v1h, v0l - v1l); -+ } else { -+ printf "#error Invalid addresses: %s - %s\n", v0, v1 \ -+ >"/dev/stderr"; -+ errc++; -+ } -+ } -+ } else { -+ v0 = strtonum("0x"v0); -+ v1 = strtonum("0x"v1); -+ d = sprintf("%016x", v0 - v1); -+ } -+ $0 = tmp; -+ -+ return d; -+ } -+ -+ BEGIN { -+ print "#include <linux/sdt.h>"; -+ -+ probec = 0; -+ } -+ -+ # -+ # Process a symbol table definition for a function in the object -+ # file ($ofn). As we pass through the symbol table, we record the -+ # function name, address, and symbol table index or alias. This -+ # information is needed for any potential DTrace probes that may exist -+ # in the function. They will be listed in relocation records -+ # subsequent to this function definition (and are processed in the -+ # next action block). -+ # -+ NF == 4 && $3 == "F" { -+ fname = $4; -+ sub(/\..*$/, "", fname); -+ alias = $4; -+ faddr = $2; -+ sub(/^0+/, "", faddr); -+ -+ next; -+ } -+ -+ NF == 4 && $3 == "G" { -+ alias = $4; -+ -+ next; -+ } -+ -+ # -+ # Process a relocation record associated with the preceding function. -+ # -+ # For kernel modules: -+ # Convert the section offset into an offset in the function where the -+ # DTrace probe is located, i.e. an offset from the start of the -+ # function. This will be resolved in an absolute address at runtime -+ # when the module is loaded. -+ # -+ NF == 4 && $3 == "R" { -+ sub(/^0+/, "", $2); -+ -+ addr = subl($2, faddr); -+ -+ if (arch == "x86" || arch == "x86_64") -+ addr = subl(addr, 1); -+ -+ protom[alias] = 1; -+ probev[probec] = sprintf(" {\042%s\042, \042%s\042 /* %s */, 0 /* sdt_args string */, (uintptr_t)%s+0x%s },", $4, fname, $1, alias, addr); -+ probec++; -+ -+ next; -+ } -+ -+ END { -+ for (alias in protom) -+ printf "extern void %s(void);\n", alias; -+ print "\nstruct sdt_probedesc\t_sdt_probes[] = {"; -+ for (i = 0; i < probec; i++) -+ print probev[i]; -+ print "};\n"; -+ -+ print "#define _sdt_probec\t" probec > hfile; -+ print "extern struct sdt_probedesc _sdt_probes[];" >> hfile; -+ -+ exit(errc == 0 ? 0 : 1); -+ }' > $tfn -+else -+ # For a linked kernel (with relocation data), the scope of the DTrace SDT -+ # probe discovery can be limited to CODE sections that are not included in -+ # the init or exit code sections. -+ # -+ # First the sections records are parsed to order to determine the base -+ # address for each relevant section. -+ # -+ # Subsequently, all function symbols that are located in the sections we -+ # care about are read from the symbol table of the linked kernel object. -+ # Each symbol is reported in the output stream with its section name, -+ # address, a token identifying it as a function (or alias), and its name. -+ # -+ # Finally, each relocation record from relevant sections that relates to -+ # SDT probes are written to the output stream with its section name, -+ # address, a token # identifying it as a relocation, and its name. Probes -+ # are identified in the relocation records as symbols with either a -+ # __dtrace_probe_ or __dtrace_isenabled_ prefix. -+ # -+ # We sort the output based on the section name and address, ensuring that -+ # the output will be a list of functions, and each function record will be -+ # followed immediately by any DTrace SDT probe records that are used in -+ # that function. -+ # -+ # Three different record types can show up in the output (4 tokens each): -+ # <section> <address> F <name> -+ # Named function at a specific address. -+ # <section> <address> G <name> -+ # Global alias for a local function at a specific offset. A -+ # function can only have one alias, and there cannot be an alias -+ # without its respective function. -+ # <section> <address> R <value> -+ # Relocation within a section at a specific address -+ # -+ ${OBJDUMP} -htr ${ofn} | \ -+ gawk 'function addl(v0, v1, v0h, v0l, v1h, v1l, d, tmp) { -+ tmp = $0; -+ if (length(v0) > 8 || length(v1) > 8) { -+ d = length(v0); -+ v0h = strtonum("0x"substr(v0, 1, d - 8)); -+ v0l = strtonum("0x"substr(v0, d - 8 + 1)); -+ d = length(v1); -+ v1h = strtonum("0x"substr(v1, 1, d - 8)); -+ v1l = strtonum("0x"substr(v1, d - 8 + 1)); -+ -+ v0l += v1l; -+ v0h += v1h; -+ d = sprintf("%x", v0l); -+ if (length(d) > 8) { -+ v0h++; -+ v0l -= 4294967296; -+ } -+ d = sprintf("%x", v0h); -+ if (length(d) <= 8) { -+ d = sprintf("%08x%08x", v0h, v0l); -+ } else { -+ printf "#error Invalid addresses: %s + %s\n", v0, v1 \ -+ >"/dev/stderr"; -+ errc++; -+ } -+ } else { -+ v0 = strtonum("0x"v0); -+ v1 = strtonum("0x"v1); -+ d = sprintf("%016x", v0 + v1); -+ } -+ $0 = tmp; -+ -+ return d; -+ } -+ -+ function subl(v0, v1, v0h, v0l, v1h, v1l, d, tmp) { -+ tmp = $0; -+ if (length(v0) > 8) { -+ d = length(v0); -+ v0h = strtonum("0x"substr(v0, 1, d - 8)); -+ v0l = strtonum("0x"substr(v0, d - 8 + 1)); -+ d = length(v1); -+ v1h = strtonum("0x"substr(v1, 1, d - 8)); -+ v1l = strtonum("0x"substr(v1, d - 8 + 1)); -+ -+ if (v0l >= v1l) { -+ if (v0h >= v1h) { -+ d = sprintf("%08x%08x", v0h - v1h, v0l - v1l); -+ } else { -+ printf "#error Invalid addresses: %s - %s\n", v0, v1 \ -+ >"/dev/stderr"; -+ errc++; -+ } -+ } else { -+ if (v0h > v1h) { -+ v0h--; -+ v0l += 4294967296; -+ d = sprintf("%08x%08x", v0h - v1h, v0l - v1l); -+ } else { -+ printf "#error Invalid addresses: %s - %s\n", v0, v1 \ -+ >"/dev/stderr"; -+ errc++; -+ } -+ } -+ } else { -+ v0 = strtonum("0x"v0); -+ v1 = strtonum("0x"v1); -+ d = sprintf("%016x", v0 - v1); -+ } -+ $0 = tmp; -+ -+ return d; -+ } -+ -+ NF == 7 && $2 !~ /^\.(exit|init|meminit)\.text/ { -+ snam = $2; -+ addr = $4; -+ -+ getline; -+ if (/CODE/) -+ base[snam] = addr; -+ -+ next; -+ } -+ -+ NF == 5 && $2 == "g" && $NF == "_stext" { -+ print ". " $1 " B _stext"; -+ next; -+ } -+ -+ /^RELOC/ { -+ snam = substr($4, 2, length($4) - 3); -+ if (snam in base) -+ in_reloc = 1; -+ else -+ in_reloc = 0; -+ next; -+ } -+ -+ in_reloc && /__dtrace_probe_/ { -+ $3 = substr($3, 16); -+ sub(/[\-+].*$/, "", $3); -+ print snam " " addl(base[snam], $1) " R " $3; -+ next; -+ } -+ -+ in_reloc && /__dtrace_isenabled_/ { -+ $3 = substr($3, 20); -+ sub(/[\-+].*$/, "", $3); -+ print snam " " addl(base[snam], $1) " R ?" $3; -+ next; -+ } -+ -+ / F / { -+ if (!($4 in base)) -+ next; -+ -+ if ($6 == ".hidden") -+ print $4 " " $1 " G " $7; -+ else -+ print $4 " " $1 " F " $6; -+ }' | \ -+ sort -k2 | \ -+ gawk -v arch=${ARCH} \ -+ 'function subl(v0, v1, v0h, v0l, v1h, v1l, d, tmp) { -+ tmp = $0; -+ if (length(v0) > 8) { -+ d = length(v0); -+ v0h = strtonum("0x"substr(v0, 1, d - 8)); -+ v0l = strtonum("0x"substr(v0, d - 8 + 1)); -+ d = length(v1); -+ v1h = strtonum("0x"substr(v1, 1, d - 8)); -+ v1l = strtonum("0x"substr(v1, d - 8 + 1)); -+ -+ if (v0l >= v1l) { -+ if (v0h >= v1h) { -+ d = sprintf("%08x%08x", v0h - v1h, v0l - v1l); -+ } else { -+ printf "#error Invalid addresses: %x vs %x", v0, v1 \ -+ >"/dev/stderr"; -+ errc++; -+ } -+ } else { -+ printf "#error Invalid addresses: %x vs %x", v0, v1 \ -+ >"/dev/stderr"; -+ errc++; -+ } -+ } else { -+ v0 = strtonum("0x"v0); -+ v1 = strtonum("0x"v1); -+ d = sprintf("%016x", v0 - v1); -+ } -+ $0 = tmp; -+ -+ return d; -+ } -+ -+ function map_string(str, off) { -+ if (str in strmap) -+ off = strmap[str]; -+ else { -+ off = strsz; -+ strmap[str] = strsz; -+ strv[strc++] = str; -+ strsz += length(str) + 1; -+ } -+ -+ return off; -+ } -+ -+ BEGIN { -+ print "#include <asm/types.h>"; -+ print "#if BITS_PER_LONG == 64"; -+ print "# define PTR .quad"; -+ if (arch == "aarch64") -+ print "# define ALGN .align 3"; -+ else -+ print "# define ALGN .align 8"; -+ print "#else"; -+ print "# define PTR .long"; -+ if (arch == "aarch64") -+ print "# define ALGN .align 2"; -+ else -+ print "# define ALGN .align 4"; -+ print "#endif"; -+ -+ print "\t.section .rodata, \042a\042"; -+ print ""; -+ -+ print ".globl dtrace_sdt_probes"; -+ print "\tALGN"; -+ print "dtrace_sdt_probes:"; -+ -+ probec = 0; -+ stroff = 0; -+ strc = 0; -+ } -+ -+ -+ # -+ # Record the _stext address so probe locations can be expressed -+ # relative to that address. -+ # -+ NF == 4 && $1 == "." && $4 == "_stext" { -+ stext = $2; -+ next; -+ } -+ -+ # -+ # Process a symbol table definition for a function in the .text -+ # section of the kernel image. We record the function name and -+ # the address, and pre-populate the alias name with the function -+ # name. -+ # -+ # We also compare the address of the current symbol to the last -+ # recorded address, and if they are the same, we do not increment -+ # the function count. -+ # -+ NF == 4 && $3 == "F" { -+ faddr = $2; -+ fname = $4; -+ sub(/\..*$/, "", fname); -+ alias = $4; -+ -+ if ($2 != prev) -+ funcc++; -+ prev = $2; -+ -+ next; -+ } -+ -+ # -+ # When we encounter an alias symbol, we record the name. -+ # -+ NF == 4 && $3 == "G" { -+ alias = $4; -+ -+ next; -+ } -+ -+ # -+ # Process a relocation record associated with the preceding function. -+ # -+ # The address was resolved earlier, so we can simply generate the -+ # numeric information for the SDT probe information record. The -+ # text information (probe name and function name) are stored. This -+ # allows us to weed out duplicates, and it is necessary because the -+ # data blob with all the strings will be written to output later. -+ # -+ NF == 4 && $3 == "R" { -+ sub(/^0+/, "", $2); -+ -+ addr = subl($2, stext); -+ -+ # -+ # On x86, relocations point to the 2nd byte of a call instruction -+ # so we need to adjust the address. -+ # -+ if (arch == "x86" || arch == "x86_64") -+ addr = subl(addr, 1); -+ -+ print "/*"; -+ print " * " $1 " " faddr " F " fname; -+ print " * " $0; -+ print " */"; -+ printf "\tPTR\t_stext + 0x%s\n", addr; -+ printf "\tPTR\t%d\n", map_string($4); -+ printf "\tPTR\t%d\n", map_string(fname); -+ -+ probec++; -+ -+ next; -+ } -+ -+ END { -+ print ""; -+ print ".globl dtrace_sdt_strings"; -+ print "\tALGN"; -+ print "dtrace_sdt_strings:"; -+ -+ -+ for (i = 0; i < strc; i++) -+ printf "\t.asciz\t\042%s\042\n", strv[i]; -+ -+ print ""; -+ print ".globl dtrace_sdt_nprobes"; -+ print ".globl dtrace_fbt_nfuncs"; -+ print "\tALGN"; -+ print "dtrace_sdt_nprobes:"; -+ printf "\tPTR\t%d\n", probec; -+ print "dtrace_fbt_nfuncs:"; -+ printf "\tPTR\t%d\n", funcc; -+ -+ exit(errc == 0 ? 0 : 1); -+ }' > $tfn -+fi -+ -+exit $? -diff --git a/scripts/kmodsdt.c b/scripts/kmodsdt.c -new file mode 100644 -index 0000000000000000000000000000000000000000..1e35794467d75ea0fd8e324eac97223fd3dc2ce5 ---- /dev/null -+++ b/scripts/kmodsdt.c -@@ -0,0 +1,410 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright 2016 Oracle, Inc. All rights reserved. -+ * Use is subject to license terms. -+ */ -+ -+#include "../include/generated/autoconf.h" -+ -+#define ELF_TARGET_ALL -+#include <elf.h> -+#include <gelf.h> -+ -+#include <sys/types.h> -+ -+#include <unistd.h> -+#include <string.h> -+#include <limits.h> -+#include <stddef.h> -+#include <stdlib.h> -+#include <stdio.h> -+#include <fcntl.h> -+#include <errno.h> -+#include <assert.h> -+ -+typedef struct symtbl { -+ struct symtbl *next; -+ void *strtab; -+ void *symtab; -+} symtbl_t; -+ -+static int -+dt_elf_symtab_lookup(Elf_Data *data_sym, int nsym, uintptr_t addr, uint32_t shn, -+ GElf_Sym *sym) -+{ -+ int i, ret = -1; -+ GElf_Sym s; -+ -+ for (i = 0; i < nsym && gelf_getsym(data_sym, i, sym) != NULL; i++) { -+ if (GELF_ST_TYPE(sym->st_info) == STT_FUNC && -+ shn == sym->st_shndx && -+ sym->st_value <= addr && -+ addr < sym->st_value + sym->st_size) { -+ if (GELF_ST_BIND(sym->st_info) == STB_GLOBAL) -+ return i; -+ -+ ret = i; -+ s = *sym; -+ } -+ } -+ -+ if (ret >= 0) -+ *sym = s; -+ return ret; -+} -+ -+static int -+process_obj(const char *obj) -+{ -+ static const char dt_ppref[] = "__dtrace_probe_"; -+ static const char dt_spref[] = "__dta_"; -+ int fd, i, sidx, mod = 0; -+ Elf *elf = NULL; -+ GElf_Ehdr ehdr; -+ Elf_Scn *scn_rel, *scn_sym, *scn_str; -+ Elf_Data *data_rel, *data_sym, *data_str; -+ GElf_Shdr shdr_rel, shdr_sym, shdr_str; -+ GElf_Sym rsym, fsym, dsym; -+ GElf_Rela rela; -+ char *p, *r, *f, *a; -+ uint32_t eclass, emachine1, emachine2; -+ size_t symsize, nsym, nstr, isym, istr, osym, len; -+ symtbl_t *pair, *bufs = NULL; -+ char **alttab; -+ const char *elferrstr = "no error"; -+ -+ fd = open(obj, O_RDWR); -+ if (fd == -1) { -+ fprintf(stderr, "failed to open %s: %s\n", obj, -+ strerror(errno)); -+ return 1; -+ } -+ -+ if (elf_version(EV_CURRENT) == EV_NONE) { -+ fprintf(stderr, "ELF library version too old\n"); -+ return 1; -+ } -+ -+ elf = elf_begin(fd, ELF_C_RDWR, NULL); -+ if (elf == NULL) { -+ fprintf(stderr, "failed to process %s: %s\n", obj, -+ elf_errmsg(elf_errno())); -+ return 1; -+ } -+ -+ switch (elf_kind(elf)) { -+ case ELF_K_ELF: -+ break; -+ case ELF_K_AR: -+ fprintf(stderr, "archives are not permitted; %s\n", obj); -+ return 1; -+ default: -+ fprintf(stderr, "invalid file type: %s\n", obj); -+ return 1; -+ } -+ -+ if (gelf_getehdr(elf, &ehdr) == NULL) { -+ fprintf(stderr, "corrupt file: %s\n", obj); -+ return 1; -+ } -+ -+#ifdef CONFIG_64BIT -+ eclass = ELFCLASS64; -+# if defined(__sparc) -+ emachine1 = emachine2 = EM_SPARCV9; -+# elif defined(__i386) || defined(__amd64) -+ emachine1 = emachine2 = EM_X86_64; -+# elif defined(__aarch64__) -+ emachine1 = emachine2 = EM_AARCH64; -+# endif -+ symsize = sizeof(Elf64_Sym); -+#else -+ eclass = ELFCLASS32; -+# if defined(__sparc) -+ emachine1 = EM_SPARC; -+ emachine2 = EM_SPARC32PLUS; -+# elif defined(__i386) || defined(__amd64) -+ emachine1 = emachine2 = EM_386; -+# elif defined(__arm__) -+ emachine1 = emachine2 = EM_ARM; -+# endif -+ symsize = sizeof(Elf32_Sym); -+#endif -+ -+ if (ehdr.e_ident[EI_CLASS] != eclass) { -+ fprintf(stderr, "incorrect ELF class for %s: %d " -+ "(expected %d)\n", obj, ehdr.e_ident[EI_CLASS], -+ eclass); -+ return 1; -+ } -+ if (ehdr.e_machine != emachine1 && ehdr.e_machine != emachine2) { -+ fprintf(stderr, "incorrect ELF machine type for %s: %d " -+ "(expected %d or %d)\n", -+ obj, ehdr.e_machine, emachine1, emachine2); -+ return 1; -+ } -+ -+ scn_rel = NULL; -+ while ((scn_rel = elf_nextscn(elf, scn_rel)) != NULL) { -+ if (gelf_getshdr(scn_rel, &shdr_rel) == NULL) { -+ elferrstr = "failed to get section header"; -+ goto elf_err; -+ } -+ -+ /* -+ * Skip any non-relocation sections. -+ */ -+ if (shdr_rel.sh_type != SHT_RELA && shdr_rel.sh_type != SHT_REL) -+ continue; -+ -+ data_rel = elf_getdata(scn_rel, NULL); -+ if (data_rel == NULL) { -+ elferrstr = "failed to get relocation data"; -+ goto elf_err; -+ } -+ -+ /* -+ * Grab the section, section header and section data for the -+ * symbol table that this relocation section references. -+ */ -+ scn_sym = elf_getscn(elf, shdr_rel.sh_link); -+ if (scn_sym == NULL || -+ gelf_getshdr(scn_sym, &shdr_sym) == NULL || -+ (data_sym = elf_getdata(scn_sym, NULL)) == NULL) { -+ elferrstr = "failed to get symbol table"; -+ goto elf_err; -+ } -+ -+ /* -+ * Ditto for that symbol table's string table. -+ */ -+ scn_str = elf_getscn(elf, shdr_sym.sh_link); -+ if (scn_str == NULL || -+ gelf_getshdr(scn_str, &shdr_str) == NULL || -+ (data_str = elf_getdata(scn_str, NULL)) == NULL) { -+ elferrstr = "failed to get string table"; -+ goto elf_err; -+ } -+ -+ /* -+ * We're looking for relocations to symbols matching this form: -+ * -+ * __dtrace_probe_<probe> -+ * -+ * If the function containing the probe is locally scoped -+ * (static), we create an alias. The alias, a new symbol, -+ * will be global (so that it can be referenced from sdtinfo -+ * entries) and hidden (so that it is converted to a local -+ * symbol at link time). Such aliases have this form: -+ * -+ * __dta_<function>_<symindex> -+ * -+ * The <symindex> is appended to ensure that aliases are unique -+ * because they are referenced in global scope. Two local -+ * functions with identical names need to be distrinct at the -+ * level of the aliases. -+ * -+ * We take a first pass through all the relocations to -+ * populate our string table and count the number of extra -+ * symbols we'll require. Note that the <function> is -+ * sanitized to ensure that it is a valid C identifier, i.e. -+ * any periods in the name are converted to underscores. -+ */ -+ isym = osym = data_sym->d_size / symsize; -+ istr = data_str->d_size; -+ -+ /* -+ * Allocate the alias table to be the exact same size as the -+ * symtab. If an alias is required for a specific symbol, its -+ * corresponding entry in this alias table will contain the -+ * alias name. Otherwise, the entry will be NULL. -+ */ -+ alttab = (char **)calloc(isym, sizeof(char *)); -+ -+ nsym = 0; -+ nstr = 0; -+ -+ for (i = 0; i < shdr_rel.sh_size / shdr_rel.sh_entsize; i++) { -+ if (shdr_rel.sh_type == SHT_RELA) { -+ if (gelf_getrela(data_rel, i, &rela) == NULL) -+ continue; -+ } else { -+ GElf_Rel rel; -+ -+ if (gelf_getrel(data_rel, i, &rel) == NULL) -+ continue; -+ rela.r_offset = rel.r_offset; -+ rela.r_info = rel.r_info; -+ rela.r_addend = 0; -+ } -+ -+ if (gelf_getsym(data_sym, GELF_R_SYM(rela.r_info), -+ &rsym) == NULL) { -+ elferrstr = "relocation symbol not found"; -+ goto elf_err; -+ } -+ -+ assert(rsym.st_name < data_str->d_size); -+ -+ r = (char *)data_str->d_buf + rsym.st_name; -+ if (strncmp(r, dt_ppref, sizeof(dt_ppref) - 1) != 0) -+ continue; -+ -+ sidx = dt_elf_symtab_lookup(data_sym, isym, -+ rela.r_offset, -+ shdr_rel.sh_info, &fsym); -+ if (sidx < 0) { -+ fprintf(stderr, "relocation %x not in " -+ "function\n", i); -+ goto err; -+ } -+ -+ assert(fsym.st_name < data_str->d_size); -+ assert(GELF_ST_TYPE(fsym.st_info) == STT_FUNC); -+ -+ if (GELF_ST_BIND(fsym.st_info) != STB_LOCAL) -+ continue; -+ -+ f = (char *)data_str->d_buf + fsym.st_name; -+ -+ if (alttab[sidx] != NULL) -+ continue; -+ -+ len = snprintf(NULL, 0, "%s%s_%d", dt_spref, f, sidx) -+ + 1; -+ a = malloc(len); -+ assert(a != NULL); -+ nstr += snprintf(a, len, "%s%s_%d", dt_spref, f, sidx) -+ + 1; -+ for (p = a; *p != '\0'; p++) { -+ if (*p == '.') -+ *p = '_'; -+ } -+ alttab[sidx] = a; -+ nsym++; -+ } -+ -+ if (!nsym) { -+ free(alttab); -+ continue; -+ } -+ -+ pair = malloc(sizeof(symtbl_t)); -+ if (pair == NULL) { -+ fprintf(stderr, "failed to alloc new symtbl\n"); -+ goto err; -+ } -+ pair->strtab = malloc(data_str->d_size + nstr); -+ if (pair->strtab == NULL) { -+ fprintf(stderr, "failed to alloc new symtbl->strtab\n"); -+ free(pair); -+ goto err; -+ } -+ pair->symtab = malloc(data_sym->d_size + nsym * symsize); -+ if (pair->symtab == NULL) { -+ fprintf(stderr, "failed to alloc new symtbl->symtab\n"); -+ free(pair->strtab); -+ free(pair); -+ goto err; -+ } -+ -+ pair->next = bufs; -+ bufs = pair; -+ -+ memcpy(pair->strtab, data_str->d_buf, data_str->d_size); -+ data_str->d_buf = pair->strtab; -+ data_str->d_size += nstr; -+ elf_flagdata(data_str, ELF_C_SET, ELF_F_DIRTY); -+ shdr_str.sh_size += nstr; -+ gelf_update_shdr(scn_str, &shdr_str); -+ -+ memcpy(pair->symtab, data_sym->d_buf, data_sym->d_size); -+ data_sym->d_buf = pair->symtab; -+ data_sym->d_size += nsym * symsize; -+ elf_flagdata(data_sym, ELF_C_SET, ELF_F_DIRTY); -+ shdr_sym.sh_size += nsym * symsize; -+ gelf_update_shdr(scn_sym, &shdr_sym); -+ -+ nsym += isym; -+ -+ /* -+ * Now that the tables have been allocated, add the aliases as -+ * described above. Since we already know the symtab index of -+ * the symbol that the alias refers to, we can simply run down -+ * the alttab and add alias for any non-NULL entries. -+ */ -+ for (i = 1; i < osym; i++) { -+ if (alttab[i] == NULL) -+ continue; -+ -+ if (gelf_getsym(data_sym, i, &fsym) == NULL) { -+ fprintf(stderr, "failed to get symbol %d: %s\n", -+ i, elf_errmsg(elf_errno())); -+ goto err; -+ } -+ -+ assert(GELF_ST_TYPE(fsym.st_info) == STT_FUNC); -+ assert(GELF_ST_BIND(fsym.st_info) == STB_LOCAL); -+ /* -+ * Add the alias as a new symbol to the symtab. -+ */ -+ dsym = fsym; -+ dsym.st_name = istr; -+ dsym.st_info = GELF_ST_INFO(STB_GLOBAL, STT_FUNC); -+ dsym.st_other = ELF64_ST_VISIBILITY(STV_HIDDEN); -+ -+ len = strlen(alttab[i]) + 1; -+ assert(istr + len <= data_str->d_size); -+ a = (char *)data_str->d_buf + istr; -+ memcpy(a, alttab[i], len); -+ -+ gelf_update_sym(data_sym, isym, &dsym); -+ istr += len; -+ isym++; -+ -+ assert(isym <= nsym); -+ -+ mod = 1; -+ -+ free(alttab[i]); -+ } -+ -+ free(alttab); -+ } -+ -+ if (mod && elf_update(elf, ELF_C_WRITE) == -1) { -+ elferrstr = "Failed to update ELF object"; -+ goto elf_err; -+ } -+ -+ elf_end(elf); -+ close(fd); -+ -+ while ((pair = bufs) != NULL) { -+ bufs = pair->next; -+ free(pair->strtab); -+ free(pair->symtab); -+ free(pair); -+ } -+ -+ return 0; -+ -+elf_err: -+ fprintf(stderr, "%s: %s\n", elferrstr, elf_errmsg(elf_errno())); -+err: -+ fprintf(stderr, "an error was encountered while processing %s\n", obj); -+ return 1; -+} -+ -+int -+main(int argc, char *argv[]) -+{ -+ int i; -+ -+ for (i = 1; i < argc; i++) { -+ if (process_obj(argv[i])) -+ exit(1); -+ } -+ -+ exit(0); -+} -diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh -index bc533252fa3c39482a870654036caf3897946123..0b2f3bb60936f81449de21f296bdaddd466c9569 100755 ---- a/scripts/link-vmlinux.sh -+++ b/scripts/link-vmlinux.sh -@@ -43,6 +43,34 @@ info() - fi - } - -+# Generate the SDT probe point stubs object file -+# ${1} output file -+sdtstub() -+{ -+ info SDTSTB ${1} -+ ${srctree}/scripts/dtrace_sdt.sh sdtstub .tmp_sdtstub.S \ -+ ${KBUILD_VMLINUX_OBJS} -+ -+ local aflags="${KBUILD_AFLAGS} ${KBUILD_AFLAGS_KERNEL} \ -+ ${NOSTDINC_FLAGS} ${LINUXINCLUDE} ${KBUILD_CPPFLAGS}" -+ -+ ${CC} ${aflags} -c -o ${1} .tmp_sdtstub.S -+} -+ -+# Generate the SDT probe info for kernel image ${1} -+# ${2} output file -+sdtinfo() -+{ -+ info SDTINF ${2} -+ -+ ${srctree}/scripts/dtrace_sdt.sh sdtinfo .tmp_sdtinfo.S ${1} -+ -+ local aflags="${KBUILD_AFLAGS} ${KBUILD_AFLAGS_KERNEL} \ -+ ${NOSTDINC_FLAGS} ${LINUXINCLUDE} ${KBUILD_CPPFLAGS}" -+ -+ ${CC} ${aflags} -c -o ${2} .tmp_sdtinfo.S -+} -+ - # Link of vmlinux.o used for section mismatch analysis - # ${1} output file - modpost_link() -@@ -84,17 +112,20 @@ objtool_link() - - # Link of vmlinux - # ${1} - output file --# ${2}, ${3}, ... - optional extra .o files -+# ${2} - optional extra ld flag(s) -+# ${3}, ${4}, ... - optional extra .o files - vmlinux_link() - { - local lds="${objtree}/${KBUILD_LDS}" - local output=${1} -+ local flags="${2}" - local objects - local strip_debug - - info LD ${output} - -- # skip output file argument -+ # skip output file and flags arguments -+ shift - shift - - # The kallsyms linking does not need debug symbols included. -@@ -114,7 +145,7 @@ vmlinux_link() - - ${LD} ${KBUILD_LDFLAGS} ${LDFLAGS_vmlinux} \ - ${strip_debug#-Wl,} \ -- -o ${output} \ -+ ${flags} -o ${output} \ - -T ${lds} ${objects} - else - objects="-Wl,--whole-archive \ -@@ -128,7 +159,7 @@ vmlinux_link() - - ${CC} ${CFLAGS_vmlinux} \ - ${strip_debug} \ -- -o ${output} \ -+ ${flags} -o ${output} \ - -Wl,-T,${lds} \ - ${objects} \ - -lutil -lrt -lpthread -@@ -219,7 +250,7 @@ kallsyms_step() - kallsymso=${kallsyms_vmlinux}.o - kallsyms_S=${kallsyms_vmlinux}.S - -- vmlinux_link ${kallsyms_vmlinux} "${kallsymso_prev}" ${btf_vmlinux_bin_o} -+ vmlinux_link ${kallsyms_vmlinux} "${2:-}" "${kallsymso_prev}" ${btf_vmlinux_bin_o} ${sdtstubo} ${sdtinfoo} - kallsyms ${kallsyms_vmlinux} ${kallsyms_S} - - info AS ${kallsyms_S} -@@ -245,6 +276,8 @@ cleanup() - { - rm -f .btf.* - rm -f .tmp_System.map -+ rm -f .tmp_sdtstub.* -+ rm -f .tmp_sdtinfo.* - rm -f .tmp_vmlinux* - rm -f System.map - rm -f vmlinux -@@ -293,6 +326,14 @@ fi; - # final build of init/ - ${MAKE} -f "${srctree}/scripts/Makefile.build" obj=init need-builtin=1 - -+sdtstubo="" -+sdtinfoo="" -+if [ -n "${CONFIG_DTRACE}" ]; then -+ sdtstubo=.tmp_sdtstub.o -+ sdtinfoo=.tmp_sdtinfo.o -+ sdtstub ${sdtstubo} -+fi -+ - #link vmlinux.o - info LD vmlinux.o - modpost_link vmlinux.o -@@ -346,7 +387,23 @@ if [ -n "${CONFIG_KALLSYMS}" ]; then - # a) Verify that the System.map from vmlinux matches the map from - # ${kallsymso}. - -+ # step 1 -+ if [ -n "${CONFIG_DTRACE}" ]; then -+ sdtinfo vmlinux.o ${sdtinfoo} -+ fi -+ - kallsyms_step 1 -+ -+ if [ -n "${CONFIG_DTRACE}" ]; then -+ if [ -n "${CONFIG_ARM64}" ]; then -+ kallsyms_step 1 -+ else -+ kallsyms_step 1 -r -+ fi -+ sdtinfo ${kallsyms_vmlinux} ${sdtinfoo} vmlinux.o -+ fi -+ -+ # step 2 - kallsyms_step 2 - - # step 3 -@@ -358,7 +415,7 @@ if [ -n "${CONFIG_KALLSYMS}" ]; then - fi - fi - --vmlinux_link vmlinux "${kallsymso}" ${btf_vmlinux_bin_o} -+vmlinux_link vmlinux "" "${kallsymso}" ${btf_vmlinux_bin_o} ${sdtstubo} ${sdtinfoo} - - # fill in BTF IDs - if [ -n "${CONFIG_DEBUG_INFO_BTF}" -a -n "${CONFIG_BPF}" ]; then -diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c -index f882ce0d9327f857049e914196b2e03c38dea9b1..ceeb69afc2091694194d42a93693ff081f7b87fe 100644 ---- a/scripts/mod/modpost.c -+++ b/scripts/mod/modpost.c -@@ -2183,7 +2183,9 @@ static int check_exports(struct module *mod) - const char *basename; - exp = find_symbol(s->name); - if (!exp || exp->module == mod) { -- if (have_vmlinux && !s->weak) { -+ if (have_vmlinux && !s->weak && -+ !strstarts(s->name, "__dtrace_probe_") && -+ !strstarts(s->name, "__dtrace_isenabled_")) { - modpost_log(warn_unresolved ? LOG_WARN : LOG_ERROR, - "\"%s\" [%s.ko] undefined!\n", - s->name, mod->name); -@@ -2238,6 +2240,13 @@ static int check_modname_len(struct module *mod) - **/ - static void add_header(struct buffer *b, struct module *mod) - { -+ const char *modname; -+ -+ modname = strrchr(mod->name, '/'); -+ if (modname != NULL) -+ modname++; -+ else -+ modname = mod->name; - buf_printf(b, "#include <linux/module.h>\n"); - /* - * Include build-salt.h after module.h in order to -@@ -2248,6 +2257,10 @@ static void add_header(struct buffer *b, struct module *mod) - buf_printf(b, "#include <linux/vermagic.h>\n"); - buf_printf(b, "#include <linux/compiler.h>\n"); - buf_printf(b, "\n"); -+ buf_printf(b, "#ifdef CONFIG_DTRACE\n"); -+ buf_printf(b, "# include \"%s.sdtinfo.h\"\n", modname); -+ buf_printf(b, "#endif\n"); -+ buf_printf(b, "\n"); - buf_printf(b, "BUILD_SALT;\n"); - buf_printf(b, "\n"); - buf_printf(b, "MODULE_INFO(vermagic, VERMAGIC_STRING);\n"); -@@ -2263,6 +2276,10 @@ static void add_header(struct buffer *b, struct module *mod) - "\t.exit = cleanup_module,\n" - "#endif\n"); - buf_printf(b, "\t.arch = MODULE_ARCH_INIT,\n"); -+ buf_printf(b, "#ifdef CONFIG_DTRACE\n"); -+ buf_printf(b, "\t.sdt_probes = _sdt_probes,\n"); -+ buf_printf(b, "\t.sdt_probec = _sdt_probec,\n"); -+ buf_printf(b, "#endif\n"); - buf_printf(b, "};\n"); - } - --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/dtrace-patches/0009-dtrace-sdt-provider-for-x86.patch b/sys-kernel/cairn-sources/files/5.10.14/dtrace-patches/0009-dtrace-sdt-provider-for-x86.patch deleted file mode 100644 index 9931c75853b5..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/dtrace-patches/0009-dtrace-sdt-provider-for-x86.patch +++ /dev/null @@ -1,1076 +0,0 @@ -From 33bb9a2aab1f792110ebeebcc2a5a0b5e02cec6c Mon Sep 17 00:00:00 2001 -From: Kris Van Hees <kris.van.hees@oracle.com> -Date: Mon, 19 Nov 2018 18:00:18 +0000 -Subject: [PATCH 09/19] dtrace: sdt provider for x86 - -This implements the SDT provider itself. It is relatively -straightforward except for the code needed to parse the argument strings -ultimately derived from SDT DTRACE_PROBE invocations and perf-event -prototype definitions. - -Signed-off-by: Kris Van Hees <kris.van.hees@oracle.com> -Signed-off-by: Nick Alcock <nick.alcock@oracle.com> -Signed-off-by: Tomas Jedlicka <tomas.jedlicka@oracle.com> -Signed-off-by: Eugene Loh <eugene.loh@oracle.com> -Signed-off-by: David Mc Lean <david.mclean@oracle.com> -Signed-off-by: Vincent Lim <vincent.lim@oracle.com> ---- - arch/x86/dtrace/Makefile.arch | 2 + - arch/x86/dtrace/sdt_x86_64.c | 126 ++++++++ - dtrace/Makefile | 2 + - dtrace/dt_test_dev.c | 33 ++ - dtrace/dt_test_mod.c | 5 + - dtrace/sdt_dev.c | 562 ++++++++++++++++++++++++++++++++++ - dtrace/sdt_impl.h | 87 ++++++ - dtrace/sdt_mod.c | 154 ++++++++++ - 8 files changed, 971 insertions(+) - create mode 100644 arch/x86/dtrace/sdt_x86_64.c - create mode 100644 dtrace/sdt_dev.c - create mode 100644 dtrace/sdt_impl.h - create mode 100644 dtrace/sdt_mod.c - -diff --git a/arch/x86/dtrace/Makefile.arch b/arch/x86/dtrace/Makefile.arch -index ffb9ef4d1722b673511418c5744067ac501d49c5..8492eaee426d1ba7a25769ff3c95d1dc828f69ae 100644 ---- a/arch/x86/dtrace/Makefile.arch -+++ b/arch/x86/dtrace/Makefile.arch -@@ -7,5 +7,7 @@ DTARCHDIR = ../arch/x86/dtrace - ccflags-y += -I$(srctree)/arch/x86/dtrace/include -Idtrace - - dtrace-obj += dtrace_asm_x86_64.o dtrace_isa_x86_64.o -+sdt-obj += sdt_x86_64.o - - dtrace-y += $(addprefix $(DTARCHDIR)/, $(dtrace-obj)) -+sdt-y += $(addprefix $(DTARCHDIR)/, $(sdt-obj)) -diff --git a/arch/x86/dtrace/sdt_x86_64.c b/arch/x86/dtrace/sdt_x86_64.c -new file mode 100644 -index 0000000000000000000000000000000000000000..e686634ff410372a83d3dd63d5041b4943f0412d ---- /dev/null -+++ b/arch/x86/dtrace/sdt_x86_64.c -@@ -0,0 +1,126 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: sdt_dev.c -+ * DESCRIPTION: DTrace - SDT provider implementation for x86 -+ * -+ * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/sdt.h> -+#include <linux/slab.h> -+#include <linux/vmalloc.h> -+#include <asm/dtrace_util.h> -+ -+#include "dtrace.h" -+#include "dtrace_dev.h" -+#include "sdt_impl.h" -+ -+#define SDT_PATCHVAL 0xf0 -+ -+static uint8_t sdt_invop(struct pt_regs *regs) -+{ -+ struct sdt_probe *sdt = sdt_probetab[SDT_ADDR2NDX(regs->ip)]; -+ -+ for (; sdt != NULL; sdt = sdt->sdp_hashnext) { -+ if ((uintptr_t)sdt->sdp_patchpoint == regs->ip) { -+ if (sdt->sdp_ptype == SDTPT_IS_ENABLED) -+ regs->ax = 1; -+ else { -+ struct pt_regs *old_regs = -+ this_cpu_core->cpu_dtrace_regs; -+ -+ this_cpu_core->cpu_dtrace_regs = regs; -+ -+ dtrace_probe(sdt->sdp_id, regs->di, regs->si, -+ regs->dx, regs->cx, regs->r8, -+ regs->r9, 0); -+ -+ this_cpu_core->cpu_dtrace_regs = old_regs; -+ } -+ -+ return DTRACE_INVOP_NOPS; -+ } -+ } -+ -+ return 0; -+} -+ -+void sdt_provide_probe_arch(struct sdt_probe *sdp, struct module *mp, int idx) -+{ -+ sdp->sdp_patchval = SDT_PATCHVAL; -+ sdp->sdp_savedval = *sdp->sdp_patchpoint; -+} -+ -+int sdt_provide_module_arch(void *arg, struct module *mp) -+{ -+ return 1; -+} -+ -+void sdt_destroy_module(void *arg, struct module *mp) -+{ -+} -+ -+void sdt_enable_arch(struct sdt_probe *sdp, dtrace_id_t id, void *arg) -+{ -+ dtrace_invop_enable(sdp->sdp_patchpoint, sdp->sdp_patchval); -+} -+ -+void sdt_disable_arch(struct sdt_probe *sdp, dtrace_id_t id, void *arg) -+{ -+ dtrace_invop_disable(sdp->sdp_patchpoint, sdp->sdp_savedval); -+} -+ -+uint64_t sdt_getarg(void *arg, dtrace_id_t id, void *parg, int argno, -+ int aframes) -+{ -+ struct pt_regs *regs = this_cpu_core->cpu_dtrace_regs; -+ uint64_t *st; -+ uint64_t val; -+ -+ if (regs == NULL) -+ return 0; -+ -+ switch (argno) { -+ case 0: -+ return regs->di; -+ case 1: -+ return regs->si; -+ case 2: -+ return regs->dx; -+ case 3: -+ return regs->cx; -+ case 4: -+ return regs->r8; -+ case 5: -+ return regs->r9; -+ } -+ -+ ASSERT(argno > 5); -+ -+ st = (uint64_t *)regs->sp; -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); -+ val = st[argno - 6]; -+ DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); -+ -+ return val; -+} -+ -+int sdt_dev_init_arch(void) -+{ -+ return dtrace_invop_add(sdt_invop); -+} -+ -+void sdt_dev_exit_arch(void) -+{ -+ dtrace_invop_remove(sdt_invop); -+} -diff --git a/dtrace/Makefile b/dtrace/Makefile -index b91bc69d38020d8c872483f894349f02a8eb58e6..126d4985967a2478ea2df97ab42eb384e6fe14d2 100644 ---- a/dtrace/Makefile -+++ b/dtrace/Makefile -@@ -3,6 +3,7 @@ - # - - obj-$(CONFIG_DT_CORE) += dtrace.o -+obj-$(CONFIG_DT_SDT) += sdt.o - obj-$(CONFIG_DT_SYSTRACE) += systrace.o - obj-$(CONFIG_DT_DT_TEST) += dt_test.o - -@@ -15,6 +16,7 @@ dtrace-y := dtrace_mod.o dtrace_dev.o \ - dtrace_probe.o dtrace_probe_ctx.o \ - dtrace_ptofapi.o dtrace_predicate.o \ - dtrace_spec.o dtrace_state.o dtrace_util.o -+sdt-y := sdt_mod.o sdt_dev.o - systrace-y := systrace_mod.o systrace_dev.o - dt_test-y := dt_test_mod.o dt_test_dev.o - -diff --git a/dtrace/dt_test_dev.c b/dtrace/dt_test_dev.c -index 8e1f5bab8a128bdc29a345e422467e6e9d294cf0..b720d8091787df618cdff877b63da2cc80a52836 100644 ---- a/dtrace/dt_test_dev.c -+++ b/dtrace/dt_test_dev.c -@@ -131,6 +131,39 @@ static long dt_test_ioctl(struct file *file, - return 0; - } - -+ if (DTRACE_PROBE_ENABLED(sdt__test)) -+ DTRACE_PROBE(sdt__test__is__enabled); -+ -+ DTRACE_PROBE(sdt__test); -+ -+ /* -+ * Test translation-to-nothing. -+ */ -+ DTRACE_PROBE(sdt__test__ioctl__file, int, cmd, int :, 666, -+ char * : (), 0, struct file *, file, int, arg); -+ -+ /* -+ * Probes with every valid count of args. -+ */ -+ DTRACE_PROBE(sdt__test__arg1, int, 1); -+ DTRACE_PROBE(sdt__test__arg2, int, 1, int, 2); -+ DTRACE_PROBE(sdt__test__arg3, int, 1, int, 2, int, 3); -+ DTRACE_PROBE(sdt__test__arg4, int, 1, int, 2, int, 3, int, 4); -+ DTRACE_PROBE(sdt__test__arg5, int, 1, int, 2, int, 3, int, 4, int, 5); -+ DTRACE_PROBE(sdt__test__arg6, int, 1, int, 2, int, 3, int, 4, int, 5, int, 6); -+ DTRACE_PROBE(sdt__test__arg7, int, 1, int, 2, int, 3, int, 4, int, 5, int, 6, int, 7); -+ DTRACE_PROBE(sdt__test__arg8, int, 1, int, 2, int, 3, int, 4, int, 5, int, 6, int, 7, int, 8); -+ DTRACE_PROBE(sdt__test__arg9, int, 1, int, 2, int, 3, int, 4, int, 5, int, 6, int, 7, int, 8, int, 9); -+ DTRACE_PROBE(sdt__test__arga, int, 1, int, 2, int, 3, int, 4, int, 5, int, 6, int, 7, int, 8, int, 9, int, 10); -+ DTRACE_PROBE(sdt__test__argb, int, 1, int, 2, int, 3, int, 4, int, 5, int, 6, int, 7, int, 8, int, 9, int, 10, int, 11); -+ DTRACE_PROBE(sdt__test__argc, int, 1, int, 2, int, 3, int, 4, int, 5, int, 6, int, 7, int, 8, int, 9, int, 10, int, 11, int, 12); -+ DTRACE_PROBE(sdt__test__argd, int, 1, int, 2, int, 3, int, 4, int, 5, int, 6, int, 7, int, 8, int, 9, int, 10, int, 11, int, 12, int, 13); -+ DTRACE_PROBE(sdt__test__arge, int, 1, int, 2, int, 3, int, 4, int, 5, int, 6, int, 7, int, 8, int, 9, int, 10, int, 11, int, 12, int, 13, int, 14); -+ DTRACE_PROBE(sdt__test__argf, int, 1, int, 2, int, 3, int, 4, int, 5, int, 6, int, 7, int, 8, int, 9, int, 10, int, 11, int, 12, int, 13, int, 14, int, 15); -+ DTRACE_PROBE(sdt__test__argg, int, 1, int, 2, int, 3, int, 4, int, 5, int, 6, int, 7, int, 8, int, 9, int, 10, int, 11, int, 12, int, 13, int, 14, int, 15, int, 16); -+ DTRACE_PROBE(sdt__test__argh, int, 1, int, 2, int, 3, int, 4, int, 5, int, 6, int, 7, int, 8, int, 9, int, 10, int, 11, int, 12, int, 13, int, 14, int, 15, int, 16, int, 17); -+ DTRACE_PROBE(sdt__test__argi, int, 1, int, 2, int, 3, int, 4, int, 5, int, 6, int, 7, int, 8, int, 9, int, 10, int, 11, int, 12, int, 13, int, 14, int, 15, int, 16, int, 17, int, 18); -+ - return -EAGAIN; - } - -diff --git a/dtrace/dt_test_mod.c b/dtrace/dt_test_mod.c -index d8af71665a37ad3157f1bf9d2ce14cb0a23f7508..a86c8bc02ae9627c62ea083a60b9c0f5aac403ea 100644 ---- a/dtrace/dt_test_mod.c -+++ b/dtrace/dt_test_mod.c -@@ -50,3 +50,8 @@ static struct dtrace_pops dt_test_pops = { - }; - - DT_PROVIDER_MODULE(dt_test, DTRACE_PRIV_USER) -+ -+void foo(void) -+{ -+ DTRACE_PROBE(sdt__test2); -+} -diff --git a/dtrace/sdt_dev.c b/dtrace/sdt_dev.c -new file mode 100644 -index 0000000000000000000000000000000000000000..78457dad87736694dc591a04498e36c61fbb4661 ---- /dev/null -+++ b/dtrace/sdt_dev.c -@@ -0,0 +1,562 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: sdt_dev.c -+ * DESCRIPTION: DTrace - SDT provider device driver -+ * -+ * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/ctype.h> -+#include <linux/fs.h> -+#include <linux/miscdevice.h> -+#include <linux/sdt.h> -+#include <linux/slab.h> -+#include <linux/uaccess.h> -+#include <linux/vmalloc.h> -+ -+#include "dtrace.h" -+#include "dtrace_dev.h" -+#include "sdt_impl.h" -+ -+#define SDT_PROBETAB_SIZE 0x1000 /* 4k entries -- 16K total */ -+ -+struct sdt_probe **sdt_probetab; -+int sdt_probetab_size; -+int sdt_probetab_mask; -+ -+/* -+ * Return, in newly-allocated space, a version of the passed-in type 'vartype' -+ * which has been cleaned up suitably for CTF: leading and trailing spaces (if -+ * any) removed, and optionally a trailing argument removed as well. -+ * -+ * Type strings look like either -+ * -+ * type (for SDT, as in function prototypes), or -+ * -+ * type argname (for perf: as in function declarations). -+ * -+ * Translator components ": (foo, foo)", if any, have been removed by this -+ * stage. -+ */ -+static char *cleanup_type(const char *vartype, int arg_strip) -+{ -+ const char *cleaned; -+ const char *p; -+ -+ cleaned = vartype + strspn(vartype, " \t"); -+ for (p = cleaned + strlen(cleaned) - 1; p > cleaned && isspace(*p); -+ p--); -+ if (arg_strip) { -+ for (; p > cleaned && (isalnum(*p) || *p == '_'); p--); -+ for (; p > cleaned && isspace(*p); p--); -+ } -+ p++; -+ -+ return kstrndup(cleaned, p - cleaned, GFP_KERNEL); -+} -+ -+/* -+ * Set up the args lists, extracting them from their sdpd entry and parsing them -+ * into an sdt_argdesc array for each probe. -+ */ -+static struct sdt_argdesc * -+sdt_setup_args(struct sdt_probedesc *sdpd, -+ size_t *sdp_nargdesc) -+{ -+ struct sdt_argdesc *args; -+ char *argstr; -+ char *p; -+ int arg_strip = 0; -+ char *next_arg = NULL; -+ size_t arg = 0, sarg = 0, i; -+ -+ *sdp_nargdesc = 0; -+ -+ if ((sdpd->sdpd_args == NULL) || (sdpd->sdpd_args[0] == '\0')) -+ return NULL; -+ -+ /* -+ * Take a copy of the string so we can mutate it without causing trouble -+ * on module reload. -+ */ -+ argstr = kstrdup(sdpd->sdpd_args, GFP_KERNEL); -+ if (argstr == NULL) -+ goto oom; -+ -+ /* -+ * Handle the common case of a trailing comma before we allocate space, -+ * and elide it. -+ */ -+ p = argstr + strlen(argstr) - 1; -+ if (p[0] == ',' && p[1] == '\0') -+ *p = '\0'; -+ -+ /* -+ * This works for counting the number of args even though translator -+ * strings can contain commas, because each comma denotes a new probe -+ * argument. It may overcount in the case of elided arguments -+ * ("foo : ,"): we compensate for that further down, and ignore the tiny -+ * memory leak that results. -+ */ -+ for (p = argstr; p != NULL; p = strchr(p + 1, ',')) -+ (*sdp_nargdesc)++; -+ -+ args = kzalloc(*sdp_nargdesc * sizeof(struct sdt_argdesc), -+ GFP_KERNEL); -+ if (args == NULL) -+ goto oom_argstr; -+ -+ /* -+ * We need to transform each arg (stripping off a terminal argument -+ * name) if this is a perf probe. -+ */ -+ if (strncmp(sdpd->sdpd_name, "__perf_", strlen("__perf_")) == 0) -+ arg_strip = 1; -+ -+ next_arg = argstr; -+ do { -+ char *tok; -+ char *xlator = NULL, *p; -+ char *native; -+ int parens = 0; -+ int empty_xlation; -+ -+ /* -+ * Find the end of this arg, and figure out if it has any -+ * translators. Clean up the type of the arg (or native type, -+ * if this is a translated type). -+ */ -+ tok = next_arg; -+ next_arg = NULL; -+ p = strpbrk(tok, "():,"); -+ while (p && !next_arg) { -+ switch (*p) { -+ case '(': -+ parens++; -+ break; -+ case ')': -+ if (parens > 0) -+ parens--; -+ break; -+ case ':': -+ *p = '\0'; -+ xlator = p + 1; -+ break; -+ case ',': -+ if (parens == 0) { -+ *p = '\0'; -+ next_arg = p + 1; -+ } -+ break; -+ } -+ p = strpbrk(p + 1, "():,"); -+ } -+ -+ native = cleanup_type(tok, arg_strip); -+ if (native == NULL) { -+ args[arg].sda_native = args[arg].sda_xlate = NULL; -+ goto full_oom; -+ } -+ -+ /* -+ * Special case: perf's DECLARE_TRACE_NOARGS passes a single arg -+ * 'void'. Spot and skip it. -+ */ -+ if (!xlator && arg_strip && strcmp(native, "void") == 0) { -+ kfree(native); -+ (*sdp_nargdesc)--; -+ sarg++; -+ continue; -+ } -+ -+ /* -+ * No translator: straight mapping. -+ */ -+ if (xlator == NULL) { -+ ASSERT(arg < *sdp_nargdesc); -+ args[arg].sda_mapping = sarg; -+ args[arg].sda_native = native; -+ args[arg].sda_xlate = NULL; -+ arg++; -+ sarg++; -+ continue; -+ } -+ -+ /* -+ * If this is a perf probe, warn: translations cannot exist for -+ * these, and have no defined format yet in any case. We can -+ * struggle on by assuming they look like SDT translations. -+ */ -+ if (arg_strip) -+ pr_warn("Perf probe %s has at least one SDT translation, " -+ "which should be impossible.", sdpd->sdpd_name); -+ -+ /* -+ * Zero or more translations. (If there are zero, i.e. a pair -+ * of empty parentheses or a colon with nothing after it, we -+ * have to decrement the nargdesc.) -+ */ -+ -+ empty_xlation = 1; -+ while ((p = strsep(&xlator, "(,)")) != NULL) { -+ /* -+ * Skip the empty space before the ( or after the ). -+ */ -+ if (strspn(p, " \t") == strlen(p)) -+ continue; -+ -+ ASSERT(arg < *sdp_nargdesc); -+ -+ empty_xlation = 0; -+ args[arg].sda_mapping = sarg; -+ args[arg].sda_native = kstrdup(native, GFP_KERNEL); -+ args[arg].sda_xlate = cleanup_type(p, 0); -+ if ((args[arg].sda_native == NULL) || -+ (args[arg].sda_xlate == NULL)) { -+ pr_warn("Unable to create argdesc list for " -+ "probe %s: out of memory\n", -+ sdpd->sdpd_name); -+ kfree(native); -+ goto full_oom; -+ } -+ arg++; -+ } -+ if (empty_xlation) -+ (*sdp_nargdesc)--; -+ -+ kfree(native); -+ sarg++; -+ } while (next_arg != NULL); -+ -+ kfree(argstr); -+ return args; -+ -+full_oom: -+ for (i = 0; i < arg; i++) { -+ kfree(args[i].sda_native); -+ kfree(args[i].sda_xlate); -+ } -+ kfree(args); -+oom_argstr: -+ kfree(argstr); -+oom: -+ *sdp_nargdesc = 0; -+ pr_warn("Unable to create argdesc list for probe %s: " -+ "out of memory\n", sdpd->sdpd_name); -+ return NULL; -+} -+ -+void sdt_provide_module(void *arg, struct module *mp) -+{ -+ char *modname = mp->name; -+ struct dtrace_mprovider *prov; -+ struct sdt_probedesc *sdpd; -+ struct sdt_probe *sdp, *prv; -+ int idx, len; -+ int probes_skipped = 0; -+ -+ /* If module setup has failed then do not provide anything. */ -+ if (PDATA(mp) == NULL) -+ return; -+ -+ /* -+ * Nothing to do if the module SDT probes were already created. -+ */ -+ if (PDATA(mp)->sdt_probe_cnt != 0) -+ return; -+ -+ /* -+ * Nothing to do if there are no SDT probes. -+ */ -+ if (mp->sdt_probec == 0) -+ return; -+ -+ /* -+ * Nothing if arch specific module setup fails. -+ */ -+ if (!sdt_provide_module_arch(NULL, mp)) -+ return; -+ -+ /* -+ * Do not provide any probes unless all SDT providers have been created -+ * for this meta-provider. -+ */ -+ for (prov = sdt_providers; prov->dtmp_name != NULL; prov++) { -+ if (prov->dtmp_id == DTRACE_PROVNONE) -+ return; -+ } -+ -+ for (idx = 0, sdpd = mp->sdt_probes; idx < mp->sdt_probec; -+ idx++, sdpd++) { -+ char *name = sdpd->sdpd_name, *nname; -+ int i, j; -+ struct dtrace_mprovider *prov; -+ dtrace_id_t id; -+ enum fasttrap_probe_type ptype; -+ -+ if (name[0] == '?') { -+ ptype = SDTPT_IS_ENABLED; -+ name++; -+ } else -+ ptype = SDTPT_OFFSETS; -+ -+ for (prov = sdt_providers; prov->dtmp_pref != NULL; prov++) { -+ char *prefix = prov->dtmp_pref; -+ int len = strlen(prefix); -+ -+ if (strncmp(name, prefix, len) == 0) { -+ name += len; -+ break; -+ } -+ } -+ -+ nname = kmalloc(len = strlen(name) + 1, GFP_KERNEL); -+ if (nname == NULL) { -+ probes_skipped++; -+ continue; -+ } -+ -+ for (i = j = 0; name[j] != '\0'; i++) { -+ if (name[j] == '_' && name[j + 1] == '_') { -+ nname[i] = '-'; -+ j += 2; -+ } else -+ nname[i] = name[j++]; -+ } -+ -+ nname[i] = '\0'; -+ -+ sdp = kzalloc(sizeof(struct sdt_probe), GFP_KERNEL); -+ if (sdp == NULL) { -+ probes_skipped++; -+ continue; -+ } -+ -+ sdp->sdp_loadcnt = 1; /* FIXME */ -+ sdp->sdp_module = mp; -+ sdp->sdp_name = nname; -+ sdp->sdp_namelen = len; -+ sdp->sdp_provider = prov; -+ sdp->sdp_ptype = ptype; -+ -+ sdp->sdp_argdesc = sdt_setup_args(sdpd, &sdp->sdp_nargdesc); -+ -+ id = dtrace_probe_lookup(prov->dtmp_id, modname, -+ sdpd->sdpd_func, nname); -+ if (id != DTRACE_IDNONE) { -+ prv = dtrace_probe_arg(prov->dtmp_id, id); -+ ASSERT(prv != NULL); -+ -+ sdp->sdp_next = prv->sdp_next; -+ sdp->sdp_id = id; -+ prv->sdp_next = sdp; -+ } else { -+ sdp->sdp_id = dtrace_probe_create(prov->dtmp_id, -+ modname, -+ sdpd->sdpd_func, -+ nname, SDT_AFRAMES, -+ sdp); -+ -+ /* -+ * If we failed to create the probe just skip it. -+ */ -+ if (sdp->sdp_id == DTRACE_IDNONE) { -+ kfree(sdp); -+ probes_skipped++; -+ continue; -+ } -+ -+ PDATA(mp)->sdt_probe_cnt++; -+ } -+ -+ sdp->sdp_patchpoint = (asm_instr_t *)sdpd->sdpd_offset; -+ -+ sdt_provide_probe_arch(sdp, mp, idx); -+ -+ sdp->sdp_hashnext = sdt_probetab[ -+ SDT_ADDR2NDX(sdp->sdp_patchpoint)]; -+ sdt_probetab[SDT_ADDR2NDX(sdp->sdp_patchpoint)] = sdp; -+ } -+ -+ if (probes_skipped != 0) -+ pr_warn("sdt: Failed to provide %d probes in %s (out of memory)\n", -+ probes_skipped, mp->name); -+} -+ -+int sdt_enable(void *arg, dtrace_id_t id, void *parg) -+{ -+ struct sdt_probe *sdp = parg; -+ struct sdt_probe *curr; -+ -+ /* -+ * Ensure that we have a reference to the module. -+ */ -+ if (!try_module_get(sdp->sdp_module)) -+ return -EAGAIN; -+ -+ /* -+ * If at least one other enabled probe exists for this module, drop the -+ * reference we took above, because we only need one to prevent the -+ * module from being unloaded. -+ */ -+ PDATA(sdp->sdp_module)->enabled_cnt++; -+ if (PDATA(sdp->sdp_module)->enabled_cnt > 1) -+ module_put(sdp->sdp_module); -+ -+ for (curr = sdp; curr != NULL; curr = curr->sdp_next) -+ sdt_enable_arch(curr, id, arg); -+ -+ return 0; -+} -+ -+void sdt_disable(void *arg, dtrace_id_t id, void *parg) -+{ -+ struct sdt_probe *sdp = parg; -+ struct sdt_probe *curr; -+ -+ for (curr = sdp; curr != NULL; curr = curr->sdp_next) -+ sdt_disable_arch(curr, id, arg); -+ -+ /* -+ * If we are disabling a probe, we know it was enabled, and therefore -+ * we know that we have a reference on the module to prevent it from -+ * being unloaded. If we disable the last probe on the module, we can -+ * drop the reference. -+ */ -+ PDATA(sdp->sdp_module)->enabled_cnt--; -+ if (PDATA(sdp->sdp_module)->enabled_cnt == 0) -+ module_put(sdp->sdp_module); -+} -+ -+void sdt_getargdesc(void *arg, dtrace_id_t id, void *parg, -+ struct dtrace_argdesc *desc) -+{ -+ struct sdt_probe *sdp = parg; -+ -+ desc->dtargd_native[0] = '\0'; -+ desc->dtargd_xlate[0] = '\0'; -+ -+ while ((sdp->sdp_ptype == SDTPT_IS_ENABLED) && -+ (sdp->sdp_next != NULL)) -+ sdp = sdp->sdp_next; -+ -+ if (sdp->sdp_nargdesc <= desc->dtargd_ndx) { -+ desc->dtargd_ndx = DTRACE_ARGNONE; -+ return; -+ } -+ -+ if (sdp->sdp_argdesc[desc->dtargd_ndx].sda_native != NULL) -+ strlcpy(desc->dtargd_native, -+ sdp->sdp_argdesc[desc->dtargd_ndx].sda_native, -+ sizeof(desc->dtargd_native)); -+ -+ if (sdp->sdp_argdesc[desc->dtargd_ndx].sda_xlate != NULL) -+ strlcpy(desc->dtargd_xlate, -+ sdp->sdp_argdesc[desc->dtargd_ndx].sda_xlate, -+ sizeof(desc->dtargd_xlate)); -+ -+ desc->dtargd_mapping = sdp->sdp_argdesc[desc->dtargd_ndx].sda_mapping; -+} -+ -+void sdt_destroy(void *arg, dtrace_id_t id, void *parg) -+{ -+ struct sdt_probe *sdp = parg; -+ -+ PDATA(sdp->sdp_module)->sdt_probe_cnt--; -+ -+ while (sdp != NULL) { -+ struct sdt_probe *old = sdp, *last, *hash; -+ int ndx; -+ size_t i; -+ -+ ndx = SDT_ADDR2NDX(sdp->sdp_patchpoint); -+ last = NULL; -+ hash = sdt_probetab[ndx]; -+ -+ while (hash != sdp) { -+ ASSERT(hash != NULL); -+ last = hash; -+ hash = hash->sdp_hashnext; -+ } -+ -+ if (last != NULL) -+ last->sdp_hashnext = sdp->sdp_hashnext; -+ else -+ sdt_probetab[ndx] = sdp->sdp_hashnext; -+ -+ for (i = 0; i < sdp->sdp_nargdesc; i++) { -+ kfree(sdp->sdp_argdesc[i].sda_native); -+ kfree(sdp->sdp_argdesc[i].sda_xlate); -+ } -+ kfree(sdp->sdp_argdesc); -+ kfree(sdp->sdp_name); -+ sdp = sdp->sdp_next; -+ kfree(old); -+ } -+} -+ -+static int sdt_open(struct inode *inode, struct file *file) -+{ -+ return -EAGAIN; -+} -+ -+static int sdt_close(struct inode *inode, struct file *file) -+{ -+ return 0; -+} -+ -+static const struct file_operations sdt_fops = { -+ .owner = THIS_MODULE, -+ .open = sdt_open, -+ .release = sdt_close, -+}; -+ -+static struct miscdevice sdt_dev = { -+ .minor = DT_DEV_SDT_MINOR, -+ .name = "sdt", -+ .nodename = "dtrace/provider/sdt", -+ .fops = &sdt_fops, -+}; -+ -+int sdt_dev_init(void) -+{ -+ int ret = 0; -+ -+ ret = misc_register(&sdt_dev); -+ if (ret) { -+ pr_err("%s: Can't register misc device %d\n", -+ sdt_dev.name, sdt_dev.minor); -+ return ret; -+ } -+ -+ if (sdt_probetab_size == 0) -+ sdt_probetab_size = SDT_PROBETAB_SIZE; -+ -+ sdt_probetab_mask = sdt_probetab_size - 1; -+ sdt_probetab = vzalloc(sdt_probetab_size * sizeof(struct sdt_probe *)); -+ if (sdt_probetab == NULL) -+ return -ENOMEM; -+ -+ sdt_dev_init_arch(); -+ -+ return ret; -+} -+ -+void sdt_dev_exit(void) -+{ -+ sdt_dev_exit_arch(); -+ -+ vfree(sdt_probetab); -+ -+ misc_deregister(&sdt_dev); -+} -diff --git a/dtrace/sdt_impl.h b/dtrace/sdt_impl.h -new file mode 100644 -index 0000000000000000000000000000000000000000..e5b7f4f802706a9eb0fcdd3b9958a7e29d9ae055 ---- /dev/null -+++ b/dtrace/sdt_impl.h -@@ -0,0 +1,87 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Dynamic Tracing for Linux - Statically Defined Tracing provider -+ * -+ * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#ifndef _SDT_IMPL_H_ -+#define _SDT_IMPL_H_ -+ -+#include <linux/sdt.h> -+#include <asm/dtrace_arch.h> -+#include <dtrace/sdt_arch.h> -+ -+extern struct module *dtrace_kmod; -+ -+struct sdt_argdesc; -+ -+enum fasttrap_probe_type { -+ SDTPT_NONE = 0, -+ SDTPT_OFFSETS, -+ SDTPT_IS_ENABLED -+}; -+ -+struct sdt_probe { -+ struct dtrace_mprovider *sdp_provider; /* provider */ -+ char *sdp_name; /* name of probe */ -+ int sdp_namelen; /* length of allocated name */ -+ dtrace_id_t sdp_id; /* probe ID */ -+ struct module *sdp_module; /* modctl for module */ -+ int sdp_loadcnt; /* load count for module */ -+ int sdp_primary; /* non-zero if primary mod */ -+ enum fasttrap_probe_type sdp_ptype; /* probe type */ -+ asm_instr_t *sdp_patchpoint;/* patch point */ -+ asm_instr_t sdp_patchval; /* instruction to patch */ -+ asm_instr_t sdp_savedval; /* saved instruction value */ -+ struct sdt_argdesc *sdp_argdesc; /* arguments for this probe */ -+ size_t sdp_nargdesc; /* number of arguments */ -+ struct sdt_probe *sdp_next; /* next probe */ -+ struct sdt_probe *sdp_hashnext; /* next on hash */ -+}; -+ -+struct sdt_argdesc { -+ int sda_mapping; -+ char *sda_native; -+ char *sda_xlate; -+}; -+ -+extern struct dtrace_mprovider sdt_providers[]; -+extern struct sdt_probe **sdt_probetab; -+extern int sdt_probetab_size; -+extern int sdt_probetab_mask; -+ -+#define SDT_ADDR2NDX(addr) ((((uintptr_t)(addr)) >> 4) & \ -+ sdt_probetab_mask) -+ -+extern void sdt_provide_probe_arch(struct sdt_probe *, struct module *, int); -+extern int sdt_provide_module_arch(void *, struct module *); -+extern void sdt_enable_arch(struct sdt_probe *, dtrace_id_t, void *); -+extern void sdt_disable_arch(struct sdt_probe *, dtrace_id_t, void *); -+ -+extern void sdt_provide_module(void *, struct module *); -+extern void sdt_destroy_module(void *, struct module *); -+extern int sdt_enable(void *, dtrace_id_t, void *); -+extern void sdt_disable(void *, dtrace_id_t, void *); -+extern void sdt_getargdesc(void *, dtrace_id_t, void *, -+ struct dtrace_argdesc *); -+extern uint64_t sdt_getarg(void *, dtrace_id_t, void *, int, int); -+extern void sdt_destroy(void *, dtrace_id_t, void *); -+ -+extern int sdt_dev_init(void); -+extern void sdt_dev_exit(void); -+ -+extern int sdt_dev_init_arch(void); -+extern void sdt_dev_exit_arch(void); -+ -+#endif /* _SDT_IMPL_H_ */ -diff --git a/dtrace/sdt_mod.c b/dtrace/sdt_mod.c -new file mode 100644 -index 0000000000000000000000000000000000000000..1de9e72396aa001e567b05f57e2c83df602b34d2 ---- /dev/null -+++ b/dtrace/sdt_mod.c -@@ -0,0 +1,154 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: sdt_mod.c -+ * DESCRIPTION: DTrace - SDT provider kernel module -+ * -+ * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/module.h> -+ -+#include "dtrace.h" -+#include "dtrace_dev.h" -+#include "sdt_impl.h" -+ -+MODULE_AUTHOR("Kris Van Hees (kris.van.hees@oracle.com)"); -+MODULE_DESCRIPTION("Profile Interrupt Tracing"); -+MODULE_VERSION("v0.1"); -+MODULE_LICENSE("GPL"); -+ -+static struct dtrace_pattr vtrace_attr = { -+{ DTRACE_STABILITY_UNSTABLE, DTRACE_STABILITY_UNSTABLE, DTRACE_CLASS_ISA }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_UNSTABLE, DTRACE_STABILITY_UNSTABLE, DTRACE_CLASS_ISA }, -+}; -+ -+static struct dtrace_pattr info_attr = { -+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA }, -+}; -+ -+static struct dtrace_pattr fc_attr = { -+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA }, -+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA }, -+}; -+ -+static struct dtrace_pattr fpu_attr = { -+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_CPU }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA }, -+}; -+ -+static struct dtrace_pattr fsinfo_attr = { -+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA }, -+}; -+ -+static struct dtrace_pattr stab_attr = { -+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA }, -+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA }, -+}; -+ -+static struct dtrace_pattr sdt_attr = { -+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA }, -+}; -+ -+static struct dtrace_pattr xpv_attr = { -+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_PLATFORM }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_PLATFORM }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_PLATFORM }, -+}; -+ -+static struct dtrace_pattr iscsi_attr = { -+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA }, -+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA }, -+}; -+ -+static struct dtrace_pattr perf_attr = { -+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA }, -+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA }, -+}; -+ -+static struct dtrace_pops sdt_pops = { -+ .dtps_provide = NULL, -+ .dtps_provide_module = sdt_provide_module, -+ .dtps_destroy_module = sdt_destroy_module, -+ .dtps_enable = sdt_enable, -+ .dtps_disable = sdt_disable, -+ .dtps_suspend = NULL, -+ .dtps_resume = NULL, -+ .dtps_getargdesc = sdt_getargdesc, -+#ifdef CONFIG_SPARC64 -+ .dtps_getargval = NULL, -+#else -+ .dtps_getargval = sdt_getarg, -+#endif -+ .dtps_usermode = NULL, -+ .dtps_destroy = sdt_destroy, -+}; -+ -+struct dtrace_mprovider sdt_providers[] = { -+ { "vtrace", "__vtrace_", &vtrace_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, -+ { "sysinfo", "__cpu_sysinfo_", &info_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, -+ { "vminfo", "__cpu_vminfo_", &info_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, -+ { "fpuinfo", "__fpuinfo_", &fpu_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, -+ { "sched", "__sched_", &stab_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, -+ { "proc", "__proc_", &stab_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, -+ { "io", "__io_", &stab_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, -+ { "ip", "__ip_", &stab_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, -+ { "lockstat", "__lockstat_", &stab_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, -+ { "tcp", "__tcp_", &stab_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, -+ { "udp", "__udp_", &stab_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, -+ { "mib", "__mib_", &stab_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, -+ { "fsinfo", "__fsinfo_", &fsinfo_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, -+ { "iscsi", "__iscsi_", &iscsi_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, -+ { "nfsv3", "__nfsv3_", &stab_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, -+ { "nfsv4", "__nfsv4_", &stab_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, -+ { "xpv", "__xpv_", &xpv_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, -+ { "fc", "__fc_", &fc_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, -+ { "srp", "__srp_", &fc_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, -+ { "sysevent", "__sysevent_", &stab_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, -+ { "perf", "__perf_", &perf_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, -+ { "sdt", NULL, &sdt_attr, DTRACE_PRIV_KERNEL, &sdt_pops, 0 }, -+ { NULL } -+}; -+ -+DT_MULTI_PROVIDER_MODULE(sdt, sdt_providers) --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/dtrace-patches/0010-dtrace-profile-provider-and-test-probe-core-componen.patch b/sys-kernel/cairn-sources/files/5.10.14/dtrace-patches/0010-dtrace-profile-provider-and-test-probe-core-componen.patch deleted file mode 100644 index 92372496ab66..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/dtrace-patches/0010-dtrace-profile-provider-and-test-probe-core-componen.patch +++ /dev/null @@ -1,50 +0,0 @@ -From 59b5eca72202d66370501cd651aef50b19ceb918 Mon Sep 17 00:00:00 2001 -From: Kris Van Hees <kris.van.hees@oracle.com> -Date: Mon, 19 Nov 2018 17:18:23 +0000 -Subject: [PATCH 10/19] dtrace: profile provider and test probe core components - -Only Kconfig changes are needed here: everything else is purely modular. - -Signed-off-by: Nick Alcock <nick.alcock@oracle.com> -Signed-off-by: Kris Van Hees <kris.van.hees@oracle.com> -Signed-off-by: Tomas Jedlicka <tomas.jedlicka@oracle.com> -Signed-off-by: Eugene Loh <eugene.loh@oracle.com> -Signed-off-by: David Mc Lean <david.mclean@oracle.com> -Signed-off-by: Vincent Lim <vincent.lim@oracle.com> ---- - kernel/dtrace/Kconfig | 12 ++++++++++++ - 1 file changed, 12 insertions(+) - -diff --git a/kernel/dtrace/Kconfig b/kernel/dtrace/Kconfig -index c1ec55d8750edfbaf55ab9431b7c822b3dd2afae..7b88206fe835fa14bb10484b658ce514d642112a 100644 ---- a/kernel/dtrace/Kconfig -+++ b/kernel/dtrace/Kconfig -@@ -23,6 +23,12 @@ config DT_CORE - - if DT_CORE - -+config DT_PROFILE -+ tristate "Profile Interrupt Tracing" -+ default m -+ help -+ The profile and tick providers, firing probes at specific intervals. -+ - config DT_SDT - tristate "Statically Defined Tracing" - default m -@@ -54,6 +60,12 @@ config DT_DT_TEST - help - A test provider used by the testsuite. - -+config DT_DT_PERF -+ tristate "DTrace Performance Test Probe" -+ default m -+ help -+ A test provider used for performance testing. -+ - config DT_DEBUG - bool "DTrace debugging" - default m --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/dtrace-patches/0011-dtrace-profile-and-tick-providers-built-on-cyclics.patch b/sys-kernel/cairn-sources/files/5.10.14/dtrace-patches/0011-dtrace-profile-and-tick-providers-built-on-cyclics.patch deleted file mode 100644 index 67c6d9f83eb5..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/dtrace-patches/0011-dtrace-profile-and-tick-providers-built-on-cyclics.patch +++ /dev/null @@ -1,641 +0,0 @@ -From f7a0d3e1af253e7887d41af5f199fc2561372448 Mon Sep 17 00:00:00 2001 -From: Kris Van Hees <kris.van.hees@oracle.com> -Date: Mon, 19 Nov 2018 18:05:13 +0000 -Subject: [PATCH 11/19] dtrace: profile and tick providers built on cyclics - -Probes are constructed dynamically as called upon by the user: some -default commonly-used probes for common timing frequencies are provided -whether or not called upon. - -Signed-off-by: Kris Van Hees <kris.van.hees@oracle.com> -Signed-off-by: Nick Alcock <nick.alcock@oracle.com> -Signed-off-by: Tomas Jedlicka <tomas.jedlicka@oracle.com> -Signed-off-by: Eugene Loh <eugene.loh@oracle.com> -Signed-off-by: David Mc Lean <david.mclean@oracle.com> -Signed-off-by: Vincent Lim <vincent.lim@oracle.com> ---- - dtrace/Makefile | 2 + - dtrace/profile.h | 32 +++ - dtrace/profile_dev.c | 491 +++++++++++++++++++++++++++++++++++++++++++ - dtrace/profile_mod.c | 52 +++++ - 4 files changed, 577 insertions(+) - create mode 100644 dtrace/profile.h - create mode 100644 dtrace/profile_dev.c - create mode 100644 dtrace/profile_mod.c - -diff --git a/dtrace/Makefile b/dtrace/Makefile -index 126d4985967a2478ea2df97ab42eb384e6fe14d2..5e6fb362a4e96afbcef906dc7eae12c6c6ad5b04 100644 ---- a/dtrace/Makefile -+++ b/dtrace/Makefile -@@ -3,6 +3,7 @@ - # - - obj-$(CONFIG_DT_CORE) += dtrace.o -+obj-$(CONFIG_DT_PROFILE) += profile.o - obj-$(CONFIG_DT_SDT) += sdt.o - obj-$(CONFIG_DT_SYSTRACE) += systrace.o - obj-$(CONFIG_DT_DT_TEST) += dt_test.o -@@ -16,6 +17,7 @@ dtrace-y := dtrace_mod.o dtrace_dev.o \ - dtrace_probe.o dtrace_probe_ctx.o \ - dtrace_ptofapi.o dtrace_predicate.o \ - dtrace_spec.o dtrace_state.o dtrace_util.o -+profile-y := profile_mod.o profile_dev.o - sdt-y := sdt_mod.o sdt_dev.o - systrace-y := systrace_mod.o systrace_dev.o - dt_test-y := dt_test_mod.o dt_test_dev.o -diff --git a/dtrace/profile.h b/dtrace/profile.h -new file mode 100644 -index 0000000000000000000000000000000000000000..713886d1d8e826fef100cb929ecb54d9a9f5a07c ---- /dev/null -+++ b/dtrace/profile.h -@@ -0,0 +1,32 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Dynamic Tracing for Linux - profile provider -+ * -+ * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#ifndef _PROFILE_H_ -+#define _PROFILE_H_ -+ -+extern void profile_provide(void *, const struct dtrace_probedesc *); -+extern int profile_enable(void *, dtrace_id_t, void *); -+extern void profile_disable(void *, dtrace_id_t, void *); -+extern int profile_usermode(void *, dtrace_id_t, void *); -+extern void profile_destroy(void *, dtrace_id_t, void *); -+ -+extern dtrace_provider_id_t profile_id; -+ -+extern int profile_dev_init(void); -+extern void profile_dev_exit(void); -+ -+#endif /* _PROFILE_H_ */ -diff --git a/dtrace/profile_dev.c b/dtrace/profile_dev.c -new file mode 100644 -index 0000000000000000000000000000000000000000..ce7261fcc911fd4589502e4b170a0b3e3e97dc99 ---- /dev/null -+++ b/dtrace/profile_dev.c -@@ -0,0 +1,491 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: profile_dev.c -+ * DESCRIPTION: DTrace - profile provider device driver -+ * -+ * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/fs.h> -+#include <linux/ktime.h> -+#include <linux/miscdevice.h> -+#include <linux/slab.h> -+#include <asm/irq_regs.h> -+#include <asm/ptrace.h> -+ -+#include <linux/hardirq.h> -+#include <linux/profile.h> -+ -+#include "dtrace.h" -+#include "dtrace_dev.h" -+#include "profile.h" -+ -+#define PROF_NAMELEN 15 -+#define PROF_PROFILE 0 -+#define PROF_TICK 1 -+#define PROF_PREFIX_PROFILE "profile-" -+#define PROF_PREFIX_TICK "tick-" -+ -+struct profile_probe { -+ char prof_name[PROF_NAMELEN]; -+ dtrace_id_t prof_id; -+ int prof_kind; -+ ktime_t prof_interval; -+ cyclic_id_t prof_cyclic; -+}; -+ -+struct profile_probe_percpu { -+ ktime_t profc_expected; -+ ktime_t profc_interval; -+ struct profile_probe *profc_probe; -+}; -+ -+static ktime_t profile_interval_min = KTIME_INIT(0, NANOSEC / 5000); -+static int profile_aframes; -+ -+static int profile_rates[] = { -+ 97, 199, 499, 997, 1999, -+ 4001, 4999, 0, 0, 0, -+ 0, 0, 0, 0, 0, -+ 0, 0, 0, 0, 0, -+ }; -+static int profile_ticks[] = { -+ 1, 10, 100, 500, 1000, -+ 5000, 0, 0, 0, 0, -+ 0, 0, 0, 0, 0, -+ }; -+ -+/* -+ * profile_max defines the upper bound on the number of profile probes that -+ * can exist (this is to prevent malicious or clumsy users from exhausing -+ * system resources by creating a slew of profile probes). At mod load time, -+ * this gets its value from PROFILE_MAX_DEFAULT or profile-max-probes if it's -+ * present as module parameter. -+ * FIXME: module parameter yet to be implemented. -+ */ -+#define PROFILE_MAX_DEFAULT 1000 /* default max. number of probes */ -+ -+static int profile_max; /* maximum number of profile probes */ -+static atomic_t profile_total; /* current number of profile probes */ -+ -+static void profile_tick_fn(uintptr_t arg) -+{ -+ struct profile_probe *prof = (struct profile_probe *)arg; -+ unsigned long pc = 0, upc = 0; -+ struct pt_regs *regs = get_irq_regs(); -+ -+ /* -+ * If regs == NULL, then we were called from from softirq context which -+ * also means that we didn't actually interrupt any processing (kernel -+ * or user space). -+ * If regs != NULL, then we did actually get called from hardirq -+ * because the timer interrupt did really interrupt something that was -+ * going on on the CPU (could be user mode or kernel mode). -+ */ -+ if (regs == NULL) { -+ uint64_t stack[8]; -+ -+ dtrace_getpcstack(stack, 8, 0, NULL); -+ pc = stack[7]; -+ } else if (user_mode(regs)) -+ upc = instruction_pointer(regs); -+ else -+ pc = instruction_pointer(regs); -+ -+ dtrace_probe(prof->prof_id, pc, upc, 0, 0, 0, 0, 0); -+} -+ -+static void profile_prof_fn(uintptr_t arg) -+{ -+ struct profile_probe_percpu *pcpu = (struct profile_probe_percpu *)arg; -+ struct profile_probe *prof = pcpu->profc_probe; -+ ktime_t late; -+ struct pt_regs *regs = get_irq_regs(); -+ unsigned long pc = 0, upc = 0; -+ -+ late = ktime_sub(dtrace_gethrtime(), pcpu->profc_expected); -+ pcpu->profc_expected = ktime_add(pcpu->profc_expected, -+ pcpu->profc_interval); -+ -+ /* -+ * If regs == NULL, then we were called from from softirq context which -+ * also means that we didn't actually interrupt any processing (kernel -+ * or user space). -+ * If regs != NULL, then we did actually get called from hardirq -+ * because the timer interrupt did really interrupt something that was -+ * going on on the CPU (could be user mode or kernel mode). -+ */ -+ if (regs == NULL) { -+ uint64_t stack[8]; -+ -+ dtrace_getpcstack(stack, 8, 0, NULL); -+ pc = stack[7]; -+ } else if (user_mode(regs)) -+ upc = instruction_pointer(regs); -+ else -+ pc = instruction_pointer(regs); -+ -+ dtrace_probe(prof->prof_id, pc, upc, ktime_to_ns(late), 0, 0, 0, 0); -+} -+ -+static void profile_online(void *arg, processorid_t cpu, -+ struct cyc_handler *hdlr, -+ struct cyc_time *when) -+{ -+ struct profile_probe *prof = arg; -+ struct profile_probe_percpu *pcpu; -+ -+ pcpu = kzalloc(sizeof(struct profile_probe_percpu), GFP_KERNEL); -+ pcpu->profc_probe = prof; -+ -+ hdlr->cyh_func = profile_prof_fn; -+ hdlr->cyh_arg = (uintptr_t)pcpu; -+ hdlr->cyh_level = CY_HIGH_LEVEL; -+ -+ when->cyt_interval = prof->prof_interval; -+ when->cyt_when = ktime_add(dtrace_gethrtime(), when->cyt_interval); -+ -+ pcpu->profc_expected = when->cyt_when; -+ pcpu->profc_interval = when->cyt_interval; -+} -+ -+static void profile_offline(void *arg, processorid_t cpu, void *oarg) -+{ -+ struct profile_probe_percpu *pcpu = oarg; -+ -+ if (pcpu->profc_probe == arg) { -+ kfree(pcpu); -+ return; -+ } -+ -+ WARN_ONCE(1, "%s: called with mismatched probe info (%p vs %p)" -+ " - leaking %lu bytes\n", __func__, pcpu->profc_probe, arg, -+ sizeof(struct profile_probe_percpu)); -+ -+} -+ -+static void profile_create(ktime_t interval, const char *name, int kind) -+{ -+ struct profile_probe *prof; -+ int nr_frames = 0; /* FIXME */ -+ -+ if (profile_aframes) -+ nr_frames = profile_aframes; -+ -+ if (ktime_lt(interval, profile_interval_min)) -+ return; -+ -+ if (dtrace_probe_lookup(profile_id, NULL, NULL, name) != 0) -+ return; -+ -+ prof = kzalloc(sizeof(struct profile_probe), GFP_KERNEL); -+ if (prof == NULL) { -+ pr_warn("Unable to create probe %s: out of memory\n", name); -+ return; -+ } -+ -+ atomic_inc(&profile_total); -+ if (atomic_read(&profile_total) > profile_max) -+ goto errout; -+ -+ strcpy(prof->prof_name, name); -+ prof->prof_interval = interval; -+ prof->prof_cyclic = CYCLIC_NONE; -+ prof->prof_kind = kind; -+ prof->prof_id = dtrace_probe_create(profile_id, NULL, NULL, name, -+ nr_frames, prof); -+ -+ if (prof->prof_id == DTRACE_IDNONE) { -+ pr_warn("Unable to create probe %s: out of memory\n", name); -+ goto errout; -+ } -+ -+ return; -+ -+errout: -+ kfree(prof); -+ atomic_dec(&profile_total); -+ return; -+} -+ -+void profile_provide(void *arg, const struct dtrace_probedesc *desc) -+{ -+ int i, j, rate, kind; -+ long val = 0, mult = 1, mult_s = 0, mult_ns = 0, len; -+ ktime_t interval; -+ const char *name, *suffix = NULL; -+ const struct { -+ char *prefix; -+ int kind; -+ } types[] = { -+ { PROF_PREFIX_PROFILE, PROF_PROFILE }, -+ { PROF_PREFIX_TICK, PROF_TICK }, -+ { NULL, 0 }, -+ }; -+ -+ const struct { -+ char *name; -+ long mult_s; -+ long mult_ns; -+ } suffixes[] = { -+ { "ns", 0, 1 }, -+ { "nsec", 0, 1 }, -+ { "us", 0, NANOSEC / MICROSEC }, -+ { "usec", 0, NANOSEC / MICROSEC }, -+ { "ms", 0, NANOSEC / MILLISEC }, -+ { "msec", 0, NANOSEC / MILLISEC }, -+ { "s", 1, 0 }, -+ { "sec", 1, 0 }, -+ { "m", 60, 0 }, -+ { "min", 60, 0 }, -+ { "h", 60 * 60, 0 }, -+ { "hour", 60 * 60, 0 }, -+ { "d", 24 * 60 * 60, 0 }, -+ { "day", 24 * 60 * 60, 0 }, -+ { "hz", 0, 0 }, -+ { NULL, }, -+ }; -+ -+ if (desc == NULL) { -+ char n[PROF_NAMELEN]; -+ -+ /* -+ * If no description was provided, provide all of our probes. -+ */ -+ for (i = 0; i < sizeof(profile_rates) / sizeof(int); i++) { -+ rate = profile_rates[i]; -+ if (rate == 0) -+ continue; -+ -+ snprintf(n, PROF_NAMELEN, "%s%d", -+ PROF_PREFIX_PROFILE, rate); -+ profile_create(ktime_set(0, NANOSEC / rate), -+ n, PROF_PROFILE); -+ } -+ -+ for (i = 0; i < sizeof(profile_ticks) / sizeof(int); i++) { -+ rate = profile_ticks[i]; -+ if (rate == 0) -+ continue; -+ -+ snprintf(n, PROF_NAMELEN, "%s%d", -+ PROF_PREFIX_TICK, rate); -+ profile_create(ktime_set(0, NANOSEC / rate), -+ n, PROF_TICK); -+ } -+ -+ return; -+ } -+ -+ name = desc->dtpd_name; -+ -+ for (i = 0; types[i].prefix != NULL; i++) { -+ len = strlen(types[i].prefix); -+ -+ if (strncmp(name, types[i].prefix, len) != 0) -+ continue; -+ -+ break; -+ } -+ -+ if (types[i].prefix == NULL) -+ return; -+ -+ kind = types[i].kind; -+ -+ /* -+ * We need to start before any time suffix. -+ */ -+ for (j = strlen(name); j >= len; j--) { -+ if (name[j] >= '0' && name[j] <= '9') -+ break; -+ -+ suffix = &name[j]; -+ } -+ -+ if (suffix == NULL) { -+ WARN_ONCE(1, "%s: missing time suffix in %s\n", __func__, name); -+ return; -+ } -+ -+ /* -+ * Now determine the numerical value present in the probe name. -+ */ -+ for (; j >= len; j--) { -+ if (name[j] < '0' || name[j] > '9') -+ return; -+ -+ val += (name[j] - '0') * mult; -+ mult *= 10; -+ } -+ -+ if (val == 0) -+ return; -+ -+ /* -+ * Look up the suffix to determine the multiplier. -+ */ -+ for (i = 0; suffixes[i].name != NULL; i++) { -+ if (strcasecmp(suffixes[i].name, suffix) == 0) { -+ mult_s = suffixes[i].mult_s; -+ mult_ns = suffixes[i].mult_ns; -+ break; -+ } -+ } -+ -+ if (suffixes[i].name == NULL && *suffix != '\0') -+ return; -+ -+ if (mult_s == 0 && mult_ns == 0) { -+ /* -+ * The default is frequency (per-second). -+ */ -+ interval = ns_to_ktime((int64_t)NANOSEC / val); -+ } else { -+ long sec; -+ long nsec = val * mult_ns; -+ -+ sec = nsec / NANOSEC; -+ nsec %= NANOSEC; -+ -+ interval = ktime_set(val * mult_s + sec, nsec); -+ } -+ -+ -+ profile_create(interval, name, kind); -+} -+ -+int profile_enable(void *arg, dtrace_id_t id, void *parg) -+{ -+ struct profile_probe *prof = parg; -+ struct cyc_time when; -+ -+ if (!ktime_nz(prof->prof_interval)) { -+ WARN_ONCE(1, "%s: trying to enable 0-interval probe %s\n", -+ __func__, prof->prof_name); -+ return 1; -+ } -+ if (!MUTEX_HELD(&cpu_lock)) { -+ WARN_ONCE(1, "%s: not holding cpu_lock\n", __func__); -+ return 1; -+ } -+ -+ if (prof->prof_kind == PROF_TICK) { -+ struct cyc_handler hdlr; -+ -+ hdlr.cyh_func = profile_tick_fn; -+ hdlr.cyh_arg = (uintptr_t)prof; -+ hdlr.cyh_level = CY_HIGH_LEVEL; -+ -+ when.cyt_interval = prof->prof_interval; -+ when.cyt_when = ktime_set(0, 0); -+ -+ prof->prof_cyclic = cyclic_add(&hdlr, &when); -+ } else if (prof->prof_kind == PROF_PROFILE) { -+ struct cyc_omni_handler omni; -+ -+ omni.cyo_online = profile_online; -+ omni.cyo_offline = profile_offline; -+ omni.cyo_arg = prof; -+ -+ prof->prof_cyclic = cyclic_add_omni(&omni); -+ } else -+ pr_warn_once("%s: Invalid profile type %d\n", -+ __func__, prof->prof_kind); -+ -+ return 0; -+} -+ -+void profile_disable(void *arg, dtrace_id_t id, void *parg) -+{ -+ struct profile_probe *prof = parg; -+ -+ if (prof->prof_cyclic == CYCLIC_NONE) { -+ WARN_ONCE(1, "%s: trying to disable probe %s without cyclic\n", -+ __func__, prof->prof_name); -+ return; -+ } -+ if (!MUTEX_HELD(&cpu_lock)) { -+ WARN_ONCE(1, "%s: not holding cpu_lock\n", __func__); -+ return; -+ } -+ -+ cyclic_remove(prof->prof_cyclic); -+ prof->prof_cyclic = CYCLIC_NONE; -+} -+ -+int profile_usermode(void *arg, dtrace_id_t id, void *parg) -+{ -+ return 1; /* FIXME: awaiting unprivileged tracing */ -+} -+ -+void profile_destroy(void *arg, dtrace_id_t id, void *parg) -+{ -+ struct profile_probe *prof = parg; -+ -+ if (prof->prof_cyclic == CYCLIC_NONE) { -+ kfree(prof); -+ -+ if (atomic_read(&profile_total) >= 1) { -+ atomic_dec(&profile_total); -+ return; -+ } -+ -+ WARN_ONCE(1, "%s: profile_total refcount is 0!\n", __func__); -+ } -+ -+ WARN_ONCE(1, "%s: %s still assigned to cyclic\n", -+ __func__, prof->prof_name); -+} -+ -+static int profile_open(struct inode *inode, struct file *file) -+{ -+ return -EAGAIN; -+} -+ -+static int profile_close(struct inode *inode, struct file *file) -+{ -+ return 0; -+} -+ -+static const struct file_operations profile_fops = { -+ .owner = THIS_MODULE, -+ .open = profile_open, -+ .release = profile_close, -+}; -+ -+static struct miscdevice profile_dev = { -+ .minor = DT_DEV_PROFILE_MINOR, -+ .name = "profile", -+ .nodename = "dtrace/provider/profile", -+ .fops = &profile_fops, -+}; -+ -+int profile_dev_init(void) -+{ -+ int ret = 0; -+ -+ ret = misc_register(&profile_dev); -+ if (ret) -+ pr_err("%s: Can't register misc device %d\n", -+ profile_dev.name, profile_dev.minor); -+ -+ profile_max = PROFILE_MAX_DEFAULT; -+ -+ return ret; -+} -+ -+void profile_dev_exit(void) -+{ -+ misc_deregister(&profile_dev); -+} -diff --git a/dtrace/profile_mod.c b/dtrace/profile_mod.c -new file mode 100644 -index 0000000000000000000000000000000000000000..1fb54a29e57ed642de6cc86615294dbf85557234 ---- /dev/null -+++ b/dtrace/profile_mod.c -@@ -0,0 +1,52 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: profile_mod.c -+ * DESCRIPTION: DTrace - Profile provider kernel module -+ * -+ * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/module.h> -+ -+#include "dtrace.h" -+#include "dtrace_dev.h" -+#include "profile.h" -+ -+MODULE_AUTHOR("Kris Van Hees (kris.van.hees@oracle.com)"); -+MODULE_DESCRIPTION("Profile Interrupt Tracing"); -+MODULE_VERSION("v0.1"); -+MODULE_LICENSE("GPL"); -+ -+static const struct dtrace_pattr profile_attr = { -+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON }, -+{ DTRACE_STABILITY_UNSTABLE, DTRACE_STABILITY_UNSTABLE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON }, -+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON }, -+}; -+ -+static struct dtrace_pops profile_pops = { -+ .dtps_provide = profile_provide, -+ .dtps_provide_module = NULL, -+ .dtps_destroy_module = NULL, -+ .dtps_enable = profile_enable, -+ .dtps_disable = profile_disable, -+ .dtps_suspend = NULL, -+ .dtps_resume = NULL, -+ .dtps_getargdesc = NULL, -+ .dtps_getargval = NULL, -+ .dtps_usermode = profile_usermode, -+ .dtps_destroy = profile_destroy, -+}; -+ -+DT_PROVIDER_MODULE(profile, DTRACE_PRIV_KERNEL | DTRACE_PRIV_USER) --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/dtrace-patches/0012-dtrace-USDT-and-pid-provider-core-and-x86-components.patch b/sys-kernel/cairn-sources/files/5.10.14/dtrace-patches/0012-dtrace-USDT-and-pid-provider-core-and-x86-components.patch deleted file mode 100644 index 3ade5058da9b..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/dtrace-patches/0012-dtrace-USDT-and-pid-provider-core-and-x86-components.patch +++ /dev/null @@ -1,412 +0,0 @@ -From 18dbf51fb9a2c43ac740c698ecbe91b48050e259 Mon Sep 17 00:00:00 2001 -From: Kris Van Hees <kris.van.hees@oracle.com> -Date: Mon, 19 Nov 2018 18:58:27 +0000 -Subject: [PATCH 12/19] dtrace: USDT and pid provider core and x86 components - -This implements the core (linked-in) machinery needed for userspace -statically-defined tracepoints (for historical reasons, known as -'fasttrap' by DTrace) and for the pid provider, which allows USDT -probes to be dropped at addresses that do not correspond to symbols, -at locations named as a symbol plus an offset. Both are implemented in -terms of kprobes. - -Signed-off-by: Nick Alcock <nick.alcock@oracle.com> -Signed-off-by: Kris Van Hees <kris.van.hees@oracle.com> -Signed-off-by: Tomas Jedlicka <tomas.jedlicka@oracle.com> -Signed-off-by: Eugene Loh <eugene.loh@oracle.com> -Signed-off-by: David Mc Lean <david.mclean@oracle.com> -Signed-off-by: Vincent Lim <vincent.lim@oracle.com> ---- - include/linux/dtrace_os.h | 23 +++ - kernel/dtrace/Kconfig | 10 ++ - kernel/dtrace/dtrace_os.c | 272 ++++++++++++++++++++++++++++++++++++ - kernel/dtrace/dtrace_task.c | 15 ++ - 4 files changed, 320 insertions(+) - -diff --git a/include/linux/dtrace_os.h b/include/linux/dtrace_os.h -index f2921ce039a76dd29f93c8183073b8d750681fe6..836825b1c7beb5418b6b6a78f0e4036e025706a5 100644 ---- a/include/linux/dtrace_os.h -+++ b/include/linux/dtrace_os.h -@@ -14,6 +14,9 @@ - #include <linux/mm.h> - #include <linux/notifier.h> - #include <linux/timekeeper_internal.h> -+#if IS_ENABLED(CONFIG_DT_FASTTRAP) -+#include <linux/uprobes.h> -+#endif - #include <asm/unistd.h> - #include <linux/dtrace_cpu.h> - #include <linux/dtrace_task.h> -@@ -94,8 +97,28 @@ static inline int dtrace_no_pf(struct pt_regs *regs) - } - - extern void (*dtrace_helpers_cleanup)(struct task_struct *); -+extern void (*dtrace_fasttrap_probes_cleanup)(struct task_struct *); - extern void (*dtrace_helpers_fork)(struct task_struct *, struct task_struct *); - -+#if IS_ENABLED(CONFIG_DT_FASTTRAP) -+struct fasttrap_machtp { -+ struct inode *fmtp_ino; -+ loff_t fmtp_off; -+ struct uprobe_consumer fmtp_cns; -+}; -+ -+extern int (*dtrace_tracepoint_hit)(struct fasttrap_machtp *, -+ struct pt_regs *, int); -+ -+extern struct task_struct *register_pid_provider(pid_t); -+extern void unregister_pid_provider(pid_t); -+ -+extern int dtrace_copy_code(pid_t, uint8_t *, uintptr_t, size_t); -+extern int dtrace_tracepoint_enable(pid_t, uintptr_t, int, -+ struct fasttrap_machtp *); -+extern int dtrace_tracepoint_disable(pid_t, struct fasttrap_machtp *); -+#endif /* CONFIG_DT_FASTTRAP || CONFIG_DT_FASTTRAP_MODULE */ -+ - #else - - /* -diff --git a/kernel/dtrace/Kconfig b/kernel/dtrace/Kconfig -index 7b88206fe835fa14bb10484b658ce514d642112a..6bf6620981cd14bcc64cd0f7f71b499e478ea31e 100644 ---- a/kernel/dtrace/Kconfig -+++ b/kernel/dtrace/Kconfig -@@ -23,6 +23,16 @@ config DT_CORE - - if DT_CORE - -+config DT_FASTTRAP -+ tristate "Fasttrap Tracing" -+ default m -+ depends on ARCH_SUPPORTS_UPROBES -+ select UPROBE_EVENT -+ help -+ Userspace tracing, providing the kernel support needed for tracing -+ userspace programs. Currently, only statically defined probes -+ (USDT) are supported. -+ - config DT_PROFILE - tristate "Profile Interrupt Tracing" - default m -diff --git a/kernel/dtrace/dtrace_os.c b/kernel/dtrace/dtrace_os.c -index 931cfd0d0fbfc05c7670f4c01f1cfef140dbf408..874e097b84fd4b517cdb1e867a4b9d9ff2504078 100644 ---- a/kernel/dtrace/dtrace_os.c -+++ b/kernel/dtrace/dtrace_os.c -@@ -40,6 +40,10 @@ - #include <linux/shmem_fs.h> - #include <linux/dtrace_task_impl.h> - -+#if IS_ENABLED(CONFIG_DT_FASTTRAP) -+# include <linux/uprobes.h> -+#endif /* CONFIG_DT_FASTTRAP || CONFIG_DT_FASTTRAP_MODULE */ -+ - /* - * OS SPECIFIC DTRACE SETUP - */ -@@ -413,3 +417,271 @@ void dtrace_disable(void) - dtrace_enabled = 0; - } - EXPORT_SYMBOL(dtrace_disable); -+ -+/* -+ * USER SPACE TRACING (FASTTRAP) SUPPORT -+ */ -+ -+#if IS_ENABLED(CONFIG_DT_FASTTRAP) -+int (*dtrace_tracepoint_hit)(struct fasttrap_machtp *, struct pt_regs *, int); -+EXPORT_SYMBOL(dtrace_tracepoint_hit); -+ -+struct task_struct *register_pid_provider(pid_t pid) -+{ -+ struct task_struct *p; -+ -+ /* -+ * Make sure the process exists, (FIXME: isn't a child created as the -+ * result of a vfork(2)), and isn't a zombie (but may be in fork). -+ */ -+ rcu_read_lock(); -+ p = find_task_by_vpid(pid); -+ if (p == NULL) { -+ rcu_read_unlock(); -+ return NULL; -+ } -+ -+ get_task_struct(p); -+ rcu_read_unlock(); -+ -+ if (p->state & TASK_DEAD || p->dt_task == NULL || -+ p->exit_state & (EXIT_ZOMBIE | EXIT_DEAD)) { -+ put_task_struct(p); -+ return NULL; -+ } -+ -+ /* -+ * Increment dtrace_probes so that the process knows to inform us -+ * when it exits or execs. fasttrap_provider_free() decrements this -+ * when we're done with this provider. -+ */ -+ if (p->dt_task != NULL) -+ p->dt_task->dt_probes++; -+ put_task_struct(p); -+ -+ return p; -+} -+EXPORT_SYMBOL(register_pid_provider); -+ -+void unregister_pid_provider(pid_t pid) -+{ -+ struct task_struct *p; -+ -+ /* -+ * Decrement dtrace_probes on the process whose provider we're -+ * freeing. We don't have to worry about clobbering somone else's -+ * modifications to it because we have locked the bucket that -+ * corresponds to this process's hash chain in the provider hash -+ * table. Don't sweat it if we can't find the process. -+ */ -+ rcu_read_lock(); -+ read_lock(&tasklist_lock); -+ if ((p = find_task_by_vpid(pid)) == NULL) { -+ read_unlock(&tasklist_lock); -+ rcu_read_unlock(); -+ return; -+ } -+ -+ get_task_struct(p); -+ read_unlock(&tasklist_lock); -+ rcu_read_unlock(); -+ -+ if (p->dt_task != NULL) -+ p->dt_task->dt_probes--; -+ put_task_struct(p); -+} -+EXPORT_SYMBOL(unregister_pid_provider); -+ -+int dtrace_copy_code(pid_t pid, uint8_t *buf, uintptr_t addr, size_t size) -+{ -+ struct task_struct *p; -+ struct inode *ino; -+ struct vm_area_struct *vma; -+ struct address_space *map; -+ loff_t off; -+ int rc = 0; -+ -+ /* -+ * First we determine the inode and offset that 'addr' refers to in the -+ * task referenced by 'pid'. -+ */ -+ rcu_read_lock(); -+ p = find_task_by_vpid(pid); -+ if (!p) { -+ rcu_read_unlock(); -+ pr_warn("PID %d not found\n", pid); -+ return -ESRCH; -+ } -+ get_task_struct(p); -+ rcu_read_unlock(); -+ -+ mmap_write_lock(p->mm); -+ vma = find_vma(p->mm, addr); -+ if (vma == NULL || vma->vm_file == NULL) { -+ rc = -EFAULT; -+ goto out; -+ } -+ -+ ino = vma->vm_file->f_mapping->host; -+ map = ino->i_mapping; -+ off = ((loff_t)vma->vm_pgoff << PAGE_SHIFT) + (addr - vma->vm_start); -+ -+ if (map->a_ops->readpage == NULL && !shmem_mapping(ino->i_mapping)) { -+ rc = -EIO; -+ goto out; -+ } -+ -+ /* -+ * Armed with inode and offset, we can start reading pages... -+ */ -+ do { -+ int len; -+ struct page *page; -+ void *kaddr; -+ -+ /* -+ * We cannot read beyond the end of the inode content. -+ */ -+ if (off >= i_size_read(ino)) -+ break; -+ -+ len = min_t(int, size, PAGE_SIZE - (off & ~PAGE_MASK)); -+ -+ /* -+ * Make sure that the page we're tring to read is populated and -+ * in page cache. -+ */ -+ if (map->a_ops->readpage) -+ page = read_mapping_page(map, off >> PAGE_SHIFT, -+ vma->vm_file); -+ else -+ page = shmem_read_mapping_page(map, off >> PAGE_SHIFT); -+ -+ if (IS_ERR(page)) { -+ rc = PTR_ERR(page); -+ break; -+ } -+ -+ kaddr = kmap_atomic(page); -+ memcpy(buf, kaddr + (off & ~PAGE_MASK), len); -+ kunmap_atomic(kaddr); -+ put_page(page); -+ -+ buf += len; -+ off += len; -+ size -= len; -+ } while (size > 0); -+ -+out: -+ mmap_write_unlock(p->mm); -+ put_task_struct(p); -+ -+ return rc; -+} -+EXPORT_SYMBOL(dtrace_copy_code); -+ -+static int handler(struct uprobe_consumer *self, struct pt_regs *regs, -+ int is_ret) -+{ -+ struct fasttrap_machtp *mtp; -+ int rc = 0; -+ -+ mtp = container_of(self, struct fasttrap_machtp, fmtp_cns); -+ -+ read_lock(&this_cpu_core->cpu_ft_lock); -+ if (dtrace_tracepoint_hit == NULL) -+ pr_warn("Fasttrap probes, but no handler\n"); -+ else -+ rc = (*dtrace_tracepoint_hit)(mtp, regs, is_ret); -+ read_unlock(&this_cpu_core->cpu_ft_lock); -+ -+ return rc; -+} -+ -+static int prb_handler(struct uprobe_consumer *self, struct pt_regs *regs) -+{ -+ return handler(self, regs, 0); -+} -+ -+static int ret_handler(struct uprobe_consumer *self, unsigned long func, -+ struct pt_regs *regs) -+{ -+ return handler(self, regs, 1); -+} -+ -+int dtrace_tracepoint_enable(pid_t pid, uintptr_t addr, int is_ret, -+ struct fasttrap_machtp *mtp) -+{ -+ struct task_struct *p; -+ struct inode *ino; -+ struct vm_area_struct *vma; -+ loff_t off; -+ int rc = 0; -+ -+ mtp->fmtp_ino = NULL; -+ mtp->fmtp_off = 0; -+ -+ p = find_task_by_vpid(pid); -+ if (!p) { -+ pr_warn("PID %d not found\n", pid); -+ return -ESRCH; -+ } -+ -+ if (p->dt_task == NULL) { -+ pr_warn("PID %d no dtrace_task\n", pid); -+ return -EFAULT; -+ } -+ -+ vma = find_vma(p->mm, addr); -+ if (vma == NULL || vma->vm_file == NULL) -+ return -EFAULT; -+ -+ ino = vma->vm_file->f_mapping->host; -+ off = ((loff_t)vma->vm_pgoff << PAGE_SHIFT) + (addr - vma->vm_start); -+ -+ if (is_ret) -+ mtp->fmtp_cns.ret_handler = ret_handler; -+ else -+ mtp->fmtp_cns.handler = prb_handler; -+ -+ rc = uprobe_register(ino, off, &mtp->fmtp_cns); -+ -+ /* -+ * If successful, increment the count of the number of -+ * tracepoints active in the victim process. -+ */ -+ if (rc == 0) { -+ mtp->fmtp_ino = ino; -+ mtp->fmtp_off = off; -+ -+ p->dt_task->dt_tp_count++; -+ } -+ -+ return rc; -+} -+EXPORT_SYMBOL(dtrace_tracepoint_enable); -+ -+int dtrace_tracepoint_disable(pid_t pid, struct fasttrap_machtp *mtp) -+{ -+ struct task_struct *p; -+ -+ if (!mtp || !mtp->fmtp_ino) -+ return -ENOENT; -+ -+ uprobe_unregister(mtp->fmtp_ino, mtp->fmtp_off, &mtp->fmtp_cns); -+ -+ mtp->fmtp_ino = NULL; -+ mtp->fmtp_off = 0; -+ -+ /* -+ * Decrement the count of the number of tracepoints active in -+ * the victim process (if it still exists). -+ */ -+ p = find_task_by_vpid(pid); -+ if (p != NULL && p->dt_task != NULL) -+ p->dt_task->dt_tp_count--; -+ -+ return 0; -+} -+EXPORT_SYMBOL(dtrace_tracepoint_disable); -+#endif /* CONFIG_DT_FASTTRAP || CONFIG_DT_FASTTRAP_MODULE */ -diff --git a/kernel/dtrace/dtrace_task.c b/kernel/dtrace/dtrace_task.c -index 02bcc6b7e0a26a04f61448ac6c8d5653344b6f40..8bae6e79c7f1e854d6e9f77481e16a3c3b107270 100644 ---- a/kernel/dtrace/dtrace_task.c -+++ b/kernel/dtrace/dtrace_task.c -@@ -22,6 +22,14 @@ - - struct kmem_cache *dtrace_task_cachep; - -+/* -+ * Fasttrap hooks that need to be called when a fasttrap meta provider -+ * is loaded and registered with the framework. -+ */ -+void (*dtrace_helpers_cleanup)(struct task_struct *); -+EXPORT_SYMBOL(dtrace_helpers_cleanup); -+void (*dtrace_fasttrap_probes_cleanup)(struct task_struct *); -+EXPORT_SYMBOL(dtrace_fasttrap_probes_cleanup); - void (*dtrace_helpers_fork)(struct task_struct *, struct task_struct *); - EXPORT_SYMBOL(dtrace_helpers_fork); - -@@ -76,6 +84,13 @@ static void dtrace_task_cleanup(struct task_struct *tsk) - if (tsk->dt_task == NULL) - return; - -+ /* Handle fasttrap provider cleanups. */ -+ if (tsk->dt_task->dt_helpers != NULL && dtrace_helpers_cleanup != NULL) -+ (*dtrace_helpers_cleanup)(tsk); -+ -+ if (tsk->dt_task->dt_probes && dtrace_fasttrap_probes_cleanup != NULL) -+ (*dtrace_fasttrap_probes_cleanup)(tsk); -+ - /* Release psinfo if any. */ - psinfo = tsk->dt_task->dt_psinfo; - if (psinfo != NULL) { --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/dtrace-patches/0013-dtrace-USDT-and-pid-providers.patch b/sys-kernel/cairn-sources/files/5.10.14/dtrace-patches/0013-dtrace-USDT-and-pid-providers.patch deleted file mode 100644 index 16619d420253..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/dtrace-patches/0013-dtrace-USDT-and-pid-providers.patch +++ /dev/null @@ -1,2691 +0,0 @@ -From 209f98383b9139b7d50f91f8433e50bf00c61236 Mon Sep 17 00:00:00 2001 -From: Kris Van Hees <kris.van.hees@oracle.com> -Date: Mon, 19 Nov 2018 18:08:41 +0000 -Subject: [PATCH 13/19] dtrace: USDT and pid providers - -For historical reasons, these are provided in a module named -fasttrap.ko. - -Much of this is arch-dependent code for jump-table detection and -implementation of globbed pid probes ("probe everything you can in this -function"), as well as arch-dependent code to look up arguments and code -to ensure that dropping a kprobe in a single process does not affect -other processes running from the same binary. - -Signed-off-by: Kris Van Hees <kris.van.hees@oracle.com> -Signed-off-by: Nick Alcock <nick.alcock@oracle.com> -Signed-off-by: Tomas Jedlicka <tomas.jedlicka@oracle.com> -Signed-off-by: Eugene Loh <eugene.loh@oracle.com> -Signed-off-by: David Mc Lean <david.mclean@oracle.com> -Signed-off-by: Vincent Lim <vincent.lim@oracle.com> ---- - arch/x86/dtrace/Makefile.arch | 2 + - arch/x86/dtrace/fasttrap_x86_64.c | 364 +++ - .../x86/dtrace/include/dtrace/fasttrap_arch.h | 29 + - dtrace/Makefile | 2 + - dtrace/fasttrap_dev.c | 1986 +++++++++++++++++ - dtrace/fasttrap_impl.h | 172 ++ - dtrace/fasttrap_mod.c | 38 + - 7 files changed, 2593 insertions(+) - create mode 100644 arch/x86/dtrace/fasttrap_x86_64.c - create mode 100644 arch/x86/dtrace/include/dtrace/fasttrap_arch.h - create mode 100644 dtrace/fasttrap_dev.c - create mode 100644 dtrace/fasttrap_impl.h - create mode 100644 dtrace/fasttrap_mod.c - -diff --git a/arch/x86/dtrace/Makefile.arch b/arch/x86/dtrace/Makefile.arch -index 8492eaee426d1ba7a25769ff3c95d1dc828f69ae..e4655557e06ad7524677b9f3b0909f248d5a1c8b 100644 ---- a/arch/x86/dtrace/Makefile.arch -+++ b/arch/x86/dtrace/Makefile.arch -@@ -7,7 +7,9 @@ DTARCHDIR = ../arch/x86/dtrace - ccflags-y += -I$(srctree)/arch/x86/dtrace/include -Idtrace - - dtrace-obj += dtrace_asm_x86_64.o dtrace_isa_x86_64.o -+fasttrap-obj += fasttrap_x86_64.o - sdt-obj += sdt_x86_64.o - - dtrace-y += $(addprefix $(DTARCHDIR)/, $(dtrace-obj)) -+fasttrap-y += $(addprefix $(DTARCHDIR)/, $(fasttrap-obj)) - sdt-y += $(addprefix $(DTARCHDIR)/, $(sdt-obj)) -diff --git a/arch/x86/dtrace/fasttrap_x86_64.c b/arch/x86/dtrace/fasttrap_x86_64.c -new file mode 100644 -index 0000000000000000000000000000000000000000..012b2a50a46ab7570c1a94cbf294ffd65463099f ---- /dev/null -+++ b/arch/x86/dtrace/fasttrap_x86_64.c -@@ -0,0 +1,364 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: fasttrap_x86_64.c -+ * DESCRIPTION: DTrace - fasttrap provider implementation for x86 -+ * -+ * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <asm/insn.h> -+#include <linux/kernel.h> -+#include <linux/slab.h> -+#include <linux/uaccess.h> -+ -+#include "dtrace.h" -+#include "dtrace_dev.h" -+#include "fasttrap_impl.h" -+ -+#define DISASM_REX_PREFIX(pfx) (((pfx) & 0xf0) == 0x40) -+#define DISASM_MODRM_REG(modrm) (((modrm) >> 3) & 0x07) -+ -+static int has_jump_table(const asm_instr_t *addr, size_t size) -+{ -+ const asm_instr_t *end = addr + size; -+ -+ while (addr < end) { -+ int len; -+ -+ /* -+ * Register-dependent jump instructions start with a 0xff byte -+ * and have the modrm.reg field set to 4. Such instructions -+ * tend to be used for jump tables. -+ */ -+ if ((addr[0] == 0xff && DISASM_MODRM_REG(addr[1]) == 4) || -+ (DISASM_REX_PREFIX(addr[0]) && addr[1] == 0xff && -+ DISASM_MODRM_REG(addr[2]) == 4)) -+ return 1; -+ -+ len = dtrace_instr_size(addr); -+ -+ /* -+ * If we encounter a problem decoding an instruction, we will -+ * assume that there might be a jump table. Better safe than -+ * sorry... -+ */ -+ if (len < 0) -+ return 1; -+ -+ addr += len; -+ } -+ -+ return 0; -+} -+ -+static uint64_t *fasttrap_all_offsets(asm_instr_t *text, size_t size, -+ uint64_t *np) -+{ -+ uint64_t *offs = NULL; -+ uint64_t noffs; -+ asm_instr_t *instr; -+ asm_instr_t *end; -+ -+ /* -+ * Two passes are taken through this section of code. The first time -+ * around we merely count the number of probe points. The second time, -+ * we actually record their locations. -+ */ -+again: -+ noffs = 0; -+ instr = text; -+ end = text + size; -+ -+ while (instr < end) { -+ int len; -+ -+ /* -+ * If we fail to decode an instruction, it is time to give up. -+ */ -+ len = dtrace_instr_size(instr); -+ if (len < 0) -+ goto fail; -+ -+ if (offs) -+ offs[noffs] = (uint64_t)(instr - text); -+ noffs++; -+ -+ instr += len; -+ } -+ -+ if (offs == NULL) { -+ /* -+ * No matching offsets found - we are done. -+ */ -+ if (noffs == 0) -+ goto fail; -+ -+ /* -+ * We know how many tracepoint locations there are for this -+ * probe, so allocate member to record them, and kick off the -+ * second pass. -+ */ -+ offs = kmalloc(sizeof(uint64_t) * noffs, GFP_KERNEL); -+ if (!offs) -+ goto fail; -+ -+ goto again; -+ } -+ -+ *np = noffs; -+ -+ return offs; -+ -+fail: -+ *np = 0; -+ kfree(offs); -+ -+ return NULL; -+} -+ -+uint64_t *fasttrap_glob_offsets(struct fasttrap_probe_spec *probe, -+ uint64_t *np) -+{ -+ size_t size = probe->ftps_size; -+ asm_instr_t *text = NULL; -+ asm_instr_t *instr; -+ asm_instr_t *end; -+ uint64_t *offs = NULL; -+ uint64_t noffs; -+ int ret = 0; -+ char ostr[sizeof(instr) * 2 + 1]; -+ -+ text = kmalloc(size, GFP_KERNEL); -+ if (!text) -+ goto fail; -+ -+ ret = dtrace_copy_code(probe->ftps_pid, (uint8_t *)text, -+ probe->ftps_pc, size); -+ if (ret != 0) -+ goto fail; -+ -+ if (has_jump_table(text, size)) -+ goto fail; -+ -+ if (probe->ftps_glen == 1 && probe->ftps_gstr[0] == '*') { -+ offs = fasttrap_all_offsets(text, size, &noffs); -+ goto out; -+ } -+ -+ /* -+ * Two passes are taken through this section of code. The first time -+ * around we merely count the number of probe points. The second time, -+ * we actually record their locations. -+ */ -+again: -+ noffs = 0; -+ instr = text; -+ end = text + size; -+ -+ while (instr < end) { -+ int len; -+ uint64_t off = (uint64_t)(instr - text); -+ -+ /* -+ * If we fail to decode an instruction, it is time to give up. -+ */ -+ len = dtrace_instr_size(instr); -+ if (len < 0) -+ goto fail; -+ -+ snprintf(ostr, sizeof(ostr), "%llx", off); -+ if (dtrace_gmatch(ostr, probe->ftps_gstr)) { -+ if (offs) -+ offs[noffs] = off; -+ noffs++; -+ } -+ -+ instr += len; -+ } -+ -+ if (offs == NULL) { -+ /* -+ * No matching offsets found - we are done. -+ */ -+ if (noffs == 0) -+ goto fail; -+ -+ /* -+ * We know how many tracepoint locations there are for this -+ * probe, so allocate member to record them, and kick off the -+ * second pass. -+ */ -+ offs = kmalloc(sizeof(uint64_t) * noffs, GFP_KERNEL); -+ if (!offs) -+ goto fail; -+ -+ goto again; -+ } -+ -+out: -+ kfree(text); -+ -+ *np = noffs; -+ -+ return offs; -+ -+fail: -+ kfree(offs); -+ kfree(text); -+ -+ *np = 0; -+ return NULL; -+} -+ -+uint64_t fasttrap_pid_getarg(void *arg, dtrace_id_t id, void *parg, int argno, -+ int aframes) -+{ -+ struct pt_regs *regs = this_cpu_core->cpu_dtrace_regs; -+ uint64_t *st; -+ uint64_t val; -+ -+ if (regs == NULL) -+ return 0; -+ -+ switch (argno) { -+ case 0: -+ return regs->di; -+ case 1: -+ return regs->si; -+ case 2: -+ return regs->dx; -+ case 3: -+ return regs->cx; -+ case 4: -+ return regs->r8; -+ case 5: -+ return regs->r9; -+ } -+ -+ ASSERT(argno > 5); -+ -+ pagefault_disable(); -+ st = (uint64_t *)regs->sp; -+ __copy_from_user_inatomic_nocache(&val, (void *)&st[argno - 6 + 1], -+ sizeof(st[0])); -+ pagefault_enable(); -+ -+ return val; -+} -+ -+uint64_t fasttrap_usdt_getarg(void *arg, dtrace_id_t id, void *parg, -+ int argno, int aframes) -+{ -+ struct pt_regs *regs = this_cpu_core->cpu_dtrace_regs; -+ uint64_t *st; -+ uint64_t val; -+ -+ if (regs == NULL) -+ return 0; -+ -+ switch (argno) { -+ case 0: -+ return regs->di; -+ case 1: -+ return regs->si; -+ case 2: -+ return regs->dx; -+ case 3: -+ return regs->cx; -+ case 4: -+ return regs->r8; -+ case 5: -+ return regs->r9; -+ } -+ -+ ASSERT(argno > 5); -+ -+ pagefault_disable(); -+ st = (uint64_t *)regs->sp; -+ __copy_from_user_inatomic_nocache(&val, (void *)&st[argno - 6], -+ sizeof(st[0])); -+ pagefault_enable(); -+ -+ return val; -+} -+ -+static void fasttrap_map_args(struct fasttrap_probe *probe, -+ struct pt_regs *regs, -+ int argc, uintptr_t *argv) -+{ -+ int i, x, cap = min(argc, (int)probe->ftp_nargs); -+ uintptr_t *st = (uintptr_t *)regs->sp; -+ -+ for (i = 0; i < cap; i++) { -+ switch (x = probe->ftp_argmap[i]) { -+ case 0: -+ argv[i] = regs->di; -+ break; -+ case 1: -+ argv[i] = regs->si; -+ break; -+ case 2: -+ argv[i] = regs->dx; -+ break; -+ case 3: -+ argv[i] = regs->cx; -+ break; -+ case 4: -+ argv[i] = regs->r8; -+ break; -+ case 5: -+ argv[i] = regs->r9; -+ break; -+ default: -+ ASSERT(x > 5); -+ -+ __copy_from_user_inatomic_nocache(&argv[i], -+ (void *)&st[x - 6], -+ sizeof(st[0])); -+ } -+ } -+ -+ while (i < argc) -+ argv[i++] = 0; -+} -+ -+void fasttrap_pid_probe_arch(struct fasttrap_probe *ftp, struct pt_regs *regs) -+{ -+ if (ftp->ftp_argmap == NULL) { -+ dtrace_probe(ftp->ftp_id, regs->di, regs->si, regs->dx, -+ regs->cx, regs->r8, regs->r9, 0); -+ } else { -+ uintptr_t t[6]; -+ -+ fasttrap_map_args(ftp, regs, sizeof(t) / sizeof(t[0]), t); -+ dtrace_probe(ftp->ftp_id, t[0], t[1], t[2], t[3], -+ t[4], t[5], 0); -+ } -+} -+ -+void fasttrap_pid_retprobe_arch(struct fasttrap_probe *ftp, -+ struct pt_regs *regs) -+{ -+ /* -+ * FIXME: The first argument to the probe should be the offset in the -+ * function that the return occured at, but uprobes doesn't give -+ * us that information (or so it seems). -+ */ -+ dtrace_probe(ftp->ftp_id, 0, regs->ax, regs->dx, 0, 0, 0, 0); -+} -+ -+void fasttrap_set_enabled(struct pt_regs *regs) -+{ -+ regs->ax = 1; -+} -+ -diff --git a/arch/x86/dtrace/include/dtrace/fasttrap_arch.h b/arch/x86/dtrace/include/dtrace/fasttrap_arch.h -new file mode 100644 -index 0000000000000000000000000000000000000000..abbe9cb2bf3852a540d2f1c535f3154285201e98 ---- /dev/null -+++ b/arch/x86/dtrace/include/dtrace/fasttrap_arch.h -@@ -0,0 +1,29 @@ -+/* -+ * Dynamic Tracing for Linux - Fasttrap provider implementation defines -+ * -+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _X86_64_FASTTRAP_ARCH_H -+#define _X86_64_FASTTRAP_ARCH_H -+ -+#define FASTTRAP_ENTRY_AFRAMES 8 -+#define FASTTRAP_RETURN_AFRAMES 8 -+#define FASTTRAP_OFFSET_AFRAMES 8 -+ -+#endif /* _X86_64_FASTTRAP_ARCH_H */ -diff --git a/dtrace/Makefile b/dtrace/Makefile -index 5e6fb362a4e96afbcef906dc7eae12c6c6ad5b04..c7e3fc512a6c7cdc40f9e3343e3cd98bec674b68 100644 ---- a/dtrace/Makefile -+++ b/dtrace/Makefile -@@ -3,6 +3,7 @@ - # - - obj-$(CONFIG_DT_CORE) += dtrace.o -+obj-$(CONFIG_DT_FASTTRAP) += fasttrap.o - obj-$(CONFIG_DT_PROFILE) += profile.o - obj-$(CONFIG_DT_SDT) += sdt.o - obj-$(CONFIG_DT_SYSTRACE) += systrace.o -@@ -17,6 +18,7 @@ dtrace-y := dtrace_mod.o dtrace_dev.o \ - dtrace_probe.o dtrace_probe_ctx.o \ - dtrace_ptofapi.o dtrace_predicate.o \ - dtrace_spec.o dtrace_state.o dtrace_util.o -+fasttrap-y := fasttrap_mod.o fasttrap_dev.o - profile-y := profile_mod.o profile_dev.o - sdt-y := sdt_mod.o sdt_dev.o - systrace-y := systrace_mod.o systrace_dev.o -diff --git a/dtrace/fasttrap_dev.c b/dtrace/fasttrap_dev.c -new file mode 100644 -index 0000000000000000000000000000000000000000..f48581e00f4bceb55118a8ecf083044741100e4b ---- /dev/null -+++ b/dtrace/fasttrap_dev.c -@@ -0,0 +1,1986 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: fasttrap_dev.c -+ * DESCRIPTION: DTrace - fasttrap provider device driver -+ * -+ * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/atomic.h> -+#include <linux/fs.h> -+#include <linux/miscdevice.h> -+#include <linux/slab.h> -+#include <linux/sort.h> -+#include <linux/uaccess.h> -+#include <linux/vmalloc.h> -+#include <linux/workqueue.h> -+ -+#include "dtrace.h" -+#include "dtrace_dev.h" -+#include "fasttrap_impl.h" -+ -+#define FASTTRAP_MAX_DEFAULT 250000 -+static uint32_t fasttrap_max; -+static uint64_t fasttrap_pid_count; -+static atomic_t fasttrap_total; -+ -+#define FASTTRAP_TPOINTS_DEFAULT_SIZE 0x4000 -+#define FASTTRAP_PROVIDERS_DEFAULT_SIZE 0x100 -+#define FASTTRAP_PROCS_DEFAULT_SIZE 0x100 -+ -+#define FASTTRAP_PID_NAME "pid" -+#define FASTTRAP_ENABLE_FAIL 1 -+#define FASTTRAP_ENABLE_PARTIAL 2 -+ -+struct fasttrap_hash fasttrap_tpoints; -+static struct fasttrap_hash fasttrap_provs; -+static struct fasttrap_hash fasttrap_procs; -+ -+#define FASTTRAP_PROVS_INDEX(pid, name) \ -+ ((fasttrap_hash_str(name) + (pid)) & fasttrap_provs.fth_mask) -+#define FASTTRAP_PROCS_INDEX(pid) ((pid) & fasttrap_procs.fth_mask) -+ -+#define FASTTRAP_TPOINTS_ELEM(pid, pc) \ -+ FASTTRAP_ELEM_BUCKET(&fasttrap_tpoints.fth_table[FASTTRAP_TPOINTS_INDEX(pid, pc)]) -+#define FASTTRAP_PROVS_ELEM(pid, name) \ -+ FASTTRAP_ELEM_BUCKET(&fasttrap_provs.fth_table[FASTTRAP_PROVS_INDEX(pid, name)]) -+#define FASTTRAP_PROCS_ELEM(pid) \ -+ FASTTRAP_ELEM_BUCKET(&fasttrap_procs.fth_table[FASTTRAP_PROCS_INDEX(pid)]) -+ -+#define CLEANUP_NONE 0 -+#define CLEANUP_SCHEDULED 1 -+#define CLEANUP_DEFERRED 2 -+ -+DEFINE_MUTEX(fasttrap_cleanup_mtx); -+DEFINE_MUTEX(fasttrap_count_mtx); -+static uint_t fasttrap_cleanup_state; -+static uint_t fasttrap_cleanup_work; -+ -+static struct kmem_cache *tracepoint_cachep; -+ -+/* -+ * Generation count on modifications to the global tracepoint lookup table. -+ */ -+static volatile uint64_t fasttrap_mod_gen; -+ -+static void fasttrap_pid_cleanup(void); -+static void fasttrap_probes_cleanup(struct task_struct *); -+ -+static int fasttrap_pid_probe(struct fasttrap_machtp *mtp, -+ struct pt_regs *regs, int is_ret) -+{ -+ struct fasttrap_tracepoint *tp; -+ struct fasttrap_id *id; -+ int is_enabled = 0; -+ -+ tp = container_of(mtp, struct fasttrap_tracepoint, ftt_mtp); -+ -+ /* -+ * Verify that this probe event is actually related to the current -+ * process (task group). If not, ignore it. -+ * -+ * TODO: The underlying probe mechanism should register a single -+ * handler for the (inode, offset) combination. When the handler -+ * is called, it should run through a list of fasttrap -+ * tracepoints associated with the OS-level probe, looking for -+ * one that is related to the current task. -+ */ -+ if (tp->ftt_pid != current->tgid) -+ return 0; -+ -+ if (atomic64_read(&tp->ftt_proc->ftpc_acount) == 0) -+ return 0; -+ -+ this_cpu_core->cpu_dtrace_regs = regs; -+ -+ if (!is_ret) { -+ for (id = tp->ftt_ids; id != NULL; id = id->fti_next) { -+ struct fasttrap_probe *ftp = id->fti_probe; -+ -+ if (id->fti_ptype == DTFTP_IS_ENABLED) -+ is_enabled = 1; -+ else -+ fasttrap_pid_probe_arch(ftp, regs); -+ } -+ } else { -+ for (id = tp->ftt_retids; id != NULL; id = id->fti_next) { -+ struct fasttrap_probe *ftp = id->fti_probe; -+ -+ fasttrap_pid_retprobe_arch(ftp, regs); -+ } -+ } -+ -+ this_cpu_core->cpu_dtrace_regs = NULL; -+ -+ if (is_enabled) -+ fasttrap_set_enabled(regs); -+ -+ return 0; -+} -+ -+static void fasttrap_pid_provide(void *arg, -+ const struct dtrace_probedesc *desc) -+{ -+ /* -+ * There are no "default" pid probes. -+ */ -+} -+ -+static void fasttrap_enable_callbacks(void) -+{ -+ /* -+ * We don't have to play the RW lock game here because we're providing -+ * something rather than taking something away -- we can be sure that -+ * no threads have tried to follow these function pointers yet. -+ */ -+ mutex_lock(&fasttrap_count_mtx); -+ if (fasttrap_pid_count == 0) { -+ ASSERT(dtrace_tracepoint_hit == NULL); -+ -+ dtrace_fasttrap_probes_cleanup = &fasttrap_probes_cleanup; -+ dtrace_tracepoint_hit = &fasttrap_pid_probe; -+ } -+ -+ ASSERT(dtrace_fasttrap_probes_cleanup == &fasttrap_probes_cleanup); -+ ASSERT(dtrace_tracepoint_hit == &fasttrap_pid_probe); -+ -+ fasttrap_pid_count++; -+ mutex_unlock(&fasttrap_count_mtx); -+} -+ -+static void fasttrap_disable_callbacks(void) -+{ -+ ASSERT(MUTEX_HELD(&cpu_lock)); -+ -+ mutex_lock(&fasttrap_count_mtx); -+ ASSERT(fasttrap_pid_count > 0); -+ fasttrap_pid_count--; -+ -+ if (fasttrap_pid_count == 0) { -+ int cpu; -+ -+ for_each_present_cpu(cpu) { -+ struct cpu_core *cpuc = per_cpu_core(cpu); -+ -+ write_lock(&cpuc->cpu_ft_lock); -+ } -+ -+ dtrace_tracepoint_hit = NULL; -+ dtrace_fasttrap_probes_cleanup = NULL; -+ -+ for_each_present_cpu(cpu) { -+ struct cpu_core *cpuc = per_cpu_core(cpu); -+ -+ write_unlock(&cpuc->cpu_ft_lock); -+ } -+ } -+ -+ mutex_unlock(&fasttrap_count_mtx); -+} -+ -+/* -+ * This function ensures that no threads are actively using the memory -+ * associated with probes that were formerly live. -+ */ -+static void fasttrap_mod_barrier(uint64_t gen) -+{ -+ int cpu; -+ -+ if (gen < fasttrap_mod_gen) -+ return; -+ -+ fasttrap_mod_gen++; -+ -+ for_each_present_cpu(cpu) { -+ struct cpu_core *cpuc = per_cpu_core(cpu); -+ -+ mutex_lock(&cpuc->cpuc_pid_lock); -+ mutex_unlock(&cpuc->cpuc_pid_lock); -+ } -+} -+ -+static int fasttrap_tracepoint_enable(struct fasttrap_probe *probe, -+ uint_t index) -+{ -+ struct fasttrap_tracepoint *tp, *new_tp = NULL; -+ struct fasttrap_bucket *bucket; -+ struct fasttrap_id *id; -+ pid_t pid; -+ uintptr_t pc; -+ -+ ASSERT(index < probe->ftp_ntps); -+ -+ pid = probe->ftp_pid; -+ pc = probe->ftp_tps[index].fit_tp->ftt_pc; -+ id = &probe->ftp_tps[index].fit_id; -+ -+ ASSERT(probe->ftp_tps[index].fit_tp->ftt_pid == pid); -+ -+ /* -+ * Before we make any modifications, make sure we've imposed a barrier -+ * on the generation in which this probe was last modified. -+ */ -+ fasttrap_mod_barrier(probe->ftp_gen); -+ -+ bucket = FASTTRAP_TPOINTS_ELEM(pid, pc); -+ -+ /* -+ * If the tracepoint has already been enabled, just add our id to the -+ * list of interested probes. This may be our second time through -+ * this path in which case we'll have constructed the tracepoint we'd -+ * like to install. If we can't find a match, and have an allocated -+ * tracepoint ready to go, enable that one now. -+ * -+ * A tracepoint whose process is defunct is also considered defunct. -+ */ -+again: -+ mutex_lock(&bucket->ftb_mtx); -+ for (tp = bucket->ftb_data; tp != NULL; tp = tp->ftt_next) { -+ /* -+ * Note that it's safe to access the active count on the -+ * associated proc structure because we know that at least one -+ * provider (this one) will still be around throughout this -+ * operation. -+ */ -+ if (tp->ftt_pid != pid || tp->ftt_pc != pc || -+ atomic64_read(&tp->ftt_proc->ftpc_acount) == 0) -+ continue; -+ -+ /* -+ * Now that we've found a matching tracepoint, it would be -+ * a decent idea to confirm that the tracepoint is still -+ * enabled and the trap instruction hasn't been overwritten. -+ * Since this is a little hairy, we'll punt for now. -+ */ -+ -+ /* -+ * This can't be the first interested probe. We don't have -+ * to worry about another thread being in the midst of -+ * deleting this tracepoint (which would be the only valid -+ * reason for a tracepoint to have no interested probes) -+ * since we're holding P_PR_LOCK for this process. -+ */ -+ ASSERT(tp->ftt_ids != NULL || tp->ftt_retids != NULL); -+ -+ switch (id->fti_ptype) { -+ case DTFTP_ENTRY: -+ case DTFTP_OFFSETS: -+ case DTFTP_IS_ENABLED: -+ if (tp->ftt_ids == NULL) /* return tp */ -+ continue; -+ -+ ASSERT(tp->ftt_retids == NULL); -+ -+ id->fti_next = tp->ftt_ids; -+ dtrace_membar_producer(); -+ tp->ftt_ids = id; -+ dtrace_membar_producer(); -+ break; -+ -+ case DTFTP_RETURN: -+ case DTFTP_POST_OFFSETS: -+ if (tp->ftt_retids == NULL) /* non-return tp */ -+ continue; -+ -+ ASSERT(tp->ftt_ids == NULL); -+ -+ id->fti_next = tp->ftt_retids; -+ dtrace_membar_producer(); -+ tp->ftt_retids = id; -+ dtrace_membar_producer(); -+ break; -+ -+ default: -+ ASSERT(0); /* FIXME */ -+ } -+ -+ mutex_unlock(&bucket->ftb_mtx); -+ -+ if (new_tp != NULL) { -+ new_tp->ftt_ids = NULL; -+ new_tp->ftt_retids = NULL; -+ } -+ -+ return 0; -+ } -+ -+ /* -+ * If we have a good tracepoint ready to go, install it now while -+ * we have the lock held and no one can screw with us. -+ */ -+ if (new_tp != NULL) { -+ int rc = 0; -+ -+ new_tp->ftt_next = bucket->ftb_data; -+ dtrace_membar_producer(); -+ bucket->ftb_data = new_tp; -+ dtrace_membar_producer(); -+ mutex_unlock(&bucket->ftb_mtx); -+ -+ /* -+ * Activate the tracepoint in the ISA-specific manner. -+ * If this fails, we need to report the failure, but -+ * indicate that this tracepoint must still be disabled -+ * by calling fasttrap_tracepoint_disable(). -+ */ -+ rc = dtrace_tracepoint_enable(pid, pc, -+ id->fti_ptype == DTFTP_RETURN, -+ &new_tp->ftt_mtp); -+ -+ return rc ? FASTTRAP_ENABLE_PARTIAL : 0; -+ } -+ -+ mutex_unlock(&bucket->ftb_mtx); -+ -+ /* -+ * Initialize the tracepoint that's been preallocated with the probe. -+ */ -+ new_tp = probe->ftp_tps[index].fit_tp; -+ -+ ASSERT(new_tp->ftt_pid == pid); -+ ASSERT(new_tp->ftt_pc == pc); -+ ASSERT(new_tp->ftt_proc == probe->ftp_prov->ftp_proc); -+ ASSERT(new_tp->ftt_ids == NULL); -+ ASSERT(new_tp->ftt_retids == NULL); -+ -+ switch (id->fti_ptype) { -+ case DTFTP_ENTRY: -+ case DTFTP_OFFSETS: -+ case DTFTP_IS_ENABLED: -+ id->fti_next = NULL; -+ new_tp->ftt_ids = id; -+ break; -+ -+ case DTFTP_RETURN: -+ case DTFTP_POST_OFFSETS: -+ id->fti_next = NULL; -+ new_tp->ftt_retids = id; -+ break; -+ -+ default: -+ ASSERT(0); -+ } -+ -+ goto again; -+} -+ -+static void fasttrap_tracepoint_disable(struct fasttrap_probe *probe, -+ uint_t index) -+{ -+ struct fasttrap_bucket *bucket; -+ struct fasttrap_provider *prov = probe->ftp_prov; -+ struct fasttrap_tracepoint **pp, *tp; -+ struct fasttrap_id *id, **idp = NULL; -+ pid_t pid; -+ uintptr_t pc; -+ -+ ASSERT(index < probe->ftp_ntps); -+ -+ pid = probe->ftp_pid; -+ pc = probe->ftp_tps[index].fit_tp->ftt_pc; -+ id = &probe->ftp_tps[index].fit_id; -+ -+ ASSERT(probe->ftp_tps[index].fit_tp->ftt_pid == pid); -+ -+ /* -+ * Find the tracepoint and make sure that our id is one of the -+ * ones registered with it. Return probes are linked in their -+ * own tracepoint, even though they share the (pi, pc) pair with -+ * entry probes. -+ */ -+ bucket = FASTTRAP_TPOINTS_ELEM(pid, pc); -+ mutex_lock(&bucket->ftb_mtx); -+ for (tp = bucket->ftb_data; tp != NULL; tp = tp->ftt_next) { -+ if (tp->ftt_pid != pid || tp->ftt_pc != pc || -+ tp->ftt_proc != prov->ftp_proc) -+ continue; -+ -+ if (id->fti_ptype == DTFTP_RETURN && tp->ftt_retids == NULL) -+ continue; -+ -+ if (id->fti_ptype != DTFTP_RETURN && tp->ftt_ids == NULL) -+ continue; -+ -+ break; -+ } -+ -+ /* -+ * If we somehow lost this tracepoint, we are in trouble. -+ */ -+ ASSERT(tp != NULL); -+ -+ switch (id->fti_ptype) { -+ case DTFTP_ENTRY: -+ case DTFTP_OFFSETS: -+ case DTFTP_IS_ENABLED: -+ ASSERT(tp->ftt_ids != NULL); -+ idp = &tp->ftt_ids; -+ break; -+ -+ case DTFTP_RETURN: -+ case DTFTP_POST_OFFSETS: -+ ASSERT(tp->ftt_retids != NULL); -+ idp = &tp->ftt_retids; -+ break; -+ -+ default: -+ ASSERT(0); -+ } -+ -+ while ((*idp)->fti_probe != probe) { -+ idp = &(*idp)->fti_next; -+ ASSERT(*idp != NULL); -+ } -+ -+ id = *idp; -+ *idp = id->fti_next; -+ dtrace_membar_producer(); -+ -+ ASSERT(id->fti_probe == probe); -+ -+ /* -+ * If there are other registered enablings of this tracepoint, we're -+ * all done, but if this was the last probe assocated with this -+ * this tracepoint, we need to remove and free it. -+ */ -+ if (tp->ftt_ids != NULL || tp->ftt_retids != NULL) { -+ /* -+ * If the current probe's tracepoint is in use, swap it -+ * for an unused tracepoint. -+ */ -+ if (tp == probe->ftp_tps[index].fit_tp) { -+ struct fasttrap_probe *tmp_probe; -+ struct fasttrap_tracepoint **tmp_tp; -+ uint_t tmp_index; -+ -+ if (tp->ftt_ids != NULL) { -+ tmp_probe = tp->ftt_ids->fti_probe; -+ tmp_index = FASTTRAP_ID_INDEX(tp->ftt_ids); -+ tmp_tp = &tmp_probe->ftp_tps[tmp_index].fit_tp; -+ } else { -+ tmp_probe = tp->ftt_retids->fti_probe; -+ tmp_index = FASTTRAP_ID_INDEX(tp->ftt_retids); -+ tmp_tp = &tmp_probe->ftp_tps[tmp_index].fit_tp; -+ } -+ -+ ASSERT(*tmp_tp != NULL); -+ ASSERT(*tmp_tp != probe->ftp_tps[index].fit_tp); -+ ASSERT((*tmp_tp)->ftt_ids == NULL); -+ ASSERT((*tmp_tp)->ftt_retids == NULL); -+ -+ probe->ftp_tps[index].fit_tp = *tmp_tp; -+ *tmp_tp = tp; -+ } -+ -+ mutex_unlock(&bucket->ftb_mtx); -+ -+ /* -+ * Tag the modified probe with the generation in which it was -+ * changed. -+ */ -+ probe->ftp_gen = fasttrap_mod_gen; -+ return; -+ } -+ -+ mutex_unlock(&bucket->ftb_mtx); -+ -+ dtrace_tracepoint_disable(pid, &tp->ftt_mtp); -+ -+ /* -+ * Remove the probe from the hash table of active tracepoints. -+ */ -+ mutex_lock(&bucket->ftb_mtx); -+ pp = (struct fasttrap_tracepoint **)&bucket->ftb_data; -+ ASSERT(*pp != NULL); -+ while (*pp != tp) { -+ pp = &(*pp)->ftt_next; -+ ASSERT(*pp != NULL); -+ } -+ -+ *pp = tp->ftt_next; -+ dtrace_membar_producer(); -+ -+ mutex_unlock(&bucket->ftb_mtx); -+ -+ /* -+ * Tag the modified probe with the generation in which it was changed. -+ */ -+ probe->ftp_gen = fasttrap_mod_gen; -+} -+ -+static int fasttrap_pid_enable(void *arg, dtrace_id_t id, void *parg) -+{ -+ struct fasttrap_probe *probe = parg; -+ int i, rc; -+ -+ ASSERT(probe != NULL); -+ ASSERT(!probe->ftp_enabled); -+ ASSERT(id == probe->ftp_id); -+ ASSERT(MUTEX_HELD(&cpu_lock)); -+ -+ /* -+ * Increment the count of enabled probes on this probe's provider; -+ * the provider can't go away while the probe still exists. We -+ * must increment this even if we aren't able to properly enable -+ * this probe. -+ */ -+ mutex_lock(&probe->ftp_prov->ftp_mtx); -+ probe->ftp_prov->ftp_rcount++; -+ mutex_unlock(&probe->ftp_prov->ftp_mtx); -+ -+ /* -+ * If this probe's provider is retired (meaning it was valid in a -+ * previously exec'ed incarnation of this address space), bail out. The -+ * provider can't go away while we're in this code path. -+ */ -+ if (probe->ftp_prov->ftp_retired) -+ return 0; -+ -+#ifdef FIXME -+ /* -+ * If we can't find the process, it may be that we're in the context of -+ * a fork in which the traced process is being born and we're copying -+ * USDT probes. Otherwise, the process is gone so bail. -+ */ -+ p = sprlock(probe->ftp_pid); -+ if (p == NULL) { -+ if ((curproc->p_flag & SFORKING) == 0) -+ return 0; -+ -+ mutex_enter(&pidlock); -+ p = prfind(probe->ftp_pid); -+ -+ /* -+ * Confirm that curproc is indeed forking the process in which -+ * we're trying to enable probes. -+ */ -+ ASSERT(p != NULL); -+ ASSERT(p->p_parent == curproc); -+ ASSERT(p->p_stat == SIDL); -+ -+ mutex_enter(&p->p_lock); -+ mutex_exit(&pidlock); -+ -+ sprlock_proc(p); -+ } -+ -+ ASSERT(!(p->p_flag & SVFORK)); -+ mutex_exit(&p->p_lock); -+#endif -+ -+ /* -+ * We have to enable the trap entry point before any user threads have -+ * the chance to execute the trap instruction we're about to place -+ * in their process's text. -+ */ -+ fasttrap_enable_callbacks(); -+ -+ /* -+ * Enable all the tracepoints and add this probe's id to each -+ * tracepoint's list of active probes. -+ */ -+ for (i = 0; i < probe->ftp_ntps; i++) { -+ rc = fasttrap_tracepoint_enable(probe, i); -+ if (rc != 0) { -+ /* -+ * If enabling the tracepoint failed completely, -+ * we don't have to disable it; if the failure -+ * was only partial we must disable it. -+ */ -+ if (rc == FASTTRAP_ENABLE_FAIL) -+ i--; -+ else -+ ASSERT(rc == FASTTRAP_ENABLE_PARTIAL); -+ -+ /* -+ * Back up and pull out all the tracepoints we've -+ * created so far for this probe. -+ */ -+ while (i >= 0) { -+ fasttrap_tracepoint_disable(probe, i); -+ i--; -+ } -+ -+#ifdef FIXME -+ mutex_enter(&p->p_lock); -+ sprunlock(p); -+#endif -+ -+ /* -+ * Since we're not actually enabling this probe, -+ * drop our reference on the trap table entry. -+ */ -+ fasttrap_disable_callbacks(); -+ return 0; -+ } -+ } -+ -+#ifdef FIXME -+ mutex_enter(&p->p_lock); -+ sprunlock(p); -+#endif -+ -+ probe->ftp_enabled = 1; -+ return 0; -+} -+ -+static void fasttrap_pid_disable(void *arg, dtrace_id_t id, void *parg) -+{ -+ struct fasttrap_probe *probe = parg; -+ struct fasttrap_provider *prov = probe->ftp_prov; -+ int i, whack = 0; -+ -+ ASSERT(id == probe->ftp_id); -+ -+ mutex_lock(&prov->ftp_mtx); -+ -+ /* -+ * Disable all the associated tracepoints (for fully enabled probes). -+ */ -+ if (probe->ftp_enabled) { -+ for (i = 0; i < probe->ftp_ntps; i++) -+ fasttrap_tracepoint_disable(probe, i); -+ } -+ -+ ASSERT(prov->ftp_rcount > 0); -+ prov->ftp_rcount--; -+ -+ if ((prov->ftp_retired || prov->ftp_rcount == 0) && !prov->ftp_marked) -+ whack = prov->ftp_marked = 1; -+ -+ mutex_unlock(&prov->ftp_mtx); -+ -+ if (whack) -+ fasttrap_pid_cleanup(); -+ -+ if (!probe->ftp_enabled) -+ return; -+ -+ probe->ftp_enabled = 0; -+ -+ ASSERT(MUTEX_HELD(&cpu_lock)); -+ fasttrap_disable_callbacks(); -+} -+ -+static void fasttrap_pid_getargdesc(void *arg, dtrace_id_t id, void *parg, -+ struct dtrace_argdesc *desc) -+{ -+ struct fasttrap_probe *probe = parg; -+ char *str; -+ int i, ndx; -+ -+ desc->dtargd_native[0] = '\0'; -+ desc->dtargd_xlate[0] = '\0'; -+ -+ if (probe->ftp_prov->ftp_retired != 0 || -+ desc->dtargd_ndx >= probe->ftp_nargs) { -+ desc->dtargd_ndx = DTRACE_ARGNONE; -+ return; -+ } -+ -+ ndx = (probe->ftp_argmap != NULL) ? probe->ftp_argmap[desc->dtargd_ndx] -+ : desc->dtargd_ndx; -+ -+ str = probe->ftp_ntypes; -+ for (i = 0; i < ndx; i++) -+ str += strlen(str) + 1; -+ -+ ASSERT(strlen(str + 1) < sizeof(desc->dtargd_native)); -+ strcpy(desc->dtargd_native, str); -+ -+ if (probe->ftp_xtypes == NULL) -+ return; -+ -+ str = probe->ftp_xtypes; -+ for (i = 0; i < desc->dtargd_ndx; i++) -+ str += strlen(str) + 1; -+ -+ ASSERT(strlen(str + 1) < sizeof(desc->dtargd_xlate)); -+ strcpy(desc->dtargd_xlate, str); -+} -+ -+static void fasttrap_pid_destroy(void *arg, dtrace_id_t id, void *parg) -+{ -+ struct fasttrap_probe *probe = parg; -+ int i; -+ -+ ASSERT(probe != NULL); -+ ASSERT(!probe->ftp_enabled); -+ ASSERT(atomic_read(&fasttrap_total) >= probe->ftp_ntps); -+ -+ atomic_add(-probe->ftp_ntps, &fasttrap_total); -+ -+ if (probe->ftp_gen + 1 >= fasttrap_mod_gen) -+ fasttrap_mod_barrier(probe->ftp_gen); -+ -+ for (i = 0; i < probe->ftp_ntps; i++) -+ kmem_cache_free(tracepoint_cachep, probe->ftp_tps[i].fit_tp); -+ -+ kfree(probe); -+} -+ -+static const struct dtrace_pattr pid_attr = { -+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+}; -+ -+static struct dtrace_pops pid_pops = { -+ .dtps_provide = fasttrap_pid_provide, -+ .dtps_provide_module = NULL, -+ .dtps_destroy_module = NULL, -+ .dtps_enable = fasttrap_pid_enable, -+ .dtps_disable = fasttrap_pid_disable, -+ .dtps_suspend = NULL, -+ .dtps_resume = NULL, -+ .dtps_getargdesc = fasttrap_pid_getargdesc, -+ .dtps_getargval = fasttrap_pid_getarg, -+ .dtps_usermode = NULL, -+ .dtps_destroy = fasttrap_pid_destroy -+}; -+ -+static struct dtrace_pops usdt_pops = { -+ .dtps_provide = fasttrap_pid_provide, -+ .dtps_provide_module = NULL, -+ .dtps_destroy_module = NULL, -+ .dtps_enable = fasttrap_pid_enable, -+ .dtps_disable = fasttrap_pid_disable, -+ .dtps_suspend = NULL, -+ .dtps_resume = NULL, -+ .dtps_getargdesc = fasttrap_pid_getargdesc, -+ .dtps_getargval = fasttrap_usdt_getarg, -+ .dtps_usermode = NULL, -+ .dtps_destroy = fasttrap_pid_destroy -+}; -+ -+static uint_t fasttrap_hash_str(const char *p) -+{ -+ unsigned int g; -+ uint_t hval = 0; -+ -+ while (*p) { -+ hval = (hval << 4) + *p++; -+ g = hval & 0xf0000000; -+ if (g != 0) -+ hval ^= g >> 24; -+ hval &= ~g; -+ } -+ -+ return hval; -+} -+ -+static int fasttrap_uint32_cmp(const void *ap, const void *bp) -+{ -+ return (*(const uint32_t *)ap - *(const uint32_t *)bp); -+} -+ -+void fasttrap_meta_create_probe(void *arg, void *parg, -+ struct dtrace_helper_probedesc *dhpb) -+{ -+ struct fasttrap_provider *provider = parg; -+ struct fasttrap_probe *pp; -+ struct fasttrap_tracepoint *tp; -+ int i, j; -+ uint32_t ntps; -+ -+ /* -+ * Since the meta provider count is non-zero we don't have to worry -+ * about this provider disappearing. -+ */ -+ ASSERT(provider->ftp_mcount > 0); -+ -+ /* -+ * The offsets must be unique. -+ */ -+ sort(dhpb->dthpb_offs, dhpb->dthpb_noffs, sizeof(uint32_t), -+ fasttrap_uint32_cmp, NULL); -+ for (i = 1; i < dhpb->dthpb_noffs; i++) { -+ if (dhpb->dthpb_base + dhpb->dthpb_offs[i] <= -+ dhpb->dthpb_base + dhpb->dthpb_offs[i - 1]) -+ return; -+ } -+ -+ sort(dhpb->dthpb_enoffs, dhpb->dthpb_nenoffs, sizeof(uint32_t), -+ fasttrap_uint32_cmp, NULL); -+ for (i = 1; i < dhpb->dthpb_nenoffs; i++) { -+ if (dhpb->dthpb_base + dhpb->dthpb_enoffs[i] <= -+ dhpb->dthpb_base + dhpb->dthpb_enoffs[i - 1]) -+ return; -+ } -+ -+ /* -+ * Grab the creation lock to ensure consistency between calls to -+ * dtrace_probe_lookup() and dtrace_probe_create() in the face of -+ * other threads creating probes. -+ */ -+ mutex_lock(&provider->ftp_cmtx); -+ -+ if (dtrace_probe_lookup(provider->ftp_provid, dhpb->dthpb_mod, -+ dhpb->dthpb_func, dhpb->dthpb_name) != DTRACE_IDNONE) { -+ mutex_unlock(&provider->ftp_cmtx); -+ return; -+ } -+ -+ ntps = dhpb->dthpb_noffs + dhpb->dthpb_nenoffs; -+ ASSERT(ntps > 0); -+ -+ pp = kzalloc(offsetof(struct fasttrap_probe, ftp_tps[ntps]), -+ GFP_KERNEL); -+ if (pp == NULL) { -+ pr_warn("Unable to create probe %s: out of memory\n", -+ dhpb->dthpb_name); -+ mutex_unlock(&provider->ftp_cmtx); -+ return; -+ } -+ -+ atomic_add(ntps, &fasttrap_total); -+ if (atomic_read(&fasttrap_total) > fasttrap_max) { -+ kfree(pp); -+ atomic_add(-ntps, &fasttrap_total); -+ mutex_unlock(&provider->ftp_cmtx); -+ return; -+ } -+ -+ pp->ftp_prov = provider; -+ pp->ftp_pid = provider->ftp_pid; -+ pp->ftp_ntps = ntps; -+ pp->ftp_nargs = dhpb->dthpb_xargc; -+ pp->ftp_xtypes = dhpb->dthpb_xtypes; -+ pp->ftp_ntypes = dhpb->dthpb_ntypes; -+ -+ /* -+ * First create a tracepoint for each actual point of interest. -+ */ -+ for (i = 0; i < dhpb->dthpb_noffs; i++) { -+ tp = kmem_cache_alloc(tracepoint_cachep, GFP_KERNEL); -+ if (tp == NULL) -+ goto fail; -+ -+ tp->ftt_proc = provider->ftp_proc; -+ tp->ftt_pc = dhpb->dthpb_base + dhpb->dthpb_offs[i]; -+ tp->ftt_pid = provider->ftp_pid; -+ memset(&tp->ftt_mtp, 0, sizeof(struct fasttrap_machtp)); -+ tp->ftt_ids = NULL; -+ tp->ftt_retids = NULL; -+ tp->ftt_next = NULL; -+ -+ dt_dbg_dof(" Tracepoint at 0x%lx (0x%llx + 0x%x)\n", -+ tp->ftt_pc, dhpb->dthpb_base, dhpb->dthpb_offs[i]); -+ -+ pp->ftp_tps[i].fit_tp = tp; -+ pp->ftp_tps[i].fit_id.fti_probe = pp; -+ pp->ftp_tps[i].fit_id.fti_ptype = DTFTP_OFFSETS; -+ } -+ -+ /* -+ * Then create a tracepoint for each is-enabled point. -+ */ -+ for (j = 0; i < ntps; i++, j++) { -+ tp = kmem_cache_alloc(tracepoint_cachep, GFP_KERNEL); -+ if (tp == NULL) -+ goto fail; -+ -+ tp->ftt_proc = provider->ftp_proc; -+ tp->ftt_pc = dhpb->dthpb_base + dhpb->dthpb_enoffs[j]; -+ tp->ftt_pid = provider->ftp_pid; -+ memset(&tp->ftt_mtp, 0, sizeof(struct fasttrap_machtp)); -+ tp->ftt_ids = NULL; -+ tp->ftt_retids = NULL; -+ tp->ftt_next = NULL; -+ -+ pp->ftp_tps[i].fit_tp = tp; -+ pp->ftp_tps[i].fit_id.fti_probe = pp; -+ pp->ftp_tps[i].fit_id.fti_ptype = DTFTP_IS_ENABLED; -+ } -+ -+ /* -+ * If the arguments are shuffled around we set the argument remapping -+ * table. Later, when the probe fires, we only remap the arguments -+ * if the table is non-NULL. -+ */ -+ for (i = 0; i < dhpb->dthpb_xargc; i++) { -+ if (dhpb->dthpb_args[i] != i) { -+ pp->ftp_argmap = dhpb->dthpb_args; -+ break; -+ } -+ } -+ -+ /* -+ * The probe is fully constructed -- register it with DTrace. -+ */ -+ pp->ftp_id = dtrace_probe_create(provider->ftp_provid, dhpb->dthpb_mod, -+ dhpb->dthpb_func, dhpb->dthpb_name, -+ FASTTRAP_OFFSET_AFRAMES, pp); -+ if (pp->ftp_id == DTRACE_IDNONE) -+ goto fail; -+ -+ mutex_unlock(&provider->ftp_cmtx); -+ return; -+ -+fail: -+ pr_warn("Unable to create probe %s: out of memory\n", -+ dhpb->dthpb_name); -+ -+ for (i = 0; i < ntps; i++) -+ kmem_cache_free(tracepoint_cachep, pp->ftp_tps[i].fit_tp); -+ -+ kfree(pp); -+ atomic_add(-ntps, &fasttrap_total); -+ mutex_unlock(&provider->ftp_cmtx); -+} -+ -+static void fasttrap_proc_release(struct fasttrap_proc *proc) -+{ -+ struct fasttrap_bucket *bucket; -+ struct fasttrap_proc *fprc, **fprcp; -+ pid_t pid = proc->ftpc_pid; -+ -+ mutex_lock(&proc->ftpc_mtx); -+ -+ ASSERT(proc->ftpc_rcount != 0); -+ ASSERT(atomic64_read(&proc->ftpc_acount) <= proc->ftpc_rcount); -+ -+ if (--proc->ftpc_rcount != 0) { -+ mutex_unlock(&proc->ftpc_mtx); -+ return; -+ } -+ -+ mutex_unlock(&proc->ftpc_mtx); -+ -+ /* -+ * There should definitely be no live providers associated with this -+ * process at this point. -+ */ -+ ASSERT(atomic64_read(&proc->ftpc_acount) == 0); -+ -+ bucket = FASTTRAP_PROCS_ELEM(pid); -+ mutex_lock(&bucket->ftb_mtx); -+ -+ fprcp = (struct fasttrap_proc **)&bucket->ftb_data; -+ while ((fprc = *fprcp) != NULL) { -+ if (fprc == proc) -+ break; -+ -+ fprcp = &fprc->ftpc_next; -+ } -+ -+ /* -+ * Something strange has happened if we can't find the proc. -+ */ -+ ASSERT(fprc != NULL); -+ -+ *fprcp = fprc->ftpc_next; -+ -+ mutex_unlock(&bucket->ftb_mtx); -+ -+ kfree(fprc); -+} -+ -+static void fasttrap_provider_free(struct fasttrap_provider *provider) -+{ -+ pid_t pid = provider->ftp_pid; -+ -+ /* -+ * There need to be no associated enabled probes, no consumers -+ * creating probes, and no meta providers referencing this provider. -+ */ -+ ASSERT(provider->ftp_rcount == 0); -+ ASSERT(provider->ftp_ccount == 0); -+ ASSERT(provider->ftp_mcount == 0); -+ -+ /* -+ * If this provider hasn't been retired, we need to explicitly drop the -+ * count of active providers on the associated process structure. -+ */ -+ if (!provider->ftp_retired) { -+ atomic64_add(-1, &provider->ftp_proc->ftpc_acount); -+ ASSERT(atomic64_read(&provider->ftp_proc->ftpc_acount) < -+ provider->ftp_proc->ftpc_rcount); -+ } -+ -+ fasttrap_proc_release(provider->ftp_proc); -+ -+ kfree(provider); -+ -+ unregister_pid_provider(pid); -+} -+ -+static struct fasttrap_proc *fasttrap_proc_lookup(pid_t pid) -+{ -+ struct fasttrap_bucket *bucket; -+ struct fasttrap_proc *fprc, *new_fprc; -+ -+ bucket = FASTTRAP_PROCS_ELEM(pid); -+ mutex_lock(&bucket->ftb_mtx); -+ -+ for (fprc = bucket->ftb_data; fprc != NULL; fprc = fprc->ftpc_next) { -+ if (fprc->ftpc_pid == pid && -+ atomic64_read(&fprc->ftpc_acount) != 0) { -+ mutex_lock(&fprc->ftpc_mtx); -+ mutex_unlock(&bucket->ftb_mtx); -+ fprc->ftpc_rcount++; -+ atomic64_inc(&fprc->ftpc_acount); -+ ASSERT(atomic64_read(&fprc->ftpc_acount) <= -+ fprc->ftpc_rcount); -+ mutex_unlock(&fprc->ftpc_mtx); -+ -+ return fprc; -+ } -+ } -+ -+ /* -+ * Drop the bucket lock so we don't try to perform a sleeping -+ * allocation under it. -+ */ -+ mutex_unlock(&bucket->ftb_mtx); -+ -+ new_fprc = kzalloc(sizeof(struct fasttrap_proc), GFP_KERNEL); -+ if (new_fprc == NULL) -+ return NULL; -+ -+ new_fprc->ftpc_pid = pid; -+ new_fprc->ftpc_rcount = 1; -+ atomic64_set(&new_fprc->ftpc_acount, 1); -+ mutex_init(&new_fprc->ftpc_mtx); -+ -+ mutex_lock(&bucket->ftb_mtx); -+ -+ /* -+ * Take another lap through the list to make sure a proc hasn't -+ * been created for this pid while we weren't under the bucket lock. -+ */ -+ for (fprc = bucket->ftb_data; fprc != NULL; fprc = fprc->ftpc_next) { -+ if (fprc->ftpc_pid == pid && -+ atomic64_read(&fprc->ftpc_acount) != 0) { -+ mutex_lock(&fprc->ftpc_mtx); -+ mutex_unlock(&bucket->ftb_mtx); -+ fprc->ftpc_rcount++; -+ atomic64_inc(&fprc->ftpc_acount); -+ ASSERT(atomic64_read(&fprc->ftpc_acount) <= -+ fprc->ftpc_rcount); -+ mutex_unlock(&fprc->ftpc_mtx); -+ -+ kfree(new_fprc); -+ -+ return fprc; -+ } -+ } -+ -+ new_fprc->ftpc_next = bucket->ftb_data; -+ bucket->ftb_data = new_fprc; -+ -+ mutex_unlock(&bucket->ftb_mtx); -+ -+ return new_fprc; -+} -+ -+/* -+ * Lookup a fasttrap-managed provider based on its name and associated pid. -+ * If the pattr argument is non-NULL, this function instantiates the provider -+ * if it doesn't exist otherwise it returns NULL. The provider is returned -+ * with its lock held. -+ */ -+static struct fasttrap_provider * -+fasttrap_provider_lookup(pid_t pid, const char *name, -+ const struct dtrace_pattr *pa) -+{ -+ struct fasttrap_provider *fp, *new_fp = NULL; -+ struct fasttrap_proc *proc = NULL; -+ struct fasttrap_bucket *bucket; -+ char provname[DTRACE_PROVNAMELEN]; -+ struct task_struct *p; -+ const struct cred *cred = NULL; -+ -+ ASSERT(strlen(name) < sizeof(fp->ftp_name)); -+ ASSERT(pa != NULL); -+ -+ bucket = FASTTRAP_PROVS_ELEM(pid, name); -+ mutex_lock(&bucket->ftb_mtx); -+ -+ /* -+ * Take a lap through the list and return the match if we find it. -+ */ -+ for (fp = bucket->ftb_data; fp != NULL; fp = fp->ftp_next) { -+ if (fp->ftp_pid == pid && strcmp(fp->ftp_name, name) == 0 && -+ !fp->ftp_retired) { -+ mutex_lock(&fp->ftp_mtx); -+ mutex_unlock(&bucket->ftb_mtx); -+ -+ return fp; -+ } -+ } -+ -+ /* -+ * Drop the bucket lock so we don't try to perform a sleeping -+ * allocation under it. -+ */ -+ mutex_unlock(&bucket->ftb_mtx); -+ -+ p = register_pid_provider(pid); -+ if (p == NULL) -+ goto fail; -+ -+ /* -+ * Grab the credentials for this process so we have -+ * something to pass to dtrace_register(). -+ */ -+ cred = get_cred(p->cred); -+ -+ proc = fasttrap_proc_lookup(pid); -+ if (proc == NULL) -+ goto fail; -+ -+ new_fp = kzalloc(sizeof(struct fasttrap_provider), GFP_KERNEL); -+ if (new_fp == NULL) -+ goto fail; -+ -+ new_fp->ftp_pid = pid; -+ new_fp->ftp_proc = proc; -+ mutex_init(&new_fp->ftp_mtx); -+ mutex_init(&new_fp->ftp_cmtx); -+ -+ ASSERT(new_fp->ftp_proc != NULL); -+ -+ mutex_lock(&bucket->ftb_mtx); -+ -+ /* -+ * Take another lap through the list to make sure a provider hasn't -+ * been created for this pid while we weren't under the bucket lock. -+ */ -+ for (fp = bucket->ftb_data; fp != NULL; fp = fp->ftp_next) { -+ if (fp->ftp_pid == pid && strcmp(fp->ftp_name, name) == 0 && -+ !fp->ftp_retired) { -+ mutex_lock(&fp->ftp_mtx); -+ mutex_unlock(&bucket->ftb_mtx); -+ fasttrap_provider_free(new_fp); -+ put_cred(cred); -+ -+ return fp; -+ } -+ } -+ -+ strcpy(new_fp->ftp_name, name); -+ -+ /* -+ * Fail and return NULL if either the provider name is too long -+ * or we fail to register this new provider with the DTrace -+ * framework. Note that this is the only place we ever construct -+ * the full provider name -- we keep it in pieces in the provider -+ * structure. -+ */ -+ if (snprintf(provname, sizeof(provname), "%s%u", name, (uint_t)pid) >= -+ sizeof(provname) || -+ dtrace_register(provname, pa, -+ DTRACE_PRIV_PROC | DTRACE_PRIV_OWNER, cred, -+ pa == &pid_attr ? &pid_pops : &usdt_pops, -+ new_fp, &new_fp->ftp_provid) != 0) { -+ mutex_unlock(&bucket->ftb_mtx); -+ fasttrap_provider_free(new_fp); -+ put_cred(cred); -+ return NULL; -+ } -+ -+ new_fp->ftp_next = bucket->ftb_data; -+ bucket->ftb_data = new_fp; -+ -+ mutex_lock(&new_fp->ftp_mtx); -+ mutex_unlock(&bucket->ftb_mtx); -+ -+ put_cred(cred); -+ -+ return new_fp; -+ -+fail: -+ if (proc) -+ fasttrap_proc_release(proc); -+ if (cred) -+ put_cred(cred); -+ if (p) -+ unregister_pid_provider(pid); -+ -+ return NULL; -+} -+ -+void *fasttrap_meta_provide(void *arg, struct dtrace_helper_provdesc *dhpv, -+ pid_t pid) -+{ -+ struct fasttrap_provider *provider; -+ -+ if (strlen(dhpv->dthpv_provname) + 10 >= sizeof(provider->ftp_name)) { -+ pr_warn("Failed to instantiate provider %s: name too long " -+ "to accommodate pid\n", dhpv->dthpv_provname); -+ return NULL; -+ } -+ -+ /* -+ * Don't let folks spoof the true pid provider. -+ */ -+ if (strcmp(dhpv->dthpv_provname, FASTTRAP_PID_NAME) == 0) { -+ pr_warn("Failed to instantiate provider %s: %s is an invalid " -+ "name\n", dhpv->dthpv_provname, FASTTRAP_PID_NAME); -+ return NULL; -+ } -+ -+ /* -+ * The highest stability class that fasttrap supports is ISA; cap -+ * the stability of the new provider accordingly. -+ */ -+ if (dhpv->dthpv_pattr.dtpa_provider.dtat_class > DTRACE_CLASS_ISA) -+ dhpv->dthpv_pattr.dtpa_provider.dtat_class = DTRACE_CLASS_ISA; -+ if (dhpv->dthpv_pattr.dtpa_mod.dtat_class > DTRACE_CLASS_ISA) -+ dhpv->dthpv_pattr.dtpa_mod.dtat_class = DTRACE_CLASS_ISA; -+ if (dhpv->dthpv_pattr.dtpa_func.dtat_class > DTRACE_CLASS_ISA) -+ dhpv->dthpv_pattr.dtpa_func.dtat_class = DTRACE_CLASS_ISA; -+ if (dhpv->dthpv_pattr.dtpa_name.dtat_class > DTRACE_CLASS_ISA) -+ dhpv->dthpv_pattr.dtpa_name.dtat_class = DTRACE_CLASS_ISA; -+ if (dhpv->dthpv_pattr.dtpa_args.dtat_class > DTRACE_CLASS_ISA) -+ dhpv->dthpv_pattr.dtpa_args.dtat_class = DTRACE_CLASS_ISA; -+ -+ provider = fasttrap_provider_lookup(pid, dhpv->dthpv_provname, -+ &dhpv->dthpv_pattr); -+ if (provider == NULL) { -+ pr_warn("Failed to instantiate provider %s for process %u\n", -+ dhpv->dthpv_provname, (uint_t)pid); -+ return NULL; -+ } -+ -+ /* -+ * Up the meta provider count so this provider isn't removed until the -+ * meta provider has been told to remove it. -+ */ -+ provider->ftp_mcount++; -+ -+ mutex_unlock(&provider->ftp_mtx); -+ -+ return provider; -+} -+ -+static void fasttrap_pid_cleanup_cb(struct work_struct *work) -+{ -+ struct fasttrap_provider **fpp, *fp; -+ struct fasttrap_bucket *bucket; -+ dtrace_provider_id_t provid; -+ int i, later = 0; -+ -+ static volatile int in; -+ -+ ASSERT(in == 0); -+ in = 1; -+ -+ mutex_lock(&fasttrap_cleanup_mtx); -+ if (!fasttrap_cleanup_work && fasttrap_cleanup_state == CLEANUP_NONE) { -+ mutex_unlock(&fasttrap_cleanup_mtx); -+ in = 0; -+ return; -+ } -+ -+ dt_dbg_prov("Fasttrap provider cleanup callback processing...\n"); -+ while (fasttrap_cleanup_work) { -+ fasttrap_cleanup_work = 0; -+ mutex_unlock(&fasttrap_cleanup_mtx); -+ -+ later = 0; -+ -+ /* -+ * Iterate over all the providers trying to remove the marked -+ * ones. If a provider is marked but not retired, we just -+ * have to take a crack at removing it -- it's no big deal if -+ * we can't. -+ */ -+ for (i = 0; i < fasttrap_provs.fth_nent; i++) { -+ bucket = FASTTRAP_ELEM_BUCKET(&fasttrap_provs.fth_table[i]); -+ mutex_lock(&bucket->ftb_mtx); -+ fpp = (struct fasttrap_provider **)&bucket->ftb_data; -+ -+ while ((fp = *fpp) != NULL) { -+ dt_dbg_prov(" Trying to unregister %s%d " -+ "(%smarked)\n", -+ fp->ftp_name, fp->ftp_pid, -+ fp->ftp_marked ? "not " : ""); -+ if (!fp->ftp_marked) { -+ fpp = &fp->ftp_next; -+ continue; -+ } -+ -+ dt_dbg_prov(" ccount %llu, mcount %llu " -+ "rcount %llu, %sretired, " -+ "%smarked\n", -+ fp->ftp_ccount, fp->ftp_mcount, -+ fp->ftp_rcount, -+ fp->ftp_retired ? "" : "not ", -+ fp->ftp_marked ? "" : "not "); -+ -+ mutex_lock(&fp->ftp_mtx); -+ -+ /* -+ * If this provider has consumers actively -+ * creating probes (ftp_ccount) or is a USDT -+ * provider (ftp_mcount), we can't unregister -+ * or even condense. -+ */ -+ if (fp->ftp_ccount != 0 || -+ fp->ftp_mcount != 0) { -+ mutex_unlock(&fp->ftp_mtx); -+ fp->ftp_marked = 0; -+ continue; -+ } -+ -+ if (!fp->ftp_retired || fp->ftp_rcount != 0) -+ fp->ftp_marked = 0; -+ -+ mutex_unlock(&fp->ftp_mtx); -+ -+ /* -+ * If we successfully unregister this -+ * provider we can remove it from the hash -+ * chain and free the memory. If our attempt -+ * to unregister fails and this is a retired -+ * provider, increment our flag to try again -+ * pretty soon. If we've consumed more than -+ * half of our total permitted number of -+ * probes call dtrace_condense() to try to -+ * clean out the unenabled probes. -+ */ -+ provid = fp->ftp_provid; -+ mutex_lock(&module_mutex); -+ if (dtrace_unregister(provid) != 0) { -+ if (atomic_read(&fasttrap_total) > -+ fasttrap_max / 2) -+ dtrace_condense(provid); -+ -+ later += fp->ftp_marked; -+ fpp = &fp->ftp_next; -+ } else { -+ *fpp = fp->ftp_next; -+ fasttrap_provider_free(fp); -+ } -+ mutex_unlock(&module_mutex); -+ } -+ -+ mutex_unlock(&bucket->ftb_mtx); -+ } -+ -+ mutex_lock(&fasttrap_cleanup_mtx); -+ } -+ -+ ASSERT(fasttrap_cleanup_state != CLEANUP_NONE); -+ -+ /* -+ * If we were unable to remove a retired provider, try again after -+ * a second. This situation can occur in certain circumstances where -+ * providers cannot be unregistered even though they have no probes -+ * enabled because of an execution of dtrace -l or something similar. -+ * If the timeout has been disabled (set to 1 because we're trying -+ * to detach), we set fasttrap_cleanup_work to ensure that we'll -+ * get a chance to do that work if and when the timeout is reenabled -+ * (if detach fails). -+ */ -+ if (later > 0) { -+ dt_dbg_prov(" Some providers were not removed " -+ " (state %d, later = %d)\n", -+ fasttrap_cleanup_state, later); -+ if (fasttrap_cleanup_state == CLEANUP_DEFERRED) -+ fasttrap_cleanup_work = 1; -+ else { -+ struct delayed_work *dw = container_of( -+ work, -+ struct delayed_work, -+ work); -+ -+ fasttrap_cleanup_state = CLEANUP_SCHEDULED; -+ schedule_delayed_work(dw, HZ); -+ } -+ } else -+ fasttrap_cleanup_state = CLEANUP_NONE; -+ -+ mutex_unlock(&fasttrap_cleanup_mtx); -+ in = 0; -+ -+ dt_dbg_prov("Fasttrap provider cleanup callback done\n"); -+} -+ -+static DECLARE_DELAYED_WORK(fasttrap_cleanup, fasttrap_pid_cleanup_cb); -+ -+/* -+ * Activate the asynchronous cleanup mechanism. -+ */ -+static void fasttrap_pid_cleanup(void) -+{ -+ mutex_lock(&fasttrap_cleanup_mtx); -+ fasttrap_cleanup_work = 1; -+ fasttrap_cleanup_state = CLEANUP_SCHEDULED; -+ schedule_delayed_work(&fasttrap_cleanup, 3); -+ mutex_unlock(&fasttrap_cleanup_mtx); -+} -+ -+void fasttrap_provider_retire(pid_t pid, const char *name, int mprov) -+{ -+ struct fasttrap_provider *fp; -+ struct fasttrap_bucket *bucket; -+ dtrace_provider_id_t provid; -+ -+ ASSERT(strlen(name) < sizeof(fp->ftp_name)); -+ -+ dt_dbg_prov("Retiring %s %sprovider for PID %d\n", -+ name, mprov ? "meta-" : "", pid); -+ -+ bucket = FASTTRAP_PROVS_ELEM(pid, name); -+ mutex_lock(&bucket->ftb_mtx); -+ -+ for (fp = bucket->ftb_data; fp != NULL; fp = fp->ftp_next) { -+ if (fp->ftp_pid == pid && strcmp(fp->ftp_name, name) == 0 && -+ !fp->ftp_retired) -+ break; -+ } -+ -+ if (fp == NULL) { -+ mutex_unlock(&bucket->ftb_mtx); -+ return; -+ } -+ -+ mutex_lock(&fp->ftp_mtx); -+ ASSERT(!mprov || fp->ftp_mcount > 0); -+ if (mprov && --fp->ftp_mcount != 0) { -+ mutex_unlock(&fp->ftp_mtx); -+ mutex_unlock(&bucket->ftb_mtx); -+ return; -+ } -+ -+ /* -+ * Mark the provider to be removed in our post-processing step, mark it -+ * retired, and drop the active count on its proc. Marking it indicates -+ * that we should try to remove it; setting the retired flag indicates -+ * that we're done with this provider; dropping the active count on the -+ * proc releases our hold, and when this reaches zero (as it will -+ * during exit or exec) the proc and associated providers become -+ * defunct. -+ * -+ * We obviously need to take the bucket lock before the provider lock -+ * to perform the lookup, but we need to drop the provider lock -+ * before calling into the DTrace framework since we acquire the -+ * provider lock in callbacks invoked from the DTrace framework. The -+ * bucket lock therefore protects the integrity of the provider hash -+ * table. -+ */ -+ atomic64_dec(&fp->ftp_proc->ftpc_acount); -+ ASSERT(atomic64_read(&fp->ftp_proc->ftpc_acount) < -+ fp->ftp_proc->ftpc_rcount); -+ -+ fp->ftp_retired = 1; -+ fp->ftp_marked = 1; -+ provid = fp->ftp_provid; -+ mutex_unlock(&fp->ftp_mtx); -+ -+ /* -+ * We don't have to worry about invalidating the same provider twice -+ * since fasttrap_provider_lookup() will ignore provider that have -+ * been marked as retired. -+ */ -+ dtrace_invalidate(provid); -+ -+ mutex_unlock(&bucket->ftb_mtx); -+ -+ fasttrap_pid_cleanup(); -+} -+ -+static void fasttrap_probes_cleanup(struct task_struct *tsk) -+{ -+ fasttrap_provider_retire(tsk->pid, FASTTRAP_PID_NAME, 0); -+} -+ -+void fasttrap_meta_remove(void *arg, struct dtrace_helper_provdesc *dhpv, -+ pid_t pid) -+{ -+ /* -+ * Clean up the USDT provider. There may be active consumers of the -+ * provider busy adding probes, no damage will actually befall the -+ * provider until that count has dropped to zero. This just puts -+ * the provider on death row. -+ */ -+ fasttrap_provider_retire(pid, dhpv->dthpv_provname, 1); -+} -+ -+static int fasttrap_add_probe(struct fasttrap_probe_spec *probe) -+{ -+ struct fasttrap_provider *provider; -+ struct fasttrap_probe *pp; -+ struct fasttrap_tracepoint *tp; -+ uint64_t *offs = NULL; -+ uint64_t noffs; -+ char *name; -+ int aframes, retired; -+ -+ switch (probe->ftps_type) { -+ case DTFTP_ENTRY: -+ name = "entry"; -+ aframes = FASTTRAP_ENTRY_AFRAMES; -+ break; -+ case DTFTP_RETURN: -+ name = "return"; -+ aframes = FASTTRAP_RETURN_AFRAMES; -+ break; -+ case DTFTP_OFFSETS: -+ if (probe->ftps_glen <= 0) -+ return -EINVAL; -+ -+ name = "<offsets>"; -+ aframes = FASTTRAP_OFFSET_AFRAMES; -+ offs = fasttrap_glob_offsets(probe, &noffs); -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ provider = fasttrap_provider_lookup(probe->ftps_pid, FASTTRAP_PID_NAME, -+ &pid_attr); -+ if (provider == NULL) -+ return -ESRCH; -+ -+ /* -+ * Increment the consumer reference count on the provider to indicate -+ * that a new probe is being associated with the provider. This makes -+ * sure that the provider will not be removed while we are working with -+ * it. -+ * -+ * This also means that we can drop the provider lock. -+ */ -+ provider->ftp_ccount++; -+ mutex_unlock(&provider->ftp_mtx); -+ -+ /* -+ * Grab the probe creation lock for this provider to ensure consistency -+ * between dtrace_probe_lookup() and dtrace_probe_create() because -+ * other threads might be creating probes also. -+ */ -+ mutex_lock(&provider->ftp_cmtx); -+ -+ if (probe->ftps_type == DTFTP_OFFSETS) { -+ int i; -+ -+ for (i = 0; i < noffs; i++) { -+ char ostr[sizeof(*offs) + 1]; -+ -+ snprintf(ostr, sizeof(ostr), "%llx", offs[i]); -+ if (dtrace_probe_lookup(provider->ftp_provid, -+ probe->ftps_mod, -+ probe->ftps_func, ostr) != 0) -+ continue; -+ -+ atomic_add(1, &fasttrap_total); -+ if (atomic_read(&fasttrap_total) > fasttrap_max) -+ goto fail_reset; -+ -+ pp = kzalloc(sizeof(struct fasttrap_probe), GFP_KERNEL); -+ if (pp == NULL) -+ goto fail_reset; -+ -+ pp->ftp_prov = provider; -+ pp->ftp_pid = provider->ftp_pid; -+ pp->ftp_ntps = 1; -+ -+ tp = kmem_cache_alloc(tracepoint_cachep, GFP_KERNEL); -+ if (tp == NULL) -+ goto fail_reset; -+ -+ tp->ftt_proc = provider->ftp_proc; -+ tp->ftt_pc = probe->ftps_pc + offs[i]; -+ tp->ftt_pid = provider->ftp_pid; -+ memset(&tp->ftt_mtp, 0, -+ sizeof(struct fasttrap_machtp)); -+ tp->ftt_ids = NULL; -+ tp->ftt_retids = NULL; -+ tp->ftt_next = NULL; -+ -+ pp->ftp_tps[0].fit_tp = tp; -+ pp->ftp_tps[0].fit_id.fti_probe = pp; -+ pp->ftp_tps[0].fit_id.fti_ptype = probe->ftps_type; -+ -+ pp->ftp_id = dtrace_probe_create(provider->ftp_provid, -+ probe->ftps_mod, -+ probe->ftps_func, ostr, -+ aframes, pp); -+ if (pp->ftp_id == DTRACE_IDNONE) { -+ kmem_cache_free(tracepoint_cachep, tp); -+ kfree(pp); -+ -+ goto fail_reset; -+ } -+ } -+ } else if (dtrace_probe_lookup(provider->ftp_provid, probe->ftps_mod, -+ probe->ftps_func, name) == 0) { -+ atomic_add(1, &fasttrap_total); -+ if (atomic_read(&fasttrap_total) > fasttrap_max) -+ goto fail_reset; -+ -+ pp = kzalloc(sizeof(struct fasttrap_probe), GFP_KERNEL); -+ if (pp == NULL) -+ goto fail_reset; -+ -+ pp->ftp_prov = provider; -+ pp->ftp_pid = provider->ftp_pid; -+ pp->ftp_ntps = 1; -+ -+ tp = kmem_cache_alloc(tracepoint_cachep, GFP_KERNEL); -+ if (tp == NULL) -+ goto fail_reset; -+ -+ tp->ftt_proc = provider->ftp_proc; -+ tp->ftt_pc = probe->ftps_pc; -+ tp->ftt_pid = provider->ftp_pid; -+ memset(&tp->ftt_mtp, 0, sizeof(struct fasttrap_machtp)); -+ tp->ftt_ids = NULL; -+ tp->ftt_retids = NULL; -+ tp->ftt_next = NULL; -+ -+ pp->ftp_tps[0].fit_tp = tp; -+ pp->ftp_tps[0].fit_id.fti_probe = pp; -+ pp->ftp_tps[0].fit_id.fti_ptype = probe->ftps_type; -+ -+ pp->ftp_id = dtrace_probe_create(provider->ftp_provid, -+ probe->ftps_mod, -+ probe->ftps_func, name, -+ aframes, pp); -+ if (pp->ftp_id == DTRACE_IDNONE) { -+ kmem_cache_free(tracepoint_cachep, tp); -+ kfree(pp); -+ -+ goto fail_reset; -+ } -+ } -+ -+ mutex_unlock(&provider->ftp_cmtx); -+ -+ /* -+ * The provider is still around because of the consumer reference -+ * count that we incremented. If another thread tried to clean up the -+ * provider while we were using it (because the process called exec or -+ * exit), we'll trigger a cleanup. -+ */ -+ mutex_lock(&provider->ftp_mtx); -+ provider->ftp_ccount--; -+ retired = provider->ftp_retired; -+ mutex_unlock(&provider->ftp_mtx); -+ -+ if (retired) -+ fasttrap_pid_cleanup(); -+ -+ return 0; -+ -+fail_reset: -+ atomic_add(-1, &fasttrap_total); -+ -+ /* -+ * If we failed to create the probe, it usually means we ran out of -+ * memory. We'll try to remove this provider to free some. This -+ * usually happens when a user accidentally triggers the creation of -+ * a very large amount of probes (e.g. pid587:::). -+ */ -+ mutex_unlock(&provider->ftp_cmtx); -+ -+ kfree(offs); -+ -+ mutex_lock(&provider->ftp_mtx); -+ provider->ftp_ccount--; -+ provider->ftp_marked = 1; -+ mutex_unlock(&provider->ftp_mtx); -+ -+ fasttrap_pid_cleanup(); -+ -+ return -ENOMEM; -+} -+ -+static long fasttrap_ioctl(struct file *file, -+ unsigned int cmd, unsigned long arg) -+{ -+ void __user *argp = (void __user *)arg; -+ -+ if (cmd == FASTTRAPIOC_MAKEPROBE) { -+ struct fasttrap_probe_spec __user *uprobe = argp; -+ struct fasttrap_probe_spec *probe; -+ uint8_t glen; -+ size_t size; -+ int ret; -+ char *c; -+ -+ dt_dbg_ioctl("PID IOCTL MAKEPROBE (cmd %#x), argp %p\n", -+ cmd, argp); -+ -+ if (copy_from_user(&glen, &uprobe->ftps_glen, -+ sizeof(uprobe->ftps_glen))) -+ return -EFAULT; -+ -+ size = sizeof(struct fasttrap_probe_spec) + -+ sizeof(probe->ftps_gstr[0]) * (glen - 1); -+ -+ if (size > 1024 * 1024) -+ return -ENOMEM; -+ -+ probe = kmalloc(size, GFP_KERNEL); -+ if (!probe) -+ return -ENOMEM; -+ -+ if (copy_from_user(probe, uprobe, size) != 0) { -+ ret = -EFAULT; -+ goto err; -+ } -+ -+ for (c = &probe->ftps_func[0]; *c != '\0'; c++) { -+ if (*c < 0x20 || 0x7f <= *c) { -+ ret = -EINVAL; -+ goto err; -+ } -+ } -+ -+ for (c = &probe->ftps_mod[0]; *c != '\0'; c++) { -+ if (*c < 0x20 || 0x7f <= *c) { -+ ret = -EINVAL; -+ goto err; -+ } -+ } -+ -+ ret = fasttrap_add_probe(probe); -+err: -+ kfree(probe); -+ -+ return ret; -+ } -+ -+ return -EAGAIN; -+} -+ -+static int fasttrap_open(struct inode *inode, struct file *file) -+{ -+ return 0; -+} -+ -+static int fasttrap_close(struct inode *inode, struct file *file) -+{ -+ return 0; -+} -+ -+static const struct file_operations fasttrap_fops = { -+ .owner = THIS_MODULE, -+ .unlocked_ioctl = fasttrap_ioctl, -+ .open = fasttrap_open, -+ .release = fasttrap_close, -+}; -+ -+static struct miscdevice fasttrap_dev = { -+ .minor = DT_DEV_FASTTRAP_MINOR, -+ .name = "fasttrap", -+ .nodename = "dtrace/provider/fasttrap", -+ .fops = &fasttrap_fops, -+}; -+ -+static int fasttrap_init_htable(struct fasttrap_hash *fth, ulong_t nent) -+{ -+ ulong_t i; -+ -+ if ((nent & (nent - 1)) == 0) -+ fth->fth_nent = nent; -+ else -+ fth->fth_nent = 1 << fls(nent); -+ -+ ASSERT(fth->fth_nent > 0); -+ -+ fth->fth_mask = fth->fth_nent - 1; -+ fth->fth_table = vzalloc(fth->fth_nent * -+ sizeof(struct fasttrap_bucket_elem)); -+ -+ if (fth->fth_table == NULL) -+ return -ENOMEM; -+ -+ for (i = 0; i < fth->fth_nent; i++) -+ mutex_init(&fth->fth_table[i].bucket.ftb_mtx); -+ -+ return 0; -+} -+ -+int fasttrap_dev_init(void) -+{ -+ int ret = 0; -+ ulong_t nent; -+ -+ ret = misc_register(&fasttrap_dev); -+ if (ret) { -+ pr_err("%s: Can't register misc device %d\n", -+ fasttrap_dev.name, fasttrap_dev.minor); -+ goto fail; -+ } -+ -+#ifdef FIXME -+ dtrace_fasttrap_exit_ptr = &fasttrap_exec_exit; -+ dtrace_fasttrap_exec_ptr = &fasttrap_exec_exit; -+#endif -+ -+ tracepoint_cachep = KMEM_CACHE(fasttrap_tracepoint, 0); -+ -+ fasttrap_max = FASTTRAP_MAX_DEFAULT; -+ atomic_set(&fasttrap_total, 0); -+ -+ /* -+ * Conjure up the tracepoints hashtable... -+ */ -+ nent = FASTTRAP_TPOINTS_DEFAULT_SIZE; -+ -+ if (nent == 0 || nent > 0x1000000) -+ nent = FASTTRAP_TPOINTS_DEFAULT_SIZE; -+ -+ if (fasttrap_init_htable(&fasttrap_tpoints, nent) != 0) -+ return -ENOMEM; -+ -+ /* -+ * ... and the providers hash table... -+ */ -+ nent = FASTTRAP_PROVIDERS_DEFAULT_SIZE; -+ if (fasttrap_init_htable(&fasttrap_provs, nent) != 0) -+ return -ENOMEM; -+ -+ /* -+ * ... and the procs hash table. -+ */ -+ nent = FASTTRAP_PROCS_DEFAULT_SIZE; -+ if (fasttrap_init_htable(&fasttrap_procs, nent) != 0) -+ return -ENOMEM; -+ -+fail: -+ return ret; -+} -+ -+/* -+ * This function is called with module_mutex held. -+ */ -+int fasttrap_prov_exit(void) -+{ -+ int fail = 0; -+ ulong_t i; -+ -+ if (dtrace_meta_unregister(fasttrap_id) != 0) -+ return 0; -+ -+ /* -+ * Prevent any new timeouts from running by setting fasttrap_timeout -+ * to a non-zero value, and wait for the current timeout to complete. -+ */ -+ mutex_lock(&fasttrap_cleanup_mtx); -+ fasttrap_cleanup_work = 0; -+ -+ while (fasttrap_cleanup_state != CLEANUP_DEFERRED) { -+ uint_t tmp; -+ -+ tmp = fasttrap_cleanup_state; -+ fasttrap_cleanup_state = CLEANUP_DEFERRED; -+ -+ if (tmp != CLEANUP_NONE) { -+ mutex_unlock(&fasttrap_cleanup_mtx); -+ flush_delayed_work(&fasttrap_cleanup); -+ mutex_lock(&fasttrap_cleanup_mtx); -+ } -+ } -+ -+ fasttrap_cleanup_work = 0; -+ mutex_unlock(&fasttrap_cleanup_mtx); -+ -+ /* -+ * Iterate over all of our providers. If there's still a process -+ * that corresponds to that pid, fail to detach. -+ */ -+ for (i = 0; i < fasttrap_provs.fth_nent; i++) { -+ struct fasttrap_provider **fpp, *fp; -+ struct fasttrap_bucket *bucket; -+ -+ bucket = FASTTRAP_ELEM_BUCKET(&fasttrap_provs.fth_table[i]); -+ mutex_lock(&bucket->ftb_mtx); -+ fpp = (struct fasttrap_provider **)&bucket->ftb_data; -+ while ((fp = *fpp) != NULL) { -+ /* -+ * Acquire and release the lock as a simple way of -+ * waiting for any other consumer to finish with -+ * this provider. A thread must first acquire the -+ * bucket lock so there's no chance of another thread -+ * blocking on the provider's lock. -+ */ -+ mutex_lock(&fp->ftp_mtx); -+ mutex_unlock(&fp->ftp_mtx); -+ -+ if (dtrace_unregister(fp->ftp_provid) != 0) { -+ fail = 1; -+ fpp = &fp->ftp_next; -+ } else { -+ *fpp = fp->ftp_next; -+ fasttrap_provider_free(fp); -+ } -+ } -+ -+ mutex_unlock(&bucket->ftb_mtx); -+ } -+ -+ if (fail) { -+ uint_t work; -+ -+ /* -+ * If we're failing to detach, we need to unblock timeouts -+ * and start a new timeout if any work has accumulated while -+ * we've been unsuccessfully trying to detach. -+ */ -+ mutex_lock(&fasttrap_cleanup_mtx); -+ fasttrap_cleanup_state = CLEANUP_NONE; -+ work = fasttrap_cleanup_work; -+ mutex_unlock(&fasttrap_cleanup_mtx); -+ -+ if (work) -+ fasttrap_pid_cleanup(); -+ -+ dtrace_meta_register("fasttrap", &fasttrap_mops, NULL, -+ &fasttrap_id); -+ -+ return 0; -+ } -+ -+ return 1; -+} -+ -+void fasttrap_dev_exit(void) -+{ -+#ifdef DEBUG -+ mutex_lock(&fasttrap_count_mtx); -+ ASSERT(fasttrap_pid_count == 0); -+ mutex_unlock(&fasttrap_count_mtx); -+#endif -+ -+ if (fasttrap_tpoints.fth_table) -+ vfree(fasttrap_tpoints.fth_table); -+ fasttrap_tpoints.fth_nent = 0; -+ -+ if (fasttrap_provs.fth_table) -+ vfree(fasttrap_provs.fth_table); -+ fasttrap_provs.fth_nent = 0; -+ -+ if (fasttrap_procs.fth_table) -+ vfree(fasttrap_procs.fth_table); -+ fasttrap_procs.fth_nent = 0; -+ -+ kmem_cache_destroy(tracepoint_cachep); -+ -+#ifdef FIXME -+ ASSERT(dtrace_fasttrap_exec_ptr == &fasttrap_exec_exit); -+ dtrace_fasttrap_exec_ptr = NULL; -+ -+ ASSERT(dtrace_fasttrap_exit_ptr == &fasttrap_exec_exit); -+ dtrace_fasttrap_exit_ptr = NULL; -+#endif -+ -+ misc_deregister(&fasttrap_dev); -+} -diff --git a/dtrace/fasttrap_impl.h b/dtrace/fasttrap_impl.h -new file mode 100644 -index 0000000000000000000000000000000000000000..cd2c4a28871eff171e5171860d600dd27e9404d7 ---- /dev/null -+++ b/dtrace/fasttrap_impl.h -@@ -0,0 +1,172 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Dynamic Tracing for Linux - fasttrap provider -+ * -+ * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#ifndef _FASTTRAP_IMPL_H_ -+#define _FASTTRAP_IMPL_H_ -+ -+#include <linux/dtrace/fasttrap.h> -+#include <dtrace/fasttrap_arch.h> -+#include <linux/cache.h> -+ -+/* -+ * Fasttrap Providers, Probes and Tracepoints -+ * -+ * Each Solaris process can have multiple providers -- the pid provider as -+ * well as any number of user-level statically defined tracing (USDT) -+ * providers. Those providers are each represented by a fasttrap_provider. -+ * All providers for a given process have a pointer to a shared -+ * fasttrap_proc. The fasttrap_proc has two states: active or defunct. -+ * When the count of active providers goes to zero it becomes defunct; a -+ * provider drops its active count when it is removed individually or as part -+ * of a mass removal when a process exits or performs an exec. -+ * -+ * Each probe is represented by a fasttrap_probe which has a pointer to -+ * its associated provider as well as a list of fasttrap_id_tp structures -+ * which are tuples combining a fasttrap_id and a fasttrap_tracepoint. -+ * A fasttrap_tracepoint represents the actual point of instrumentation -+ * and it contains two lists of fasttrap_id structures (to be fired pre- -+ * and post-instruction emulation) that identify the probes attached to the -+ * tracepoint. Tracepoints also have a pointer to the fasttrap_proc for the -+ * process they trace which is used when looking up a tracepoint both when a -+ * probe fires and when enabling and disabling probes. -+ * -+ * It's important to note that probes are preallocated with the necessary -+ * number of tracepoints, but that tracepoints can be shared by probes and -+ * swapped between probes. If a probe's preallocated tracepoint is enabled -+ * (and, therefore, the associated probe is enabled), and that probe is -+ * then disabled, ownership of that tracepoint may be exchanged for an -+ * unused tracepoint belonging to another probe that was attached to the -+ * enabled tracepoint. -+ */ -+struct fasttrap_proc { -+ pid_t ftpc_pid; /* process ID for this proc */ -+ atomic64_t ftpc_acount; /* count of active providers */ -+ uint64_t ftpc_rcount; /* count of extant providers */ -+ struct mutex ftpc_mtx; /* lock on all but acount */ -+ struct fasttrap_proc *ftpc_next; /* next proc in hash chain */ -+}; -+ -+struct fasttrap_provider { -+ pid_t ftp_pid; /* process ID for this prov */ -+ char ftp_name[DTRACE_PROVNAMELEN]; /* prov name (w/o the pid) */ -+ dtrace_provider_id_t ftp_provid; /* DTrace provider handle */ -+ uint_t ftp_marked; /* mark for possible removal */ -+ uint_t ftp_retired; /* mark when retired */ -+ struct mutex ftp_mtx; /* provider lock */ -+ struct mutex ftp_cmtx; /* lock on creating probes */ -+ uint64_t ftp_rcount; /* enabled probes ref count */ -+ uint64_t ftp_ccount; /* consumers creating probes */ -+ uint64_t ftp_mcount; /* meta provider count */ -+ struct fasttrap_proc *ftp_proc; /* shared proc for all provs */ -+ struct fasttrap_provider *ftp_next; /* next prov in hash chain */ -+}; -+ -+struct fasttrap_id { -+ struct fasttrap_probe *fti_probe; /* referrring probe */ -+ struct fasttrap_id *fti_next; /* enabled probe list on tp */ -+ enum fasttrap_probe_type fti_ptype; /* probe type */ -+}; -+ -+struct fasttrap_tracepoint { -+ struct fasttrap_proc *ftt_proc; /* associated process struct */ -+ uintptr_t ftt_pc; /* address of tracepoint */ -+ pid_t ftt_pid; /* pid of tracepoint */ -+ struct fasttrap_machtp ftt_mtp; /* ISA-specific portion */ -+ struct fasttrap_id *ftt_ids; /* NULL-terminated list */ -+ struct fasttrap_id *ftt_retids; /* NULL-terminated list */ -+ struct fasttrap_tracepoint *ftt_next; /* link in global hash */ -+}; -+ -+struct fasttrap_id_tp { -+ struct fasttrap_id fit_id; -+ struct fasttrap_tracepoint *fit_tp; -+}; -+ -+struct fasttrap_probe { -+ dtrace_id_t ftp_id; /* DTrace probe identifier */ -+ pid_t ftp_pid; /* pid for this probe */ -+ struct fasttrap_provider *ftp_prov; /* this probe's provider */ -+ uint64_t ftp_gen; /* modification generation */ -+ uint64_t ftp_ntps; /* number of tracepoints */ -+ uint8_t *ftp_argmap; /* native to translated args */ -+ uint8_t ftp_nargs; /* translated argument count */ -+ uint8_t ftp_enabled; /* is this probe enabled */ -+ char *ftp_xtypes; /* translated types index */ -+ char *ftp_ntypes; /* native types index */ -+ struct fasttrap_id_tp ftp_tps[1]; /* flexible array */ -+}; -+ -+struct fasttrap_bucket_elem { -+ union { -+ struct fasttrap_bucket { -+ struct mutex ftb_mtx; /* bucket lock */ -+ void *ftb_data; /* data payload */ -+ } bucket; -+ -+ /* -+ * Fill a cacheline, no matter how large struct mutex is. -+ */ -+ uint8_t ftb_pad[(sizeof(struct fasttrap_bucket) + -+ L1_CACHE_BYTES - 1) & ~(L1_CACHE_BYTES - 1)]; -+ }; -+}; -+typedef struct fasttrap_bucket fasttrap_bucket_t; -+ -+#define FASTTRAP_ELEM_BUCKET(elem) ((fasttrap_bucket_t *) (elem)) -+ -+struct fasttrap_hash { -+ ulong_t fth_nent; /* power-of-2 num. of entries */ -+ ulong_t fth_mask; /* fth_nent - 1 */ -+ struct fasttrap_bucket_elem *fth_table; /* array of buckets */ -+}; -+ -+extern struct fasttrap_hash fasttrap_tpoints; -+ -+#define FASTTRAP_ID_INDEX(id) \ -+ ((struct fasttrap_id_tp *)(((char *)(id) - \ -+ offsetof(struct fasttrap_id_tp, fit_id))) - \ -+ &(id)->fti_probe->ftp_tps[0]) -+#define FASTTRAP_TPOINTS_INDEX(pid, pc) \ -+ (((pc) / sizeof(fasttrap_instr_t) + (pid)) & \ -+ fasttrap_tpoints.fth_mask) -+ -+extern uint64_t *fasttrap_glob_offsets(struct fasttrap_probe_spec *probe, -+ uint64_t *np); -+extern uint64_t fasttrap_pid_getarg(void *arg, dtrace_id_t id, void *parg, -+ int argno, int aframes); -+extern uint64_t fasttrap_usdt_getarg(void *arg, dtrace_id_t id, void *parg, -+ int argno, int aframes); -+extern void fasttrap_pid_probe_arch(struct fasttrap_probe *ftp, -+ struct pt_regs *regs); -+extern void fasttrap_pid_retprobe_arch(struct fasttrap_probe *ftp, -+ struct pt_regs *regs); -+extern void fasttrap_set_enabled(struct pt_regs *regs); -+ -+extern void fasttrap_meta_create_probe(void *, void *, -+ struct dtrace_helper_probedesc *); -+extern void *fasttrap_meta_provide(void *, struct dtrace_helper_provdesc *, -+ pid_t); -+extern void fasttrap_meta_remove(void *, struct dtrace_helper_provdesc *, -+ pid_t); -+ -+extern dtrace_meta_provider_id_t fasttrap_id; -+extern struct dtrace_mops fasttrap_mops; -+ -+extern int fasttrap_dev_init(void); -+extern void fasttrap_dev_exit(void); -+ -+#endif /* _FASTTRAP_IMPL_H_ */ -diff --git a/dtrace/fasttrap_mod.c b/dtrace/fasttrap_mod.c -new file mode 100644 -index 0000000000000000000000000000000000000000..e9bd0eb065f1aeea9b771abc05c07838de42d701 ---- /dev/null -+++ b/dtrace/fasttrap_mod.c -@@ -0,0 +1,38 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: fasttrap_mod.c -+ * DESCRIPTION: DTrace - fasttrap provider kernel module -+ * -+ * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/module.h> -+ -+#define DTRACE_HAVE_PROV_EXIT -+ -+#include "dtrace.h" -+#include "dtrace_dev.h" -+#include "fasttrap_impl.h" -+ -+MODULE_AUTHOR("Kris Van Hees (kris.van.hees@oracle.com)"); -+MODULE_DESCRIPTION("Fasttrap Tracing"); -+MODULE_VERSION("v0.1"); -+MODULE_LICENSE("GPL"); -+ -+struct dtrace_mops fasttrap_mops = { -+ fasttrap_meta_create_probe, -+ fasttrap_meta_provide, -+ fasttrap_meta_remove -+}; -+ -+DT_META_PROVIDER_MODULE(fasttrap) --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/dtrace-patches/0014-dtrace-function-boundary-tracing-FBT-core-and-x86-co.patch b/sys-kernel/cairn-sources/files/5.10.14/dtrace-patches/0014-dtrace-function-boundary-tracing-FBT-core-and-x86-co.patch deleted file mode 100644 index 0be10e63a35c..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/dtrace-patches/0014-dtrace-function-boundary-tracing-FBT-core-and-x86-co.patch +++ /dev/null @@ -1,1799 +0,0 @@ -From bc81b22d39f0332275cd6834fdffb749368e62a0 Mon Sep 17 00:00:00 2001 -From: Kris Van Hees <kris.van.hees@oracle.com> -Date: Mon, 19 Nov 2018 19:02:39 +0000 -Subject: [PATCH 14/19] dtrace: function boundary tracing (FBT) core and x86 - components - -This commit implements the core components needed for FBT tracing. -Unlike ftrace we allow the tracing of very large numbers of functions at -once: the intent is that the system should still be stable when every -eligible function in the kernel is traced simultaneously. Functions -that are not safe for this (because e.g. they are used in trap handling, -or by functions called by the DTrace module itself during probe -processing) are (semi-manually) blacklisted from being probed. - -As part of this, a treewide change to the prototype of traps is started: -they all return 0 by default now, with a nonzero return value indicating -that the trap happened as a result of an FBT probe: the return value is -the opcode atop which the trap was originally placed for later emulation. - -Signed-off-by: Kris Van Hees <kris.van.hees@oracle.com> -Signed-off-by: Tomas Jedlicka <tomas.jedlicka@oracle.com> -Signed-off-by: Nick Alcock <nick.alcock@oracle.com> -Signed-off-by: Eugene Loh <eugene.loh@oracle.com> -Signed-off-by: David Mc Lean <david.mclean@oracle.com> -Signed-off-by: Vincent Lim <vincent.lim@oracle.com> ---- - arch/x86/entry/entry_64.S | 134 ++++++++++++++++++- - arch/x86/hyperv/hv_init.c | 1 + - arch/x86/include/asm/idtentry.h | 86 +++++++------ - arch/x86/include/asm/irq_stack.h | 36 +++--- - arch/x86/kernel/apic/apic.c | 4 + - arch/x86/kernel/apic/vector.c | 1 + - arch/x86/kernel/cpu/acrn.c | 1 + - arch/x86/kernel/cpu/mce/amd.c | 1 + - arch/x86/kernel/cpu/mce/core.c | 3 + - arch/x86/kernel/cpu/mce/therm_throt.c | 1 + - arch/x86/kernel/cpu/mce/threshold.c | 1 + - arch/x86/kernel/cpu/mshyperv.c | 2 + - arch/x86/kernel/dtrace_fbt.c | 177 ++++++++++++++++++++++++++ - arch/x86/kernel/fbt_blacklist.h | 95 ++++++++++++++ - arch/x86/kernel/irq.c | 5 + - arch/x86/kernel/irq_work.c | 1 + - arch/x86/kernel/kvm.c | 1 + - arch/x86/kernel/nmi.c | 5 +- - arch/x86/kernel/sev-es.c | 6 +- - arch/x86/kernel/smp.c | 4 + - arch/x86/kernel/traps.c | 91 ++++++++----- - arch/x86/mm/fault.c | 3 +- - arch/x86/xen/enlighten_hvm.c | 1 + - arch/x86/xen/enlighten_pv.c | 8 +- - include/linux/dtrace_fbt.h | 48 +++++++ - kernel/dtrace/Kconfig | 7 + - kernel/dtrace/Makefile | 4 +- - kernel/dtrace/dtrace_fbt_core.c | 125 ++++++++++++++++++ - kernel/dtrace/dtrace_os.c | 2 + - kernel/kprobes.c | 8 ++ - 30 files changed, 764 insertions(+), 98 deletions(-) - create mode 100644 arch/x86/kernel/dtrace_fbt.c - create mode 100644 arch/x86/kernel/fbt_blacklist.h - create mode 100644 include/linux/dtrace_fbt.h - create mode 100644 kernel/dtrace/dtrace_fbt_core.c - -diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S -index cad08703c4ad774f2e473f0dcc71b53cdb579a68..689b45e5b0c4f6c28c9b141d51a8921239b0810f 100644 ---- a/arch/x86/entry/entry_64.S -+++ b/arch/x86/entry/entry_64.S -@@ -38,7 +38,7 @@ - #include <asm/frame.h> - #include <asm/trapnr.h> - #include <asm/nospec-branch.h> --#include <asm/fsgsbase.h> -+#include <asm/dtrace_util.h> - #include <linux/err.h> - - #include "calling.h" -@@ -335,6 +335,15 @@ SYM_CODE_END(ret_from_fork) - - call \cfunc - -+#ifdef CONFIG_DTRACE -+ /* -+ * Nonzero exit from a trap handler means we want to emulate -+ * an instruction. -+ */ -+ test %rax,%rax -+ jnz dtrace_error_return -+#endif -+ - jmp error_return - .endm - -@@ -1097,6 +1106,129 @@ SYM_CODE_START_LOCAL(error_return) - jmp swapgs_restore_regs_and_return_to_usermode - SYM_CODE_END(error_return) - -+#ifdef CONFIG_DTRACE -+/* -+ * Emulate an instruction (given by one of the DTRACE_INVOP constants) on exit -+ * from a trap handler. -+ */ -+SYM_CODE_START_LOCAL(dtrace_error_return) -+ UNWIND_HINT_REGS -+ -+ negq %rax -+ -+ cmpl $DTRACE_INVOP_MOV_RSP_RBP,%eax -+ je dtrace_emu_mov -+ cmpl $DTRACE_INVOP_PUSH_BP,%eax -+ je dtrace_emu_push -+ cmpl $DTRACE_INVOP_LEAVE,%eax -+ je dtrace_emu_leave -+ cmpl $DTRACE_INVOP_NOP,%eax -+ je dtrace_emu_nop -+ cmpl $DTRACE_INVOP_RET,%eax -+ je dtrace_emu_ret -+ -+ leaq dtrace_error_msg(%rip),%rdi -+ movq %rax,%rsi -+ movq (%rsp),%rdx -+ call printk -+ -+ jmp error_return -+ -+dtrace_emu_mov: -+ POP_REGS -+ addq $8, %rsp /* skip regs->orig_ax */ -+ -+ /* Emulate "mov %rsp, %rbp" instruction. */ -+ pushq %rax /* push temp */ -+ movq 8(%rsp),%rax /* load calling RIP */ -+ addq $3,%rax /* increment over trapping instr */ -+ movq %rax,8(%rsp) /* store calling RIP */ -+ movq 32(%rsp),%rbp /* load %rsp into %rbp */ -+ popq %rax /* pop off temp */ -+ -+ INTERRUPT_RETURN -+ -+dtrace_emu_push: -+ POP_REGS -+ addq $8, %rsp /* skip regs->orig_ax */ -+ -+ /* -+ * Emulate a "pushq %rbp" instruction. We need to move the stack down -+ * to make room for the extra address getting pushed. -+ */ -+ subq $16,%rsp /* make room for %rbp */ -+ pushq %rax /* push temp */ -+ movq 24(%rsp),%rax /* load calling RIP */ -+ addq $1,%rax /* increment over trapping instr */ -+ movq %rax,8(%rsp) /* store calling RIP */ -+ movq 32(%rsp),%rax /* load calling CS */ -+ movq %rax,16(%rsp) /* store calling CS */ -+ movq 40(%rsp),%rax /* load calling RFLAGS */ -+ movq %rax,24(%rsp) /* store calling RFLAGS */ -+ movq 48(%rsp),%rax /* load calling RSP */ -+ subq $8,%rax /* make room for %rbp */ -+ movq %rax,32(%rsp) /* store calling RSP */ -+ movq 56(%rsp),%rax /* load calling SS */ -+ movq %rax,40(%rsp) /* store calling SS */ -+ movq 32(%rsp),%rax /* reload calling RSP */ -+ movq %rbp,(%rax) /* store %rbp there */ -+ popq %rax /* pop off temp */ -+ -+ INTERRUPT_RETURN -+ -+dtrace_emu_nop: -+ POP_REGS -+ addq $8, %rsp /* skip regs->orig_ax */ -+ -+ /* Emulate a "nop" instruction. */ -+ incq (%rsp) -+ -+ INTERRUPT_RETURN -+ -+dtrace_emu_leave: -+ POP_REGS -+ addq $8, %rsp /* skip regs->orig_ax */ -+ -+ /* -+ * Emulate a "leave" instruction. This is equivalent to the sequence: -+ * movq %rbp,%rsp -+ * popq %rbp -+ * We can use the fact that on x86_64 %rsp is saved explicitly, so we -+ * do not need to move any data around. -+ */ -+ pushq %rax /* push temp */ -+ movq 8(%rsp),%rax /* load calling RIP */ -+ addq $1,%rax /* increment over trapping instr */ -+ movq %rax,8(%rsp) /* store calling RIP */ -+ movq (%rbp),%rax /* get new %rbp */ -+ addq $8,%rbp /* adjust new %rsp */ -+ movq %rbp,32(%rsp) /* store new %rsp */ -+ movq %rax,%rbp /* set new %rbp */ -+ popq %rax /* pop off temp */ -+ -+ INTERRUPT_RETURN -+ -+dtrace_emu_ret: -+ POP_REGS -+ addq $8, %rsp /* skip regs->orig_ax */ -+ -+ /* Emulate a "ret" instruction. */ -+ pushq %rax /* push temp */ -+ movq 32(%rsp),%rax /* load %rsp */ -+ movq (%rax),%rax /* load calling RIP */ -+ movq %rax,8(%rsp) /* store calling RIP */ -+ addq $8,32(%rsp) /* adjust new %rsp */ -+ popq %rax /* pop off temp */ -+ -+ INTERRUPT_RETURN -+SYM_CODE_END(dtrace_error_return) -+ -+.pushsection .rodata, "a" -+dtrace_error_msg: -+ .asciz "DTRACE: non-zero (%x) return from trap at %x\n" -+.popsection -+#endif -+ - /* - * Runs on exception stack. Xen PV does not go through this path at all, - * so we can use real assembly here. -diff --git a/arch/x86/hyperv/hv_init.c b/arch/x86/hyperv/hv_init.c -index 6375967a8244dc4e6777d8ff95de1be33ea77e06..e22347681c03b49c07eaf0b7a55cfb9b3d1e709b 100644 ---- a/arch/x86/hyperv/hv_init.c -+++ b/arch/x86/hyperv/hv_init.c -@@ -161,6 +161,7 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_hyperv_reenlightenment) - ack_APIC_irq(); - inc_irq_stat(irq_hv_reenlightenment_count); - schedule_delayed_work(&hv_reenlightenment_work, HZ/10); -+ return 0; - } - - void set_hv_tscchange_cb(void (*cb)(void)) -diff --git a/arch/x86/include/asm/idtentry.h b/arch/x86/include/asm/idtentry.h -index b2442eb0ac2f8010bdae488a715be6e67d012b0e..2222870fb7ab975d17e1085ba3e8d27e803b38fd 100644 ---- a/arch/x86/include/asm/idtentry.h -+++ b/arch/x86/include/asm/idtentry.h -@@ -32,7 +32,7 @@ void idtentry_exit_nmi(struct pt_regs *regs, bool irq_state); - #define DECLARE_IDTENTRY(vector, func) \ - asmlinkage void asm_##func(void); \ - asmlinkage void xen_asm_##func(void); \ -- __visible void func(struct pt_regs *regs) -+ __visible int func(struct pt_regs *regs) - - /** - * DEFINE_IDTENTRY - Emit code for simple IDT entry points -@@ -48,19 +48,21 @@ void idtentry_exit_nmi(struct pt_regs *regs, bool irq_state); - * which has to run before returning to the low level assembly code. - */ - #define DEFINE_IDTENTRY(func) \ --static __always_inline void __##func(struct pt_regs *regs); \ -+static __always_inline int __##func(struct pt_regs *regs); \ - \ --__visible noinstr void func(struct pt_regs *regs) \ -+__visible noinstr int func(struct pt_regs *regs) \ - { \ - irqentry_state_t state = irqentry_enter(regs); \ -+ int ret; \ - \ - instrumentation_begin(); \ -- __##func (regs); \ -+ ret = __##func (regs); \ - instrumentation_end(); \ - irqentry_exit(regs, state); \ -+ return ret; \ - } \ - \ --static __always_inline void __##func(struct pt_regs *regs) -+static __always_inline int __##func(struct pt_regs *regs) - - /* Special case for 32bit IRET 'trap' */ - #define DECLARE_IDTENTRY_SW DECLARE_IDTENTRY -@@ -83,7 +85,7 @@ static __always_inline void __##func(struct pt_regs *regs) - #define DECLARE_IDTENTRY_ERRORCODE(vector, func) \ - asmlinkage void asm_##func(void); \ - asmlinkage void xen_asm_##func(void); \ -- __visible void func(struct pt_regs *regs, unsigned long error_code) -+ __visible int func(struct pt_regs *regs, unsigned long error_code) - - /** - * DEFINE_IDTENTRY_ERRORCODE - Emit code for simple IDT entry points -@@ -93,22 +95,24 @@ static __always_inline void __##func(struct pt_regs *regs) - * Same as DEFINE_IDTENTRY, but has an extra error_code argument - */ - #define DEFINE_IDTENTRY_ERRORCODE(func) \ --static __always_inline void __##func(struct pt_regs *regs, \ -- unsigned long error_code); \ -+static __always_inline int __##func(struct pt_regs *regs, \ -+ unsigned long error_code); \ - \ --__visible noinstr void func(struct pt_regs *regs, \ -- unsigned long error_code) \ -+__visible noinstr int func(struct pt_regs *regs, \ -+ unsigned long error_code) \ - { \ - irqentry_state_t state = irqentry_enter(regs); \ -+ int ret; \ - \ - instrumentation_begin(); \ -- __##func (regs, error_code); \ -+ ret = __##func (regs, error_code); \ - instrumentation_end(); \ - irqentry_exit(regs, state); \ -+ return ret; \ - } \ - \ --static __always_inline void __##func(struct pt_regs *regs, \ -- unsigned long error_code) -+static __always_inline int __##func(struct pt_regs *regs, \ -+ unsigned long error_code) - - /** - * DECLARE_IDTENTRY_RAW - Declare functions for raw IDT entry points -@@ -136,7 +140,7 @@ static __always_inline void __##func(struct pt_regs *regs, \ - * is required before the enter/exit() helpers are invoked. - */ - #define DEFINE_IDTENTRY_RAW(func) \ --__visible noinstr void func(struct pt_regs *regs) -+__visible noinstr int func(struct pt_regs *regs) - - /** - * DECLARE_IDTENTRY_RAW_ERRORCODE - Declare functions for raw IDT entry points -@@ -164,7 +168,7 @@ __visible noinstr void func(struct pt_regs *regs) - * is required before the enter/exit() helpers are invoked. - */ - #define DEFINE_IDTENTRY_RAW_ERRORCODE(func) \ --__visible noinstr void func(struct pt_regs *regs, unsigned long error_code) -+__visible noinstr int func(struct pt_regs *regs, unsigned long error_code) - - /** - * DECLARE_IDTENTRY_IRQ - Declare functions for device interrupt IDT entry -@@ -190,23 +194,25 @@ __visible noinstr void func(struct pt_regs *regs, unsigned long error_code) - * has to be done in the function body if necessary. - */ - #define DEFINE_IDTENTRY_IRQ(func) \ --static __always_inline void __##func(struct pt_regs *regs, u8 vector); \ -+static __always_inline int __##func(struct pt_regs *regs, u8 vector); \ - \ --__visible noinstr void func(struct pt_regs *regs, \ -- unsigned long error_code) \ -+__visible noinstr int func(struct pt_regs *regs, \ -+ unsigned long error_code) \ - { \ - irqentry_state_t state = irqentry_enter(regs); \ -+ int ret; \ - \ - instrumentation_begin(); \ - irq_enter_rcu(); \ - kvm_set_cpu_l1tf_flush_l1d(); \ -- __##func (regs, (u8)error_code); \ -+ ret = __##func (regs, (u8)error_code); \ - irq_exit_rcu(); \ - instrumentation_end(); \ - irqentry_exit(regs, state); \ -+ return ret; \ - } \ - \ --static __always_inline void __##func(struct pt_regs *regs, u8 vector) -+static __always_inline int __##func(struct pt_regs *regs, u8 vector) - - /** - * DECLARE_IDTENTRY_SYSVEC - Declare functions for system vector entry points -@@ -233,22 +239,24 @@ static __always_inline void __##func(struct pt_regs *regs, u8 vector) - * Runs the function on the interrupt stack if the entry hit kernel mode - */ - #define DEFINE_IDTENTRY_SYSVEC(func) \ --static void __##func(struct pt_regs *regs); \ -+static int __##func(struct pt_regs *regs); \ - \ --__visible noinstr void func(struct pt_regs *regs) \ -+__visible noinstr int func(struct pt_regs *regs) \ - { \ - irqentry_state_t state = irqentry_enter(regs); \ -+ int ret; \ - \ - instrumentation_begin(); \ - irq_enter_rcu(); \ - kvm_set_cpu_l1tf_flush_l1d(); \ -- run_sysvec_on_irqstack_cond(__##func, regs); \ -+ ret = run_sysvec_on_irqstack_cond(__##func, regs); \ - irq_exit_rcu(); \ - instrumentation_end(); \ - irqentry_exit(regs, state); \ -+ return ret; \ - } \ - \ --static noinline void __##func(struct pt_regs *regs) -+static noinline int __##func(struct pt_regs *regs) - - /** - * DEFINE_IDTENTRY_SYSVEC_SIMPLE - Emit code for simple system vector IDT -@@ -262,22 +270,24 @@ static noinline void __##func(struct pt_regs *regs) - * interrupt vectors. - */ - #define DEFINE_IDTENTRY_SYSVEC_SIMPLE(func) \ --static __always_inline void __##func(struct pt_regs *regs); \ -+static __always_inline int __##func(struct pt_regs *regs); \ - \ --__visible noinstr void func(struct pt_regs *regs) \ -+__visible noinstr int func(struct pt_regs *regs) \ - { \ - irqentry_state_t state = irqentry_enter(regs); \ -+ int ret; \ - \ - instrumentation_begin(); \ - __irq_enter_raw(); \ - kvm_set_cpu_l1tf_flush_l1d(); \ -- __##func (regs); \ -+ ret = __##func (regs); \ - __irq_exit_raw(); \ - instrumentation_end(); \ - irqentry_exit(regs, state); \ -+ return ret; \ - } \ - \ --static __always_inline void __##func(struct pt_regs *regs) -+static __always_inline int __##func(struct pt_regs *regs) - - /** - * DECLARE_IDTENTRY_XENCB - Declare functions for XEN HV callback entry point -@@ -306,7 +316,7 @@ static __always_inline void __##func(struct pt_regs *regs) - */ - #define DECLARE_IDTENTRY_IST(vector, func) \ - DECLARE_IDTENTRY_RAW(vector, func); \ -- __visible void noist_##func(struct pt_regs *regs) -+ __visible int noist_##func(struct pt_regs *regs) - - /** - * DECLARE_IDTENTRY_VC - Declare functions for the VC entry point -@@ -318,8 +328,8 @@ static __always_inline void __##func(struct pt_regs *regs) - */ - #define DECLARE_IDTENTRY_VC(vector, func) \ - DECLARE_IDTENTRY_RAW_ERRORCODE(vector, func); \ -- __visible noinstr void ist_##func(struct pt_regs *regs, unsigned long error_code); \ -- __visible noinstr void safe_stack_##func(struct pt_regs *regs, unsigned long error_code) -+ __visible noinstr int ist_##func(struct pt_regs *regs, unsigned long error_code); \ -+ __visible noinstr int safe_stack_##func(struct pt_regs *regs, unsigned long error_code) - - /** - * DEFINE_IDTENTRY_IST - Emit code for IST entry points -@@ -401,10 +411,10 @@ static __always_inline void __##func(struct pt_regs *regs) - * - The C handler called from the C shim - */ - #define DECLARE_IDTENTRY_DF(vector, func) \ -- asmlinkage void asm_##func(void); \ -- __visible void func(struct pt_regs *regs, \ -- unsigned long error_code, \ -- unsigned long address) -+ asmlinkage int asm_##func(void); \ -+ __visible int func(struct pt_regs *regs, \ -+ unsigned long error_code, \ -+ unsigned long address) - - /** - * DEFINE_IDTENTRY_DF - Emit code for double fault on 32bit -@@ -414,9 +424,9 @@ static __always_inline void __##func(struct pt_regs *regs) - * cr2 in the address argument. - */ - #define DEFINE_IDTENTRY_DF(func) \ --__visible noinstr void func(struct pt_regs *regs, \ -- unsigned long error_code, \ -- unsigned long address) -+__visible noinstr int func(struct pt_regs *regs, \ -+ unsigned long error_code, \ -+ unsigned long address) - - #endif /* !CONFIG_X86_64 */ - -diff --git a/arch/x86/include/asm/irq_stack.h b/arch/x86/include/asm/irq_stack.h -index 775816965c6ae098f249dcf83c61d131da0ced9a..04f91986cee35b4ec140ce12ab24a2141024b0f7 100644 ---- a/arch/x86/include/asm/irq_stack.h -+++ b/arch/x86/include/asm/irq_stack.h -@@ -12,11 +12,11 @@ static __always_inline bool irqstack_active(void) - return __this_cpu_read(irq_count) != -1; - } - --void asm_call_on_stack(void *sp, void (*func)(void), void *arg); --void asm_call_sysvec_on_stack(void *sp, void (*func)(struct pt_regs *regs), -- struct pt_regs *regs); --void asm_call_irq_on_stack(void *sp, void (*func)(struct irq_desc *desc), -- struct irq_desc *desc); -+int asm_call_on_stack(void *sp, void (*func)(void), void *arg); -+int asm_call_sysvec_on_stack(void *sp, int (*func)(struct pt_regs *regs), -+ struct pt_regs *regs); -+int asm_call_irq_on_stack(void *sp, void (*func)(struct irq_desc *desc), -+ struct irq_desc *desc); - - static __always_inline void __run_on_irqstack(void (*func)(void)) - { -@@ -27,15 +27,17 @@ static __always_inline void __run_on_irqstack(void (*func)(void)) - __this_cpu_sub(irq_count, 1); - } - --static __always_inline void --__run_sysvec_on_irqstack(void (*func)(struct pt_regs *regs), -+static __always_inline int -+__run_sysvec_on_irqstack(int (*func)(struct pt_regs *regs), - struct pt_regs *regs) - { - void *tos = __this_cpu_read(hardirq_stack_ptr); -+ int ret; - - __this_cpu_add(irq_count, 1); -- asm_call_sysvec_on_stack(tos - 8, func, regs); -+ ret = asm_call_sysvec_on_stack(tos - 8, func, regs); - __this_cpu_sub(irq_count, 1); -+ return ret; - } - - static __always_inline void -@@ -51,11 +53,11 @@ __run_irq_on_irqstack(void (*func)(struct irq_desc *desc), - - #else /* CONFIG_X86_64 */ - static inline bool irqstack_active(void) { return false; } --static inline void __run_on_irqstack(void (*func)(void)) { } --static inline void __run_sysvec_on_irqstack(void (*func)(struct pt_regs *regs), -- struct pt_regs *regs) { } --static inline void __run_irq_on_irqstack(void (*func)(struct irq_desc *desc), -- struct irq_desc *desc) { } -+static inline int __run_on_irqstack(int (*func)(void)) { } -+static inline int __run_sysvec_on_irqstack(int (*func)(struct pt_regs *regs), -+ struct pt_regs *regs) { } -+static inline int __run_irq_on_irqstack(int (*func)(struct irq_desc *desc), -+ struct irq_desc *desc) { } - #endif /* !CONFIG_X86_64 */ - - static __always_inline bool irq_needs_irq_stack(struct pt_regs *regs) -@@ -79,16 +81,16 @@ static __always_inline void run_on_irqstack_cond(void (*func)(void), - func(); - } - --static __always_inline void --run_sysvec_on_irqstack_cond(void (*func)(struct pt_regs *regs), -+static __always_inline int -+run_sysvec_on_irqstack_cond(int (*func)(struct pt_regs *regs), - struct pt_regs *regs) - { - lockdep_assert_irqs_disabled(); - - if (irq_needs_irq_stack(regs)) -- __run_sysvec_on_irqstack(func, regs); -+ return __run_sysvec_on_irqstack(func, regs); - else -- func(regs); -+ return func(regs); - } - - static __always_inline void -diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c -index 113f6ca7b82849fd18271f3661b78b479accc2e6..06bd0bf3ae5a49a53fdc80ca52c762d95b8434ff 100644 ---- a/arch/x86/kernel/apic/apic.c -+++ b/arch/x86/kernel/apic/apic.c -@@ -1098,6 +1098,7 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_apic_timer_interrupt) - trace_local_timer_exit(LOCAL_TIMER_VECTOR); - - set_irq_regs(old_regs); -+ return 0; - } - - int setup_profiling_timer(unsigned int multiplier) -@@ -2160,11 +2161,13 @@ DEFINE_IDTENTRY_IRQ(spurious_interrupt) - } - out: - trace_spurious_apic_exit(vector); -+ return 0; - } - - DEFINE_IDTENTRY_SYSVEC(sysvec_spurious_apic_interrupt) - { - __spurious_interrupt(regs, SPURIOUS_APIC_VECTOR); -+ return 0; - } - - /* -@@ -2207,6 +2210,7 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_error_interrupt) - apic_printk(APIC_DEBUG, KERN_CONT "\n"); - - trace_error_apic_exit(ERROR_APIC_VECTOR); -+ return 0; - } - - /** -diff --git a/arch/x86/kernel/apic/vector.c b/arch/x86/kernel/apic/vector.c -index 758bbf25ef748f2d4560eb146af6be2bc65831e1..a841e833f2672f1575f03fa603d684a23f6ede1f 100644 ---- a/arch/x86/kernel/apic/vector.c -+++ b/arch/x86/kernel/apic/vector.c -@@ -887,6 +887,7 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_irq_move_cleanup) - } - - raw_spin_unlock(&vector_lock); -+ return 0; - } - - static void __send_cleanup_vector(struct apic_chip_data *apicd) -diff --git a/arch/x86/kernel/cpu/acrn.c b/arch/x86/kernel/cpu/acrn.c -index 0b2c03943ac6b31fea3d742e5db5b379f70018c7..b17c61c16e993886527b6dc60d967daec62dd377 100644 ---- a/arch/x86/kernel/cpu/acrn.c -+++ b/arch/x86/kernel/cpu/acrn.c -@@ -53,6 +53,7 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_acrn_hv_callback) - acrn_intr_handler(); - - set_irq_regs(old_regs); -+ return 0; - } - - const __initconst struct hypervisor_x86 x86_hyper_acrn = { -diff --git a/arch/x86/kernel/cpu/mce/amd.c b/arch/x86/kernel/cpu/mce/amd.c -index 0c6b02dd744c1424c3235035aab439d2f1d0d1b8..8126b080d4888e1e0125c0d3af35ace8e6f5635a 100644 ---- a/arch/x86/kernel/cpu/mce/amd.c -+++ b/arch/x86/kernel/cpu/mce/amd.c -@@ -928,6 +928,7 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_deferred_error) - deferred_error_int_vector(); - trace_deferred_error_apic_exit(DEFERRED_ERROR_VECTOR); - ack_APIC_irq(); -+ return 0; - } - - /* -diff --git a/arch/x86/kernel/cpu/mce/core.c b/arch/x86/kernel/cpu/mce/core.c -index 311688202ea51b5104a8c9391503c6db2f9a5a9a..e94cf10e05f7012142b0e8d10ca22a4ecfa98bc6 100644 ---- a/arch/x86/kernel/cpu/mce/core.c -+++ b/arch/x86/kernel/cpu/mce/core.c -@@ -2030,6 +2030,7 @@ DEFINE_IDTENTRY_MCE(exc_machine_check) - dr7 = local_db_save(); - exc_machine_check_kernel(regs); - local_db_restore(dr7); -+ return 0; - } - - /* The user mode variant. */ -@@ -2040,6 +2041,7 @@ DEFINE_IDTENTRY_MCE_USER(exc_machine_check) - dr7 = local_db_save(); - exc_machine_check_user(regs); - local_db_restore(dr7); -+ return 0; - } - #else - /* 32bit unified entry point */ -@@ -2053,6 +2055,7 @@ DEFINE_IDTENTRY_RAW(exc_machine_check) - else - exc_machine_check_kernel(regs); - local_db_restore(dr7); -+ return 0; - } - #endif - -diff --git a/arch/x86/kernel/cpu/mce/therm_throt.c b/arch/x86/kernel/cpu/mce/therm_throt.c -index a7cd2d203ceda64ebd711be273b97249921f1edf..8e86a3baf32e9bf9d4ebd84ade9cb8da2c24816e 100644 ---- a/arch/x86/kernel/cpu/mce/therm_throt.c -+++ b/arch/x86/kernel/cpu/mce/therm_throt.c -@@ -621,6 +621,7 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_thermal) - smp_thermal_vector(); - trace_thermal_apic_exit(THERMAL_APIC_VECTOR); - ack_APIC_irq(); -+ return 0; - } - - /* Thermal monitoring depends on APIC, ACPI and clock modulation */ -diff --git a/arch/x86/kernel/cpu/mce/threshold.c b/arch/x86/kernel/cpu/mce/threshold.c -index 6a059a035021d87a1e0dcd342663a365ed7a2ad3..fa361a5b297ac8f04a0811935268aa2fea1a91e3 100644 ---- a/arch/x86/kernel/cpu/mce/threshold.c -+++ b/arch/x86/kernel/cpu/mce/threshold.c -@@ -28,4 +28,5 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_threshold) - mce_threshold_vector(); - trace_threshold_apic_exit(THRESHOLD_APIC_VECTOR); - ack_APIC_irq(); -+ return 0; - } -diff --git a/arch/x86/kernel/cpu/mshyperv.c b/arch/x86/kernel/cpu/mshyperv.c -index 6cc50ab07bded72e50ff6900d5f150ac37eea6da..5146b1f713e0b39ae7635ec6a617cdaac3f4027d 100644 ---- a/arch/x86/kernel/cpu/mshyperv.c -+++ b/arch/x86/kernel/cpu/mshyperv.c -@@ -53,6 +53,7 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_hyperv_callback) - ack_APIC_irq(); - - set_irq_regs(old_regs); -+ return 0; - } - - int hv_setup_vmbus_irq(int irq, void (*handler)(void)) -@@ -88,6 +89,7 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_hyperv_stimer0) - ack_APIC_irq(); - - set_irq_regs(old_regs); -+ return 0; - } - - int hv_setup_stimer0_irq(int *irq, int *vector, void (*handler)(void)) -diff --git a/arch/x86/kernel/dtrace_fbt.c b/arch/x86/kernel/dtrace_fbt.c -new file mode 100644 -index 0000000000000000000000000000000000000000..52ff3f49d101cdcfc0bf58acbfd3e121f914ca8f ---- /dev/null -+++ b/arch/x86/kernel/dtrace_fbt.c -@@ -0,0 +1,177 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_fbt.c -+ * DESCRIPTION: Dynamic Tracing: FBT registration code (arch-specific) -+ * -+ * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/kallsyms.h> -+#include <linux/dtrace_os.h> -+#include <linux/dtrace_fbt.h> -+#include <linux/slab.h> -+#include <linux/sort.h> -+#include <asm/insn.h> -+#include <asm/sections.h> -+ -+#define FBT_MOV_RSP_RBP_1 0x48 -+#define FBT_MOV_RSP_RBP_2 0x89 -+#define FBT_MOV_RSP_RBP_3 0xe5 -+#define FBT_PUSHL_EBP 0x55 -+#define FBT_NOP 0x90 -+#define FBT_RET_IMM16 0xc2 -+#define FBT_RET 0xc3 -+#define FBT_LEAVE 0xc9 -+ -+#define BL_SENTRY(tp, nm) extern tp nm; -+#define BL_DENTRY(tp, nm) -+#include "fbt_blacklist.h" -+#undef BL_DENTRY -+#undef BL_SENTRY -+ -+static void -+dtrace_fbt_populate_bl(void) -+{ -+#define BL_SENTRY(tp, nm) dtrace_fbt_bl_add((unsigned long)&nm, \ -+ __stringify(nm)); -+#define BL_DENTRY(tp, nm) dtrace_fbt_bl_add(0, __stringify(nm)); -+#include "fbt_blacklist.h" -+#undef BL_SENTRY -+#undef BL_DENTRY -+} -+ -+void dtrace_fbt_init(fbt_add_probe_fn fbt_add_probe, struct module *mp, -+ void *arg) -+{ -+ loff_t pos; -+ struct kallsym_iter sym; -+ asm_instr_t *paddr = NULL; -+ struct dt_fbt_bl_entry *blent = NULL; -+ -+ /* -+ * Look up any unresolved symbols in the blacklist, and sort the list -+ * by ascending address. -+ */ -+ dtrace_fbt_populate_bl(); -+ blent = dtrace_fbt_bl_first(); -+ -+ pos = 0; -+ kallsyms_iter_reset(&sym, 0); -+ while (kallsyms_iter_update(&sym, pos++)) { -+ asm_instr_t *addr, *end; -+ int state = 0, insc = 0; -+ void *fbtp = NULL; -+ -+ /* -+ * There is no point considering non-function symbols for FBT, -+ * or symbols that have a zero size. We could consider weak -+ * symbols but that gets quite complicated and there is no -+ * demands for that (so far). -+ */ -+ if (sym.type != 'T' && sym.type != 't') -+ continue; -+ if (!sym.size) -+ continue; -+ -+ /* -+ * Handle only symbols that belong to the module we have been -+ * asked for. -+ */ -+ if (mp == dtrace_kmod && !core_kernel_text(sym.value)) -+ continue; -+ -+ /* -+ * Ensure we have not been given .init symbol from kallsyms -+ * interface. This could lead to memory corruption once DTrace -+ * tries to enable probe in already freed memory. -+ */ -+ if (mp != dtrace_kmod && !within_module_core(sym.value, mp)) -+ continue; -+ -+ /* -+ * See if the symbol is on the FBT's blacklist. Since both -+ * iterators are workng in sort order by ascending address we -+ * can use concurrent traversal. -+ */ -+ while (blent != NULL && -+ dtrace_fbt_bl_entry_addr(blent) < sym.value) { -+ blent = dtrace_fbt_bl_next(blent); -+ } -+ if (dtrace_fbt_bl_entry_addr(blent) == sym.value) -+ continue; -+ -+ /* -+ * No FBT tracing for DTrace functions, and functions that are -+ * crucial to probe processing. -+ * Also weed out symbols that are not relevant here. -+ */ -+ if (strncmp(sym.name, "dtrace_", 7) == 0) -+ continue; -+ if (strncmp(sym.name, "insn_", 5) == 0) -+ continue; -+ if (strncmp(sym.name, "inat_", 5) == 0) -+ continue; -+ if (strncmp(sym.name, "_GLOBAL_", 8) == 0) -+ continue; -+ if (strncmp(sym.name, "do_", 3) == 0) -+ continue; -+ if (strncmp(sym.name, "xen_", 4) == 0) -+ continue; -+ -+ addr = (asm_instr_t *)sym.value; -+ end = (asm_instr_t *)(sym.value + sym.size); -+ -+ /* -+ * FIXME: -+ * When there are multiple symbols for the same address, we -+ * should link them together as probes associated with the -+ * same function. When a probe for that function is triggered -+ * all associated probes should fire. -+ * -+ * For now, we ignore duplicates. -+ */ -+ if (addr == paddr) -+ continue; -+ paddr = addr; -+ -+ while (addr < end) { -+ struct insn insn; -+ -+ insc++; -+ -+ switch (state) { -+ case 0: /* start of function */ -+ if (*addr == FBT_PUSHL_EBP) { -+ fbt_add_probe( -+ mp, sym.name, -+ FBT_ENTRY, *addr, addr, 0, -+ NULL, arg); -+ state = 1; -+ } else if (insc > 10) -+ state = 2; -+ break; -+ case 1: /* look for ret */ -+ if (*addr == FBT_RET) { -+ uintptr_t off; -+ -+ off = addr - (asm_instr_t *)sym.value; -+ fbtp = fbt_add_probe( -+ mp, sym.name, -+ FBT_RETURN, *addr, addr, off, -+ fbtp, arg); -+ } -+ break; -+ } -+ -+ if (state == 2) -+ break; -+ -+ kernel_insn_init(&insn, addr, MAX_INSN_SIZE); -+ insn_get_length(&insn); -+ -+ addr += insn.length; -+ } -+ } -+} -+EXPORT_SYMBOL(dtrace_fbt_init); -diff --git a/arch/x86/kernel/fbt_blacklist.h b/arch/x86/kernel/fbt_blacklist.h -new file mode 100644 -index 0000000000000000000000000000000000000000..2e1ce2a90c86ca041e89ab83fcf51dfd77e433f6 ---- /dev/null -+++ b/arch/x86/kernel/fbt_blacklist.h -@@ -0,0 +1,95 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Functions used in die notifier chain calling. -+ */ -+BL_SENTRY(void *, notify_die) -+BL_DENTRY(void *, notifier_call_chain) -+BL_SENTRY(typeof(atomic_notifier_call_chain_robust), atomic_notifier_call_chain_robust) -+BL_SENTRY(typeof(atomic_notifier_call_chain), atomic_notifier_call_chain) -+BL_SENTRY(typeof(raw_notifier_call_chain_robust), raw_notifier_call_chain_robust) -+BL_SENTRY(typeof(raw_notifier_call_chain), raw_notifier_call_chain) -+BL_DENTRY(void *, hw_breakpoint_exceptions_notify) -+BL_DENTRY(void *, kprobe_exceptions_notify) -+ -+/* -+ * Functions used to update vtime in probe context. -+ */ -+BL_SENTRY(typeof(ktime_get_raw_fast_ns), ktime_get_raw_fast_ns) -+BL_DENTRY(void *, raw_read_seqcount) -+BL_DENTRY(void *, read_seqcount_retry) -+BL_DENTRY(void *, __read_seqcount_retry) -+ -+/* xen_clocksource */ -+BL_DENTRY(void *, xen_clocksource_get_cycles) -+BL_DENTRY(void *, xen_clocksource_read) -+BL_DENTRY(void *, pvclock_clocksource_read) -+BL_DENTRY(void *, pvclock_touch_watchdogs) -+BL_DENTRY(void *, touch_softlockup_watchdog_sync) -+BL_DENTRY(void *, clocksource_touch_watchdog) -+BL_DENTRY(void *, clocksource_resume_watchdog) -+BL_DENTRY(void *, reset_hung_task_detector) -+/* clocksource_tsc */ -+BL_DENTRY(void *, read_tsc) -+BL_DENTRY(void *, get_cycles) -+/* clocksource_hpet */ -+BL_DENTRY(void *, read_hpet) -+BL_DENTRY(void *, hpet_readl) -+/* kvm_clock */ -+BL_DENTRY(void *, kvm_clock_get_cycles) -+BL_DENTRY(void *, kvm_clock_read) -+ -+/* -+ * Functions used in trap handling. -+ */ -+BL_DENTRY(void *, fixup_exception) -+BL_DENTRY(void *, paranoid_entry) -+BL_DENTRY(void *, kgdb_ll_trap) -+BL_DENTRY(void *, error_entry) -+BL_DENTRY(void *, xen_int3) -+BL_DENTRY(void *, ftrace_int3_handler) -+BL_DENTRY(typeof(poke_int3_handler), poke_int3_handler) -+BL_DENTRY(void *, fixup_bad_iret) -+BL_DENTRY(void *, xen_adjust_exception_frame) -+BL_DENTRY(void *, paravirt_nop) -+BL_DENTRY(void *, ist_enter) -+BL_DENTRY(void *, rcu_nmi_enter) -+BL_DENTRY(void *, rcu_dynticks_curr_cpu_in_eqs) -+BL_DENTRY(void *, rcu_dynticks_eqs_exit) -+BL_DENTRY(void *, trace_rcu_dyntick) -+BL_DENTRY(void *, rcu_nmi_exit) -+BL_DENTRY(void *, rcu_irq_exit) -+BL_DENTRY(void *, rcu_nmi_exit_common) -+BL_DENTRY(void *, rcu_dynticks_eqs_enter) -+BL_DENTRY(void *, ist_exit) -+ -+/* -+ * Functions used in page fault handling. -+ */ -+BL_DENTRY(void *, do_kern_addr_fault) -+BL_DENTRY(void *, do_kern_addr_fault) -+BL_DENTRY(void *, handle_page_fault) -+BL_DENTRY(void *, huge_page_mask) -+BL_DENTRY(void *, mmap_address_hint_valid) -+BL_DENTRY(void *, vm_start_gap) -+BL_DENTRY(void *, hugetlb_get_unmapped_area_bottomup) -+BL_DENTRY(void *, hugetlb_get_unmapped_area_topdown) -+BL_DENTRY(void *, down_read_trylock) -+BL_DENTRY(void *, __get_user_pages_fast) -+BL_DENTRY(void *, gup_pud_range) -+BL_DENTRY(void *, gup_huge_pud) -+BL_DENTRY(void *, gup_pmd_range) -+BL_DENTRY(void *, gup_huge_pmd) -+BL_DENTRY(void *, gup_pte_range) -+BL_DENTRY(void *, pte_mfn_to_pfn) -+ -+/* -+ * Functions used under 4.12 idr_find -+ */ -+BL_DENTRY(void *, idr_find) -+BL_DENTRY(void *, find_next_bit) -+BL_DENTRY(void *, _find_next_bit) -+BL_DENTRY(void *, radix_tree_lookup) -+BL_DENTRY(void *, __radix_tree_lookup) -+BL_DENTRY(void *, radix_tree_load_root) -+BL_DENTRY(void *, radix_tree_descend) -+BL_DENTRY(void *, is_sibling_entry) -diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c -index c5dd50369e2f3394bc483b8744ace94eaaea552b..b80211006fb2e13b0f8f0dbdab93f9868025e1d3 100644 ---- a/arch/x86/kernel/irq.c -+++ b/arch/x86/kernel/irq.c -@@ -260,6 +260,7 @@ DEFINE_IDTENTRY_IRQ(common_interrupt) - } - - set_irq_regs(old_regs); -+ return 0; - } - - #ifdef CONFIG_X86_LOCAL_APIC -@@ -279,6 +280,7 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_x86_platform_ipi) - x86_platform_ipi_callback(); - trace_x86_platform_ipi_exit(X86_PLATFORM_IPI_VECTOR); - set_irq_regs(old_regs); -+ return 0; - } - #endif - -@@ -302,6 +304,7 @@ DEFINE_IDTENTRY_SYSVEC_SIMPLE(sysvec_kvm_posted_intr_ipi) - { - ack_APIC_irq(); - inc_irq_stat(kvm_posted_intr_ipis); -+ return 0; - } - - /* -@@ -312,6 +315,7 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_kvm_posted_intr_wakeup_ipi) - ack_APIC_irq(); - inc_irq_stat(kvm_posted_intr_wakeup_ipis); - kvm_posted_intr_wakeup_handler(); -+ return 0; - } - - /* -@@ -321,6 +325,7 @@ DEFINE_IDTENTRY_SYSVEC_SIMPLE(sysvec_kvm_posted_intr_nested_ipi) - { - ack_APIC_irq(); - inc_irq_stat(kvm_posted_intr_nested_ipis); -+ return 0; - } - #endif - -diff --git a/arch/x86/kernel/irq_work.c b/arch/x86/kernel/irq_work.c -index 890d4778cd352c69866464001e5ee16f414bf621..ac74998e2faa3a587d46dce272f678a3524fd74e 100644 ---- a/arch/x86/kernel/irq_work.c -+++ b/arch/x86/kernel/irq_work.c -@@ -21,6 +21,7 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_irq_work) - inc_irq_stat(apic_irq_work_irqs); - irq_work_run(); - trace_irq_work_exit(IRQ_WORK_VECTOR); -+ return 0; - } - - void arch_irq_work_raise(void) -diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c -index 7f57ede3cb8e73b3fc3eb0586c1337d7c2658254..07ea0a6336e9e5a668f546810b69af4096181234 100644 ---- a/arch/x86/kernel/kvm.c -+++ b/arch/x86/kernel/kvm.c -@@ -285,6 +285,7 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_kvm_asyncpf_interrupt) - } - - set_irq_regs(old_regs); -+ return 0; - } - - static void __init paravirt_ops_setup(void) -diff --git a/arch/x86/kernel/nmi.c b/arch/x86/kernel/nmi.c -index 4bc77aaf1303974753bc8ea87c678357e61325d5..c3c8eec1a597aab3320e2daa514ff60edaf51b51 100644 ---- a/arch/x86/kernel/nmi.c -+++ b/arch/x86/kernel/nmi.c -@@ -484,11 +484,11 @@ DEFINE_IDTENTRY_RAW(exc_nmi) - sev_es_nmi_complete(); - - if (IS_ENABLED(CONFIG_SMP) && arch_cpu_is_offline(smp_processor_id())) -- return; -+ return 0; - - if (this_cpu_read(nmi_state) != NMI_NOT_RUNNING) { - this_cpu_write(nmi_state, NMI_LATCHED); -- return; -+ return 0; - } - this_cpu_write(nmi_state, NMI_EXECUTING); - this_cpu_write(nmi_cr2, read_cr2()); -@@ -522,6 +522,7 @@ DEFINE_IDTENTRY_RAW(exc_nmi) - - if (user_mode(regs)) - mds_user_clear_cpu_buffers(); -+ return 0; - } - - void stop_nmi(void) -diff --git a/arch/x86/kernel/sev-es.c b/arch/x86/kernel/sev-es.c -index 84c1821819afb8fb3da3b09b8d429930bd1d4da3..536e85e4932dd53d460a6ae3558c5f4d21b6f1e3 100644 ---- a/arch/x86/kernel/sev-es.c -+++ b/arch/x86/kernel/sev-es.c -@@ -1260,7 +1260,7 @@ DEFINE_IDTENTRY_VC_SAFE_STACK(exc_vmm_communication) - */ - if (error_code == SVM_EXIT_EXCP_BASE + X86_TRAP_DB) { - vc_handle_trap_db(regs); -- return; -+ return 0; - } - - instrumentation_begin(); -@@ -1326,7 +1326,7 @@ DEFINE_IDTENTRY_VC_SAFE_STACK(exc_vmm_communication) - out: - instrumentation_end(); - -- return; -+ return 0; - - fail: - if (user_mode(regs)) { -@@ -1359,6 +1359,7 @@ DEFINE_IDTENTRY_VC_IST(exc_vmm_communication) - instrumentation_begin(); - panic("Can't handle #VC exception from unsupported context\n"); - instrumentation_end(); -+ return 0; - } - - DEFINE_IDTENTRY_VC(exc_vmm_communication) -@@ -1367,6 +1368,7 @@ DEFINE_IDTENTRY_VC(exc_vmm_communication) - safe_stack_exc_vmm_communication(regs, error_code); - else - ist_exc_vmm_communication(regs, error_code); -+ return 0; - } - - bool __init handle_vc_boot_ghcb(struct pt_regs *regs) -diff --git a/arch/x86/kernel/smp.c b/arch/x86/kernel/smp.c -index eff4ce3b10da7185cb770e35b6006516e72830db..2b3046a5b07e11d23e88bd6280d6a0480ddfe15f 100644 ---- a/arch/x86/kernel/smp.c -+++ b/arch/x86/kernel/smp.c -@@ -136,6 +136,7 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_reboot) - ack_APIC_irq(); - cpu_emergency_vmxoff(); - stop_this_cpu(NULL); -+ return 0; - } - - static int register_stop_handler(void) -@@ -229,6 +230,7 @@ DEFINE_IDTENTRY_SYSVEC_SIMPLE(sysvec_reschedule_ipi) - inc_irq_stat(irq_resched_count); - scheduler_ipi(); - trace_reschedule_exit(RESCHEDULE_VECTOR); -+ return 0; - } - - DEFINE_IDTENTRY_SYSVEC(sysvec_call_function) -@@ -238,6 +240,7 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_call_function) - inc_irq_stat(irq_call_count); - generic_smp_call_function_interrupt(); - trace_call_function_exit(CALL_FUNCTION_VECTOR); -+ return 0; - } - - DEFINE_IDTENTRY_SYSVEC(sysvec_call_function_single) -@@ -247,6 +250,7 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_call_function_single) - inc_irq_stat(irq_call_count); - generic_smp_call_function_single_interrupt(); - trace_call_function_single_exit(CALL_FUNCTION_SINGLE_VECTOR); -+ return 0; - } - - static int __init nonmi_ipi_setup(char *str) -diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c -index 170c94ec00685de0348f39e8f1087f9e7f119fed..39f2ab128cc7b39083c457985910f824a27805c7 100644 ---- a/arch/x86/kernel/traps.c -+++ b/arch/x86/kernel/traps.c -@@ -166,17 +166,20 @@ do_trap(int trapnr, int signr, char *str, struct pt_regs *regs, - } - NOKPROBE_SYMBOL(do_trap); - --static void do_error_trap(struct pt_regs *regs, long error_code, char *str, -+static int do_error_trap(struct pt_regs *regs, long error_code, char *str, - unsigned long trapnr, int signr, int sicode, void __user *addr) - { -+ int ret; -+ - RCU_LOCKDEP_WARN(!rcu_is_watching(), "entry code didn't wake RCU"); - -- if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) != -- NOTIFY_STOP) { -+ ret = notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr); -+ if ((ret & NOTIFY_STOP_MASK) != NOTIFY_STOP_MASK) { - cond_local_irq_enable(regs); - do_trap(trapnr, signr, str, regs, error_code, sicode, addr); - cond_local_irq_disable(regs); - } -+ return notifier_to_errno(ret); - } - - /* -@@ -196,13 +199,14 @@ static __always_inline void __user *error_get_trap_addr(struct pt_regs *regs) - - DEFINE_IDTENTRY(exc_divide_error) - { -- do_error_trap(regs, 0, "divide error", X86_TRAP_DE, SIGFPE, -- FPE_INTDIV, error_get_trap_addr(regs)); -+ return do_error_trap(regs, 0, "divide error", X86_TRAP_DE, SIGFPE, -+ FPE_INTDIV, error_get_trap_addr(regs)); - } - - DEFINE_IDTENTRY(exc_overflow) - { -- do_error_trap(regs, 0, "overflow", X86_TRAP_OF, SIGSEGV, 0, NULL); -+ return do_error_trap(regs, 0, "overflow", X86_TRAP_OF, SIGSEGV, -+ 0, NULL); - } - - #ifdef CONFIG_X86_F00F_BUG -@@ -253,37 +257,38 @@ DEFINE_IDTENTRY_RAW(exc_invalid_op) - * in case exception entry is the one triggering WARNs. - */ - if (!user_mode(regs) && handle_bug(regs)) -- return; -+ return 0; - - state = irqentry_enter(regs); - instrumentation_begin(); - handle_invalid_op(regs); - instrumentation_end(); - irqentry_exit(regs, state); -+ return 0; - } - - DEFINE_IDTENTRY(exc_coproc_segment_overrun) - { -- do_error_trap(regs, 0, "coprocessor segment overrun", -- X86_TRAP_OLD_MF, SIGFPE, 0, NULL); -+ return do_error_trap(regs, 0, "coprocessor segment overrun", -+ X86_TRAP_OLD_MF, SIGFPE, 0, NULL); - } - - DEFINE_IDTENTRY_ERRORCODE(exc_invalid_tss) - { -- do_error_trap(regs, error_code, "invalid TSS", X86_TRAP_TS, SIGSEGV, -- 0, NULL); -+ return do_error_trap(regs, error_code, "invalid TSS", X86_TRAP_TS, -+ SIGSEGV, 0, NULL); - } - - DEFINE_IDTENTRY_ERRORCODE(exc_segment_not_present) - { -- do_error_trap(regs, error_code, "segment not present", X86_TRAP_NP, -- SIGBUS, 0, NULL); -+ return do_error_trap(regs, error_code, "segment not present", X86_TRAP_NP, -+ SIGBUS, 0, NULL); - } - - DEFINE_IDTENTRY_ERRORCODE(exc_stack_segment) - { -- do_error_trap(regs, error_code, "stack segment", X86_TRAP_SS, SIGBUS, -- 0, NULL); -+ return do_error_trap(regs, error_code, "stack segment", X86_TRAP_SS, -+ SIGBUS, 0, NULL); - } - - DEFINE_IDTENTRY_ERRORCODE(exc_alignment_check) -@@ -291,7 +296,7 @@ DEFINE_IDTENTRY_ERRORCODE(exc_alignment_check) - char *str = "alignment check"; - - if (notify_die(DIE_TRAP, str, regs, error_code, X86_TRAP_AC, SIGBUS) == NOTIFY_STOP) -- return; -+ return 0; - - if (!user_mode(regs)) - die("Split lock detected\n", regs, error_code); -@@ -306,6 +311,7 @@ DEFINE_IDTENTRY_ERRORCODE(exc_alignment_check) - - out: - local_irq_disable(); -+ return 0; - } - - #ifdef CONFIG_VMAP_STACK -@@ -402,7 +408,7 @@ DEFINE_IDTENTRY_DF(exc_double_fault) - regs->ip = (unsigned long)asm_exc_general_protection; - regs->sp = (unsigned long)&gpregs->orig_ax; - -- return; -+ return 0; - } - #endif - -@@ -461,13 +467,14 @@ DEFINE_IDTENTRY_DF(exc_double_fault) - die("double fault", regs, error_code); - panic("Machine halted."); - instrumentation_end(); -+ return 0; - } - - DEFINE_IDTENTRY(exc_bounds) - { - if (notify_die(DIE_TRAP, "bounds", regs, 0, - X86_TRAP_BR, SIGSEGV) == NOTIFY_STOP) -- return; -+ return 0; - cond_local_irq_enable(regs); - - if (!user_mode(regs)) -@@ -476,6 +483,7 @@ DEFINE_IDTENTRY(exc_bounds) - do_trap(X86_TRAP_BR, SIGSEGV, "bounds", regs, 0, 0, NULL); - - cond_local_irq_disable(regs); -+ return 0; - } - - enum kernel_gp_hint { -@@ -529,7 +537,7 @@ DEFINE_IDTENTRY_ERRORCODE(exc_general_protection) - enum kernel_gp_hint hint = GP_NO_HINT; - struct task_struct *tsk; - unsigned long gp_addr; -- int ret; -+ int ret = 0; - - cond_local_irq_enable(regs); - -@@ -542,7 +550,7 @@ DEFINE_IDTENTRY_ERRORCODE(exc_general_protection) - local_irq_enable(); - handle_vm86_fault((struct kernel_vm86_regs *) regs, error_code); - local_irq_disable(); -- return; -+ return 0; - } - - tsk = current; -@@ -572,8 +580,10 @@ DEFINE_IDTENTRY_ERRORCODE(exc_general_protection) - goto exit; - - ret = notify_die(DIE_GPF, desc, regs, error_code, X86_TRAP_GP, SIGSEGV); -- if (ret == NOTIFY_STOP) -+ if ((ret & NOTIFY_STOP_MASK) == NOTIFY_STOP_MASK) { -+ ret = notifier_to_errno(ret); - goto exit; -+ } - - if (error_code) - snprintf(desc, sizeof(desc), "segment-related " GPFSTR); -@@ -597,9 +607,10 @@ DEFINE_IDTENTRY_ERRORCODE(exc_general_protection) - - exit: - cond_local_irq_disable(regs); -+ return ret; - } - --static bool do_int3(struct pt_regs *regs) -+static bool do_int3(struct pt_regs *regs, int *error_code) - { - int res; - -@@ -615,28 +626,37 @@ static bool do_int3(struct pt_regs *regs) - #endif - res = notify_die(DIE_INT3, "int3", regs, 0, X86_TRAP_BP, SIGTRAP); - -- return res == NOTIFY_STOP; -+ if ((res & NOTIFY_STOP_MASK) == NOTIFY_STOP_MASK) { -+ *error_code = notifier_to_errno (res); -+ return true; -+ } -+ -+ return false; - } - --static void do_int3_user(struct pt_regs *regs) -+static int do_int3_user(struct pt_regs *regs) - { -- if (do_int3(regs)) -- return; -+ int ret = 0; -+ if (do_int3(regs, &ret)) -+ return ret; - - cond_local_irq_enable(regs); - do_trap(X86_TRAP_BP, SIGTRAP, "int3", regs, 0, 0, NULL); - cond_local_irq_disable(regs); -+ return 0; - } - - DEFINE_IDTENTRY_RAW(exc_int3) - { -+ int ret = 0; -+ - /* - * poke_int3_handler() is completely self contained code; it does (and - * must) *NOT* call out to anything, lest it hits upon yet another - * INT3. - */ - if (poke_int3_handler(regs)) -- return; -+ return 0; - - /* - * irqentry_enter_from_user_mode() uses static_branch_{,un}likely() -@@ -648,17 +668,18 @@ DEFINE_IDTENTRY_RAW(exc_int3) - if (user_mode(regs)) { - irqentry_enter_from_user_mode(regs); - instrumentation_begin(); -- do_int3_user(regs); -+ ret = do_int3_user(regs); - instrumentation_end(); - irqentry_exit_to_user_mode(regs); - } else { - bool irq_state = idtentry_enter_nmi(regs); - instrumentation_begin(); -- if (!do_int3(regs)) -+ if (!do_int3(regs, &ret)) - die("int3", regs, 0); - instrumentation_end(); - idtentry_exit_nmi(regs, irq_state); - } -+ return ret; - } - - #ifdef CONFIG_X86_64 -@@ -988,12 +1009,14 @@ static __always_inline void exc_debug_user(struct pt_regs *regs, - DEFINE_IDTENTRY_DEBUG(exc_debug) - { - exc_debug_kernel(regs, debug_read_clear_dr6()); -+ return 0; - } - - /* User entry, runs on regular task stack */ - DEFINE_IDTENTRY_DEBUG_USER(exc_debug) - { - exc_debug_user(regs, debug_read_clear_dr6()); -+ return 0; - } - #else - /* 32 bit does not have separate entry points. */ -@@ -1005,6 +1028,7 @@ DEFINE_IDTENTRY_RAW(exc_debug) - exc_debug_user(regs, dr6); - else - exc_debug_kernel(regs, dr6); -+ return 0; - } - #endif - -@@ -1058,6 +1082,7 @@ static void math_error(struct pt_regs *regs, int trapnr) - DEFINE_IDTENTRY(exc_coprocessor_error) - { - math_error(regs, X86_TRAP_MF); -+ return 0; - } - - DEFINE_IDTENTRY(exc_simd_coprocessor_error) -@@ -1066,10 +1091,11 @@ DEFINE_IDTENTRY(exc_simd_coprocessor_error) - /* AMD 486 bug: INVD in CPL 0 raises #XF instead of #GP */ - if (!static_cpu_has(X86_FEATURE_XMM)) { - __exc_general_protection(regs, 0); -- return; -+ return 0; - } - } - math_error(regs, X86_TRAP_XF); -+ return 0; - } - - DEFINE_IDTENTRY(exc_spurious_interrupt_bug) -@@ -1093,6 +1119,7 @@ DEFINE_IDTENTRY(exc_spurious_interrupt_bug) - * In theory this could be limited to 32bit, but the handler is not - * hurting and who knows which other CPUs suffer from this. - */ -+ return 0; - } - - DEFINE_IDTENTRY(exc_device_not_available) -@@ -1109,7 +1136,7 @@ DEFINE_IDTENTRY(exc_device_not_available) - math_emulate(&info); - - cond_local_irq_disable(regs); -- return; -+ return 0; - } - #endif - -@@ -1125,6 +1152,7 @@ DEFINE_IDTENTRY(exc_device_not_available) - */ - die("unexpected #NM exception", regs, 0); - } -+ return 0; - } - - #ifdef CONFIG_X86_32 -@@ -1137,6 +1165,7 @@ DEFINE_IDTENTRY_SW(iret_error) - ILL_BADSTK, (void __user *)NULL); - } - local_irq_disable(); -+ return 0; - } - #endif - -diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c -index 5b16183100d07fb85d26163b11694097b774a751..d5b9734946c3b77b3451f338a37f6602cee67447 100644 ---- a/arch/x86/mm/fault.c -+++ b/arch/x86/mm/fault.c -@@ -1493,7 +1493,7 @@ DEFINE_IDTENTRY_RAW_ERRORCODE(exc_page_fault) - * itself. - */ - if (kvm_handle_async_pf(regs, (u32)address)) -- return; -+ return 0; - - /* - * Entry handling for valid #PF from kernel mode is slightly -@@ -1512,4 +1512,5 @@ DEFINE_IDTENTRY_RAW_ERRORCODE(exc_page_fault) - instrumentation_end(); - - irqentry_exit(regs, state); -+ return 0; - } -diff --git a/arch/x86/xen/enlighten_hvm.c b/arch/x86/xen/enlighten_hvm.c -index ec50b7423a4c8609118f3f6f1ee67aa9dd238b31..1c4b08f2dc3b43619359fa72b708f87d89b9609c 100644 ---- a/arch/x86/xen/enlighten_hvm.c -+++ b/arch/x86/xen/enlighten_hvm.c -@@ -129,6 +129,7 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_xen_hvm_callback) - xen_hvm_evtchn_do_upcall(); - - set_irq_regs(old_regs); -+ return 0; - } - - #ifdef CONFIG_KEXEC_CORE -diff --git a/arch/x86/xen/enlighten_pv.c b/arch/x86/xen/enlighten_pv.c -index 4409306364dc3cd5c774ee190efe83a6079a9cc2..080702bf757bb1d9de12d1670a8f6a6a4e140ea8 100644 ---- a/arch/x86/xen/enlighten_pv.c -+++ b/arch/x86/xen/enlighten_pv.c -@@ -563,12 +563,12 @@ static void xen_write_ldt_entry(struct desc_struct *dt, int entrynum, - preempt_enable(); - } - --void noist_exc_debug(struct pt_regs *regs); -+int noist_exc_debug(struct pt_regs *regs); - - DEFINE_IDTENTRY_RAW(xenpv_exc_nmi) - { - /* On Xen PV, NMI doesn't use IST. The C part is the sane as native. */ -- exc_nmi(regs); -+ return exc_nmi(regs); - } - - DEFINE_IDTENTRY_RAW(xenpv_exc_debug) -@@ -578,9 +578,9 @@ DEFINE_IDTENTRY_RAW(xenpv_exc_debug) - * to the correct handler. - */ - if (user_mode(regs)) -- noist_exc_debug(regs); -+ return noist_exc_debug(regs); - else -- exc_debug(regs); -+ return exc_debug(regs); - } - - struct trap_array_entry { -diff --git a/include/linux/dtrace_fbt.h b/include/linux/dtrace_fbt.h -new file mode 100644 -index 0000000000000000000000000000000000000000..d11e273cee317949ba85e954e4c0ead42e52b115 ---- /dev/null -+++ b/include/linux/dtrace_fbt.h -@@ -0,0 +1,48 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ *Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+#ifndef _LINUX_DTRACE_FBT_H -+#define _LINUX_DTRACE_FBT_H -+ -+#include <linux/module.h> -+#include <asm/dtrace_arch.h> -+ -+extern unsigned long dtrace_fbt_nfuncs __attribute__((weak)); -+ -+/* -+ * Prototype for callback function that handles the actual creation of FBT -+ * probes. -+ * -+ * Arguments to pass: -+ * - Pointer to module the probe will belong to -+ * - function name -+ * - probe type (FBT_ENTRY or FBT_RETURN) -+ * - probe subtype (arch-specific) -+ * - address (location of the probe) -+ * - offset from the function start -+ * - return value from previous callback invocation -+ * - cookie passed to dtrace_fbt_init -+ * Returns: -+ * - generic pointer (only to be used to pass back in) -+ */ -+#define FBT_ENTRY 0 -+#define FBT_RETURN 1 -+ -+typedef void *(*fbt_add_probe_fn)(struct module *, char *, int, int, -+ asm_instr_t *, uintptr_t, void *, void *); -+extern void dtrace_fbt_init(fbt_add_probe_fn, struct module *, void *); -+ -+/* -+ * Dynamic blacklist routines. -+ */ -+struct dt_fbt_bl_entry; -+ -+extern struct dt_fbt_bl_entry *dtrace_fbt_bl_add(unsigned long, const char *); -+extern struct dt_fbt_bl_entry *dtrace_fbt_bl_first(void); -+extern struct dt_fbt_bl_entry *dtrace_fbt_bl_next(struct dt_fbt_bl_entry *); -+extern unsigned long dtrace_fbt_bl_entry_addr(struct dt_fbt_bl_entry *); -+extern const char *dtrace_fbt_bl_entry_name(struct dt_fbt_bl_entry *); -+ -+#endif /* _LINUX_DTRACE_FBT_H */ -diff --git a/kernel/dtrace/Kconfig b/kernel/dtrace/Kconfig -index 6bf6620981cd14bcc64cd0f7f71b499e478ea31e..1f070e49c69f107cfa4c940ae47ab3a72622f8f7 100644 ---- a/kernel/dtrace/Kconfig -+++ b/kernel/dtrace/Kconfig -@@ -55,6 +55,13 @@ config DT_SDT_PERF - Provides the perf provider, containing a DTrace probe for each - perf-events tracepoint in the system. - -+config DT_FBT -+ tristate "Function boundary tracing" -+ default m -+ select FTRACE -+ help -+ Provides function boundary tracing for functions in the kernel. -+ - config DT_SYSTRACE - tristate "System Call Tracing" - default m -diff --git a/kernel/dtrace/Makefile b/kernel/dtrace/Makefile -index 06329cbe52cbfbd96c23e6838fc99e53cc5ec5d6..0e5fb34b7b478af215c24a57003c3988ee7a43fa 100644 ---- a/kernel/dtrace/Makefile -+++ b/kernel/dtrace/Makefile -@@ -4,11 +4,11 @@ - - DT_CORE_ARCH_OBJS = $(addprefix ../../arch/$(SRCARCH)/kernel/, \ - dtrace_syscall.o dtrace_syscall_stubs.o \ -- dtrace_sdt.o dtrace_util.o) -+ dtrace_fbt.o dtrace_sdt.o dtrace_util.o) - - ifdef CONFIG_DT_CORE - obj-y += cyclic.o dtrace_os.o dtrace_cpu.o \ -- dtrace_sdt_core.o \ -+ dtrace_sdt_core.o dtrace_fbt_core.o \ - dtrace_task.o dtrace_psinfo.o \ - $(DT_CORE_ARCH_OBJS) - endif -diff --git a/kernel/dtrace/dtrace_fbt_core.c b/kernel/dtrace/dtrace_fbt_core.c -new file mode 100644 -index 0000000000000000000000000000000000000000..67182a3b13fcd9cd0b6c81167ae502bbde181f4a ---- /dev/null -+++ b/kernel/dtrace/dtrace_fbt_core.c -@@ -0,0 +1,125 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_fbt_core.c -+ * DESCRIPTION: DTrace - FBT common code -+ * -+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/kallsyms.h> -+#include <linux/rbtree.h> -+#include <linux/slab.h> -+#include <linux/dtrace_fbt.h> -+ -+struct dt_fbt_bl_entry { -+ struct rb_node dfbe_node; -+ unsigned long dfbe_addr; -+ const char *dfbe_name; -+}; -+ -+static struct rb_root dt_fbt_root = RB_ROOT; -+ -+struct dt_fbt_bl_entry * -+dtrace_fbt_bl_add(unsigned long addr, const char *name) -+{ -+ struct rb_node **p = &dt_fbt_root.rb_node; -+ struct rb_node *parent = NULL; -+ struct dt_fbt_bl_entry *entry; -+ -+ /* -+ * If no address was given, we need to do a symbol name lookup: -+ * - If no symbol name was given, we cannot add anything. -+ * - If the lookup failed, we cannot add anything. -+ */ -+ if (addr == 0) { -+ if (name == NULL) -+ return NULL; -+ -+ addr = kallsyms_lookup_name(name); -+ -+ if (addr == 0) -+ return NULL; -+ } -+ -+ /* Find place in the tree. */ -+ while (*p) { -+ parent = *p; -+ entry = rb_entry(parent, struct dt_fbt_bl_entry, dfbe_node); -+ -+ if (addr > entry->dfbe_addr) -+ p = &parent->rb_right; -+ else if (addr < entry->dfbe_addr) -+ p = &parent->rb_left; -+ else -+ return NULL; /* no duplicates please */ -+ } -+ -+ /* Create a new blacklist entry. */ -+ entry = kmalloc(sizeof(*entry), GFP_KERNEL); -+ if (entry == NULL) -+ return NULL; -+ -+ entry->dfbe_name = name; -+ entry->dfbe_addr = addr; -+ -+ /* Update the tree. */ -+ rb_link_node(&entry->dfbe_node, parent, p); -+ rb_insert_color(&entry->dfbe_node, &dt_fbt_root); -+ -+ return entry; -+} -+ -+/* -+ * Iterators for blacklisted symbols. The iteration happens in sort order by -+ * virtual memory address. Symbols with pending resolution are inored. -+ */ -+struct dt_fbt_bl_entry * -+dtrace_fbt_bl_first(void) -+{ -+ struct rb_node *node = rb_first(&dt_fbt_root); -+ -+ if (node == NULL) -+ return (NULL); -+ -+ return rb_entry(node, struct dt_fbt_bl_entry, dfbe_node); -+} -+ -+struct dt_fbt_bl_entry * -+dtrace_fbt_bl_next(struct dt_fbt_bl_entry *entry) -+{ -+ struct rb_node *node = rb_next(&entry->dfbe_node); -+ -+ if (node == NULL) -+ return (NULL); -+ -+ return rb_entry(node, struct dt_fbt_bl_entry, dfbe_node); -+} -+ -+unsigned long -+dtrace_fbt_bl_entry_addr(struct dt_fbt_bl_entry *entry) -+{ -+ if (entry == NULL) -+ return (0); -+ -+ return entry->dfbe_addr; -+} -+ -+const char * -+dtrace_fbt_bl_entry_name(struct dt_fbt_bl_entry *entry) -+{ -+ if (entry == NULL) -+ return (NULL); -+ -+ return entry->dfbe_name; -+} -diff --git a/kernel/dtrace/dtrace_os.c b/kernel/dtrace/dtrace_os.c -index 874e097b84fd4b517cdb1e867a4b9d9ff2504078..bb5650cf72ebf9177d7e2d87eabf3d849e60cd76 100644 ---- a/kernel/dtrace/dtrace_os.c -+++ b/kernel/dtrace/dtrace_os.c -@@ -18,6 +18,7 @@ - - #include <linux/binfmts.h> - #include <linux/dtrace_cpu.h> -+#include <linux/dtrace_fbt.h> - #include <linux/dtrace_os.h> - #include <linux/dtrace_sdt.h> - #include <linux/fs.h> -@@ -103,6 +104,7 @@ void __init dtrace_os_init(void) - dtrace_kmod->core_layout.size = 0x2000000; - #endif - -+ dtrace_kmod->num_ftrace_callsites = dtrace_fbt_nfuncs; - dtrace_kmod->state = MODULE_STATE_LIVE; - atomic_inc(&dtrace_kmod->refcnt); - -diff --git a/kernel/kprobes.c b/kernel/kprobes.c -index 41fdbb7953c60f878049b2a5807abb4aecf95320..b702c7c484e7710d2b8501f75cd83a0fb3f7775d 100644 ---- a/kernel/kprobes.c -+++ b/kernel/kprobes.c -@@ -38,6 +38,10 @@ - #include <linux/perf_event.h> - #include <linux/static_call.h> - -+#ifdef CONFIG_DTRACE -+#include <linux/dtrace_fbt.h> -+#endif -+ - #include <asm/sections.h> - #include <asm/cacheflush.h> - #include <asm/errno.h> -@@ -2336,6 +2340,10 @@ int kprobe_add_ksym_blacklist(unsigned long entry) - !kallsyms_lookup_size_offset(entry, &size, &offset)) - return -EINVAL; - -+#ifdef CONFIG_DTRACE -+ dtrace_fbt_bl_add(entry, NULL); -+#endif -+ - ent = kmalloc(sizeof(*ent), GFP_KERNEL); - if (!ent) - return -ENOMEM; --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/dtrace-patches/0015-dtrace-fbt-provider-modular-components.patch b/sys-kernel/cairn-sources/files/5.10.14/dtrace-patches/0015-dtrace-fbt-provider-modular-components.patch deleted file mode 100644 index d62dd30f73f4..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/dtrace-patches/0015-dtrace-fbt-provider-modular-components.patch +++ /dev/null @@ -1,683 +0,0 @@ -From b3955b4ec46d8139665fc881dd088e9fcb67ff36 Mon Sep 17 00:00:00 2001 -From: Kris Van Hees <kris.van.hees@oracle.com> -Date: Mon, 19 Nov 2018 18:12:44 +0000 -Subject: [PATCH 15/19] dtrace: fbt provider, modular components - -This uses the fbt machinery added in the previous commit. - -Signed-off-by: Kris Van Hees <kris.van.hees@oracle.com> -Signed-off-by: Nick Alcock <nick.alcock@oracle.com> -Signed-off-by: Tomas Jedlicka <tomas.jedlicka@oracle.com> -Signed-off-by: Eugene Loh <eugene.loh@oracle.com> -Signed-off-by: David Mc Lean <david.mclean@oracle.com> -Signed-off-by: Vincent Lim <vincent.lim@oracle.com> ---- - arch/x86/dtrace/Makefile.arch | 2 + - arch/x86/dtrace/fbt_x86_64.c | 156 ++++++++++++ - arch/x86/dtrace/include/dtrace/fbt_arch.h | 42 ++++ - dtrace/Makefile | 2 + - dtrace/fbt_dev.c | 281 ++++++++++++++++++++++ - dtrace/fbt_impl.h | 52 ++++ - dtrace/fbt_mod.c | 56 +++++ - 7 files changed, 591 insertions(+) - create mode 100644 arch/x86/dtrace/fbt_x86_64.c - create mode 100644 arch/x86/dtrace/include/dtrace/fbt_arch.h - create mode 100644 dtrace/fbt_dev.c - create mode 100644 dtrace/fbt_impl.h - create mode 100644 dtrace/fbt_mod.c - -diff --git a/arch/x86/dtrace/Makefile.arch b/arch/x86/dtrace/Makefile.arch -index e4655557e06ad7524677b9f3b0909f248d5a1c8b..906fa8c7e17c02958fa19a5e33d043a92109c4fa 100644 ---- a/arch/x86/dtrace/Makefile.arch -+++ b/arch/x86/dtrace/Makefile.arch -@@ -8,8 +8,10 @@ ccflags-y += -I$(srctree)/arch/x86/dtrace/include -Idtrace - - dtrace-obj += dtrace_asm_x86_64.o dtrace_isa_x86_64.o - fasttrap-obj += fasttrap_x86_64.o -+fbt-obj += fbt_x86_64.o - sdt-obj += sdt_x86_64.o - - dtrace-y += $(addprefix $(DTARCHDIR)/, $(dtrace-obj)) - fasttrap-y += $(addprefix $(DTARCHDIR)/, $(fasttrap-obj)) -+fbt-y += $(addprefix $(DTARCHDIR)/, $(fbt-obj)) - sdt-y += $(addprefix $(DTARCHDIR)/, $(sdt-obj)) -diff --git a/arch/x86/dtrace/fbt_x86_64.c b/arch/x86/dtrace/fbt_x86_64.c -new file mode 100644 -index 0000000000000000000000000000000000000000..a8a05292be7e1f876d0971c133db9436f31a5eab ---- /dev/null -+++ b/arch/x86/dtrace/fbt_x86_64.c -@@ -0,0 +1,156 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: fbt_x86_64.c -+ * DESCRIPTION: DTrace - FBT provider implementation for x86 -+ * -+ * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/dtrace_fbt.h> -+#include <linux/vmalloc.h> -+#include <asm/dtrace_util.h> -+ -+#include "dtrace.h" -+#include "dtrace_dev.h" -+#include "fbt_impl.h" -+ -+/* -+ * Use 0xf0 (LOCK Prefix) and X86_TRAP_UD for Invalid Opcode traps to be used. -+ * Use 0xcc (INT 3) and X86_TRAP_BP for Breakpoint traps to be used. -+ */ -+#define FBT_ENTRY_PATCHVAL 0xcc -+#define FBT_ENTRY_TRAP X86_TRAP_BP -+#define FBT_RETURN_PATCHVAL 0xcc -+#define FBT_RETURN_TRAP X86_TRAP_BP -+ -+static uint8_t fbt_invop(struct pt_regs *regs) -+{ -+ struct fbt_probe *fbp = fbt_probetab[FBT_ADDR2NDX(regs->ip)]; -+ -+ for (; fbp != NULL; fbp = fbp->fbp_hashnext) { -+ if ((uintptr_t)fbp->fbp_patchpoint == regs->ip) { -+ struct pt_regs *old = this_cpu_core->cpu_dtrace_regs; -+ -+ this_cpu_core->cpu_dtrace_regs = regs; -+ if (fbp->fbp_roffset == 0) { -+ dtrace_probe(fbp->fbp_id, regs->di, regs->si, -+ regs->dx, regs->cx, regs->r8, -+ regs->r9, 0); -+ } else { -+ dtrace_probe(fbp->fbp_id, fbp->fbp_roffset, -+ regs->ax, 0, 0, 0, 0, 0); -+ } -+ -+ this_cpu_core->cpu_dtrace_regs = old; -+ -+ return fbp->fbp_rval; -+ } -+ } -+ -+ return 0; -+} -+ -+uint64_t fbt_getarg(void *arg, dtrace_id_t id, void *parg, int argno, -+ int aframes) -+{ -+ struct pt_regs *regs = this_cpu_core->cpu_dtrace_regs; -+ uint64_t *st; -+ uint64_t val; -+ -+ if (regs == NULL) -+ return 0; -+ -+ switch (argno) { -+ case 0: -+ return regs->di; -+ case 1: -+ return regs->si; -+ case 2: -+ return regs->dx; -+ case 3: -+ return regs->cx; -+ case 4: -+ return regs->r8; -+ case 5: -+ return regs->r9; -+ } -+ -+ ASSERT(argno > 5); -+ -+ st = (uint64_t *)regs->sp; -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); -+ /* -+ * Skip the topmost slot of the stack because that holds the return -+ * address for the call to the function we are entering. At this point -+ * the BP has not been pushed yet, so we are still working within the -+ * caller's stack frame. -+ */ -+ val = st[1 + argno - 6]; -+ DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); -+ -+ return val; -+} -+ -+void fbt_provide_probe_arch(struct fbt_probe *fbp, int probetype, int stype) -+{ -+ fbp->fbp_patchval = probetype == FBT_ENTRY ? FBT_ENTRY_PATCHVAL -+ : FBT_RETURN_PATCHVAL; -+ fbp->fbp_savedval = *fbp->fbp_patchpoint; -+ fbp->fbp_rval = probetype == FBT_ENTRY ? DTRACE_INVOP_PUSH_BP -+ : DTRACE_INVOP_RET; -+} -+ -+int fbt_can_patch_return_arch(asm_instr_t *addr) -+{ -+ return 1; -+} -+ -+int fbt_provide_module_arch(void *arg, struct module *mp) -+{ -+ return 1; -+} -+ -+void fbt_destroy_module(void *arg, struct module *mp) -+{ -+} -+ -+void fbt_enable_arch(struct fbt_probe *fbp, dtrace_id_t id, void *arg) -+{ -+ dtrace_invop_enable(fbp->fbp_patchpoint, fbp->fbp_patchval); -+} -+ -+void fbt_disable_arch(struct fbt_probe *fbp, dtrace_id_t id, void *arg) -+{ -+ dtrace_invop_disable(fbp->fbp_patchpoint, fbp->fbp_savedval); -+} -+ -+int fbt_dev_init_arch(void) -+{ -+ fbt_probetab_mask = fbt_probetab_size - 1; -+ fbt_probetab = dtrace_vzalloc_try(fbt_probetab_size * -+ sizeof(struct fbt_probe *)); -+ -+ if (fbt_probetab == NULL) -+ return -ENOMEM; -+ -+ return dtrace_invop_add(fbt_invop); -+} -+ -+void fbt_dev_exit_arch(void) -+{ -+ vfree(fbt_probetab); -+ fbt_probetab_mask = 0; -+ fbt_probetab_size = 0; -+ -+ dtrace_invop_remove(fbt_invop); -+} -diff --git a/arch/x86/dtrace/include/dtrace/fbt_arch.h b/arch/x86/dtrace/include/dtrace/fbt_arch.h -new file mode 100644 -index 0000000000000000000000000000000000000000..7e90b2b75bba0c2d45aab458af7d9f7e8e923d06 ---- /dev/null -+++ b/arch/x86/dtrace/include/dtrace/fbt_arch.h -@@ -0,0 +1,42 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Dynamic Tracing for Linux - FBT Implementation defines -+ * -+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _X86_64_FBT_ARCH_H -+#define _X86_64_FBT_ARCH_H -+ -+#define FBT_AFRAMES 7 -+ -+struct fbt_probe { -+ char *fbp_name; /* name of probe */ -+ dtrace_id_t fbp_id; /* probe ID */ -+ struct module *fbp_module; /* defining module */ -+ int fbp_primary; /* non-zero if primary mod */ -+ asm_instr_t *fbp_patchpoint;/* patch point */ -+ asm_instr_t fbp_patchval; /* instruction to patch */ -+ asm_instr_t fbp_savedval; /* saved instruction value */ -+ uintptr_t fbp_roffset; /* relative offset */ -+ int fbp_rval; -+ struct fbt_probe *fbp_next; /* next probe */ -+ struct fbt_probe *fbp_hashnext; /* next on hash */ -+}; -+ -+#endif /* _X86_64_FBT_ARCH_H */ -diff --git a/dtrace/Makefile b/dtrace/Makefile -index c7e3fc512a6c7cdc40f9e3343e3cd98bec674b68..35b8b098123ff254e99c3962d1c1854202c7f623 100644 ---- a/dtrace/Makefile -+++ b/dtrace/Makefile -@@ -4,6 +4,7 @@ - - obj-$(CONFIG_DT_CORE) += dtrace.o - obj-$(CONFIG_DT_FASTTRAP) += fasttrap.o -+obj-$(CONFIG_DT_FBT) += fbt.o - obj-$(CONFIG_DT_PROFILE) += profile.o - obj-$(CONFIG_DT_SDT) += sdt.o - obj-$(CONFIG_DT_SYSTRACE) += systrace.o -@@ -19,6 +20,7 @@ dtrace-y := dtrace_mod.o dtrace_dev.o \ - dtrace_ptofapi.o dtrace_predicate.o \ - dtrace_spec.o dtrace_state.o dtrace_util.o - fasttrap-y := fasttrap_mod.o fasttrap_dev.o -+fbt-y := fbt_mod.o fbt_dev.o - profile-y := profile_mod.o profile_dev.o - sdt-y := sdt_mod.o sdt_dev.o - systrace-y := systrace_mod.o systrace_dev.o -diff --git a/dtrace/fbt_dev.c b/dtrace/fbt_dev.c -new file mode 100644 -index 0000000000000000000000000000000000000000..281fd749aae7951b09fc2a44e5c2110eec33bc66 ---- /dev/null -+++ b/dtrace/fbt_dev.c -@@ -0,0 +1,281 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: fbt_dev.c -+ * DESCRIPTION: DTrace - FBT provider device driver -+ * -+ * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/fs.h> -+#include <linux/miscdevice.h> -+#include <linux/kallsyms.h> -+#include <linux/slab.h> -+#include <linux/vmalloc.h> -+#include <linux/dtrace_fbt.h> -+ -+#include "dtrace.h" -+#include "dtrace_dev.h" -+#include "fbt_impl.h" -+ -+#define FBT_PROBETAB_SIZE 0x8000 /* 32k entries -- 128K total */ -+ -+struct fbt_probe **fbt_probetab; -+int fbt_probetab_size = FBT_PROBETAB_SIZE; -+int fbt_probetab_mask; -+ -+static void *fbt_provide_probe(struct module *mp, char *func, int probetype, -+ int stype, asm_instr_t *addr, uintptr_t off, -+ void *pfbt, void *arg) -+{ -+ struct fbt_probe *fbp; -+ struct fbt_probe *prev; -+ int *skipped = arg; -+ -+ switch (probetype) { -+ case FBT_ENTRY: -+ fbp = kzalloc(sizeof(struct fbt_probe), GFP_KERNEL); -+ fbp->fbp_name = kstrdup(func, GFP_KERNEL); -+ if (fbp->fbp_name == NULL) -+ goto err_probe; -+ -+ fbp->fbp_id = dtrace_probe_create(fbt_id, mp->name, func, -+ "entry", FBT_AFRAMES, fbp); -+ if (fbp->fbp_id == DTRACE_IDNONE) -+ goto err_name; -+ -+ fbp->fbp_module = mp; -+ fbp->fbp_primary = 1; /* FIXME */ -+ fbp->fbp_roffset = off; -+ fbp->fbp_patchpoint = addr; -+ fbt_provide_probe_arch(fbp, probetype, stype); -+ -+ fbp->fbp_hashnext = fbt_probetab[FBT_ADDR2NDX(fbp->fbp_patchpoint)]; -+ fbt_probetab[FBT_ADDR2NDX(fbp->fbp_patchpoint)] = fbp; -+ -+ PDATA(mp)->fbt_probe_cnt++; -+ -+ return fbp; -+ case FBT_RETURN: -+ -+ /* Check if we are able to patch this return probe. */ -+ if (!fbt_can_patch_return_arch(addr)) -+ return pfbt; -+ -+ fbp = kzalloc(sizeof(struct fbt_probe), GFP_KERNEL); -+ fbp->fbp_name = kstrdup(func, GFP_KERNEL); -+ if (fbp->fbp_name == NULL) -+ goto err_probe; -+ -+ prev = (struct fbt_probe *)pfbt; -+ if (prev != NULL) { -+ prev->fbp_next = fbp; -+ fbp->fbp_id = prev->fbp_id; -+ } else { -+ fbp->fbp_id = dtrace_probe_create(fbt_id, mp->name, -+ func, "return", -+ FBT_AFRAMES, fbp); -+ if (fbp->fbp_id == DTRACE_IDNONE) -+ goto err_name; -+ } -+ -+ fbp->fbp_module = mp; -+ fbp->fbp_primary = 1; /* FIXME */ -+ fbp->fbp_roffset = off; -+ fbp->fbp_patchpoint = addr; -+ fbt_provide_probe_arch(fbp, probetype, stype); -+ -+ fbp->fbp_hashnext = fbt_probetab[FBT_ADDR2NDX(fbp->fbp_patchpoint)]; -+ fbt_probetab[FBT_ADDR2NDX(fbp->fbp_patchpoint)] = fbp; -+ -+ PDATA(mp)->fbt_probe_cnt++; -+ -+ return fbp; -+ default: -+ pr_info("FBT: Invalid probe type %d (%d) for %s\n", -+ probetype, stype, func); -+ -+ return NULL; -+ } -+ -+err_name: -+ kfree(fbp->fbp_name); -+err_probe: -+ kfree(fbp); -+ (*skipped)++; -+ -+ return NULL; -+} -+ -+void fbt_provide_module(void *arg, struct module *mp) -+{ -+ struct module_use *use; -+ int probes_skipped = 0; -+ -+ /* If module setup has failed then do not provide anything. */ -+ if (PDATA(mp) == NULL) -+ return; -+ -+ /* -+ * Nothing to do if the module FBT probes were already created. -+ */ -+ if (PDATA(mp)->fbt_probe_cnt != 0) -+ return; -+ -+ /* -+ * Do not try to instrument DTrace itself and its modules: -+ * - dtrace module -+ * - all modules depending on dtrace -+ */ -+ if (!strncmp(mp->name, "dtrace", 7)) -+ return; -+ -+ list_for_each_entry(use, &mp->target_list, target_list) { -+ if (!strncmp(use->target->name, "dtrace", 7)) -+ return; -+ } -+ -+ /* -+ * Provide probes. -+ */ -+ if (!fbt_provide_module_arch(arg, mp)) -+ return; -+ -+ dtrace_fbt_init((fbt_add_probe_fn)fbt_provide_probe, mp, -+ &probes_skipped); -+ -+ if (probes_skipped != 0) -+ pr_warn("fbt: Failed to provide %d probes in %s (out of memory)\n", -+ probes_skipped, mp->name); -+} -+ -+int fbt_enable(void *arg, dtrace_id_t id, void *parg) -+{ -+ struct fbt_probe *fbp = parg; -+ struct fbt_probe *curr; -+ -+ /* -+ * Ensure that we have a reference to the module. -+ */ -+ if (!try_module_get(fbp->fbp_module)) -+ return -EAGAIN; -+ -+ /* -+ * If at least one other enabled probe exists for this module, drop the -+ * reference we took above, because we only need one to prevent the -+ * module from being unloaded. -+ */ -+ PDATA(fbp->fbp_module)->enabled_cnt++; -+ if (PDATA(fbp->fbp_module)->enabled_cnt > 1) -+ module_put(fbp->fbp_module); -+ -+ for (curr = fbp; curr != NULL; curr = curr->fbp_next) -+ fbt_enable_arch(curr, id, arg); -+ -+ return 0; -+} -+ -+void fbt_disable(void *arg, dtrace_id_t id, void *parg) -+{ -+ struct fbt_probe *fbp = parg; -+ struct fbt_probe *curr; -+ -+ for (curr = fbp; curr != NULL; curr = curr->fbp_next) -+ fbt_disable_arch(curr, id, arg); -+ -+ /* -+ * If we are disabling a probe, we know it was enabled, and therefore -+ * we know that we have a reference on the module to prevent it from -+ * being unloaded. If we disable the last probe on the module, we can -+ * drop the reference. -+ */ -+ PDATA(fbp->fbp_module)->enabled_cnt--; -+ if (PDATA(fbp->fbp_module)->enabled_cnt == 0) -+ module_put(fbp->fbp_module); -+} -+ -+void fbt_destroy(void *arg, dtrace_id_t id, void *parg) -+{ -+ struct fbt_probe *fbp = parg; -+ struct fbt_probe *hbp, *lst, *nxt; -+ int ndx; -+ struct module *mp = fbp->fbp_module; -+ -+ do { -+ nxt = fbp->fbp_next; -+ -+ ndx = FBT_ADDR2NDX(fbp->fbp_patchpoint); -+ lst = NULL; -+ hbp = fbt_probetab[ndx]; -+ -+ while (hbp != fbp) { -+ ASSERT(hbp != NULL); -+ -+ lst = hbp; -+ hbp = hbp->fbp_hashnext; -+ } -+ -+ if (lst != NULL) -+ lst->fbp_hashnext = fbp->fbp_hashnext; -+ else -+ fbt_probetab[ndx] = fbp->fbp_hashnext; -+ -+ kfree(fbp->fbp_name); -+ kfree(fbp); -+ -+ PDATA(mp)->fbt_probe_cnt--; -+ -+ fbp = nxt; -+ } while (fbp != NULL); -+} -+ -+static int fbt_open(struct inode *inode, struct file *file) -+{ -+ return -EAGAIN; -+} -+ -+static int fbt_close(struct inode *inode, struct file *file) -+{ -+ return 0; -+} -+ -+static const struct file_operations fbt_fops = { -+ .owner = THIS_MODULE, -+ .open = fbt_open, -+ .release = fbt_close, -+}; -+ -+static struct miscdevice fbt_dev = { -+ .minor = DT_DEV_FBT_MINOR, -+ .name = "fbt", -+ .nodename = "dtrace/provider/fbt", -+ .fops = &fbt_fops, -+}; -+ -+int fbt_dev_init(void) -+{ -+ int ret = 0; -+ -+ ret = misc_register(&fbt_dev); -+ if (ret) -+ pr_err("%s: Can't register misc device %d\n", -+ fbt_dev.name, fbt_dev.minor); -+ -+ return fbt_dev_init_arch(); -+} -+ -+void fbt_dev_exit(void) -+{ -+ fbt_dev_exit_arch(); -+ -+ misc_deregister(&fbt_dev); -+} -diff --git a/dtrace/fbt_impl.h b/dtrace/fbt_impl.h -new file mode 100644 -index 0000000000000000000000000000000000000000..85f83e704988c952ab3552ac06d74982fbf34657 ---- /dev/null -+++ b/dtrace/fbt_impl.h -@@ -0,0 +1,52 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Dynamic Tracing for Linux - Function Boundary Tracing provider -+ * -+ * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#ifndef _FBT_H_ -+#define _FBT_H_ -+ -+#include <asm/dtrace_arch.h> -+#include <dtrace/fbt_arch.h> -+ -+#define FBT_ADDR2NDX(addr) ((((uintptr_t)(addr)) >> 4) & \ -+ fbt_probetab_mask) -+ -+extern struct fbt_probe **fbt_probetab; -+extern int fbt_probetab_size; -+extern int fbt_probetab_mask; -+ -+extern void fbt_provide_probe_arch(struct fbt_probe *, int, int); -+extern void fbt_enable_arch(struct fbt_probe *, dtrace_id_t, void *); -+extern void fbt_disable_arch(struct fbt_probe *, dtrace_id_t, void *); -+extern int fbt_can_patch_return_arch(asm_instr_t *); -+ -+extern int fbt_provide_module_arch(void *, struct module *); -+extern void fbt_provide_module(void *, struct module *); -+extern void fbt_destroy_module(void *, struct module *); -+extern int fbt_enable(void *, dtrace_id_t, void *); -+extern void fbt_disable(void *, dtrace_id_t, void *); -+extern uint64_t fbt_getarg(void *, dtrace_id_t, void *, int, int); -+extern void fbt_destroy(void *, dtrace_id_t, void *); -+ -+extern dtrace_provider_id_t fbt_id; -+ -+extern int fbt_dev_init_arch(void); -+extern void fbt_dev_exit_arch(void); -+ -+extern int fbt_dev_init(void); -+extern void fbt_dev_exit(void); -+ -+#endif /* _FBT_H_ */ -diff --git a/dtrace/fbt_mod.c b/dtrace/fbt_mod.c -new file mode 100644 -index 0000000000000000000000000000000000000000..3da13d71809dcaa907c4473e38047aea1c9f877d ---- /dev/null -+++ b/dtrace/fbt_mod.c -@@ -0,0 +1,56 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: fbt_mod.c -+ * DESCRIPTION: DTrace - FBT provider kernel module -+ * -+ * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/module.h> -+ -+#include "dtrace.h" -+#include "dtrace_dev.h" -+#include "fbt_impl.h" -+ -+MODULE_AUTHOR("Kris Van Hees (kris.van.hees@oracle.com)"); -+MODULE_DESCRIPTION("Function Boundary Tracing"); -+MODULE_VERSION("v0.1"); -+MODULE_LICENSE("GPL"); -+ -+static const struct dtrace_pattr fbt_attr = { -+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA }, -+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_COMMON }, -+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA }, -+}; -+ -+static struct dtrace_pops fbt_pops = { -+ .dtps_provide = NULL, -+ .dtps_provide_module = fbt_provide_module, -+ .dtps_destroy_module = fbt_destroy_module, -+ .dtps_enable = fbt_enable, -+ .dtps_disable = fbt_disable, -+ .dtps_suspend = NULL, -+ .dtps_resume = NULL, -+ .dtps_getargdesc = NULL, -+#ifdef CONFIG_X86_64 -+ .dtps_getargval = fbt_getarg, -+#else -+ .dtps_getargval = NULL, -+#endif -+ .dtps_usermode = NULL, -+ .dtps_destroy = fbt_destroy -+}; -+ -+DT_PROVIDER_MODULE(fbt, DTRACE_PRIV_KERNEL) --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/dtrace-patches/0016-dtrace-arm-arm64-port.patch b/sys-kernel/cairn-sources/files/5.10.14/dtrace-patches/0016-dtrace-arm-arm64-port.patch deleted file mode 100644 index fda507e7c8e9..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/dtrace-patches/0016-dtrace-arm-arm64-port.patch +++ /dev/null @@ -1,2667 +0,0 @@ -From 7448665d4354efd9fafea1149cc2adc31dc98c64 Mon Sep 17 00:00:00 2001 -From: Kris Van Hees <kris.van.hees@oracle.com> -Date: Thu, 8 Nov 2018 18:57:33 +0000 -Subject: [PATCH 16/19] dtrace, arm: arm64 port - -This provides an arm64 implementation of DTrace. - -Signed-off-by: Nick Alcock <nick.alcock@oracle.com> -Signed-off-by: Kris Van Hees <kris.van.hees@oracle.com> -Signed-off-by: Tomas Jedlicka <tomas.jedlicka@oracle.com> -Signed-off-by: Eugene Loh <eugene.loh@oracle.com> -Signed-off-by: David Mc Lean <david.mclean@oracle.com> -Signed-off-by: Vincent Lim <vincent.lim@oracle.com> ---- - arch/arm64/Kconfig | 3 + - arch/arm64/dtrace/Makefile.arch | 17 + - arch/arm64/dtrace/dtrace_asm_arm64.S | 51 +++ - arch/arm64/dtrace/dtrace_isa_arm64.c | 164 +++++++ - arch/arm64/dtrace/fasttrap_arm64.c | 282 ++++++++++++ - arch/arm64/dtrace/fbt_arm64.c | 152 +++++++ - .../dtrace/include/dtrace/fasttrap_arch.h | 30 ++ - arch/arm64/dtrace/include/dtrace/fbt_arch.h | 53 +++ - arch/arm64/dtrace/include/dtrace/sdt_arch.h | 28 ++ - arch/arm64/dtrace/sdt_arm64.c | 122 +++++ - arch/arm64/include/asm/brk-imm.h | 6 + - arch/arm64/include/asm/cpu.h | 1 + - arch/arm64/include/asm/debug-monitors.h | 4 + - arch/arm64/include/asm/dtrace_arch.h | 31 ++ - arch/arm64/include/asm/dtrace_cpuinfo.h | 13 + - arch/arm64/include/asm/dtrace_sdt_arch.h | 15 + - arch/arm64/include/asm/dtrace_syscall.h | 3 + - arch/arm64/include/asm/dtrace_syscall_types.h | 11 + - arch/arm64/include/asm/dtrace_util.h | 14 + - arch/arm64/include/asm/kdebug.h | 11 + - arch/arm64/include/asm/syscall.h | 8 +- - arch/arm64/kernel/dtrace_fbt.c | 187 ++++++++ - arch/arm64/kernel/dtrace_sdt.c | 25 ++ - arch/arm64/kernel/dtrace_syscall.c | 89 ++++ - arch/arm64/kernel/dtrace_syscall_stubs.S | 0 - arch/arm64/kernel/dtrace_util.c | 292 ++++++++++++ - arch/arm64/kernel/entry-common.c | 6 +- - arch/arm64/kernel/entry.S | 53 ++- - arch/arm64/kernel/fbt_blacklist.h | 91 ++++ - arch/arm64/kernel/probes/uprobes.c | 3 +- - arch/arm64/kernel/sys.c | 2 +- - arch/arm64/mm/fault.c | 18 + - include/linux/uprobes.h | 1 + - kernel/events/uprobes.c | 10 + - scripts/dtrace_sdt_arm64.sh | 425 ++++++++++++++++++ - scripts/link-vmlinux.sh | 15 +- - 36 files changed, 2221 insertions(+), 15 deletions(-) - create mode 100644 arch/arm64/dtrace/Makefile.arch - create mode 100644 arch/arm64/dtrace/dtrace_asm_arm64.S - create mode 100644 arch/arm64/dtrace/dtrace_isa_arm64.c - create mode 100644 arch/arm64/dtrace/fasttrap_arm64.c - create mode 100644 arch/arm64/dtrace/fbt_arm64.c - create mode 100644 arch/arm64/dtrace/include/dtrace/fasttrap_arch.h - create mode 100644 arch/arm64/dtrace/include/dtrace/fbt_arch.h - create mode 100644 arch/arm64/dtrace/include/dtrace/sdt_arch.h - create mode 100644 arch/arm64/dtrace/sdt_arm64.c - create mode 100644 arch/arm64/include/asm/dtrace_arch.h - create mode 100644 arch/arm64/include/asm/dtrace_cpuinfo.h - create mode 100644 arch/arm64/include/asm/dtrace_sdt_arch.h - create mode 100644 arch/arm64/include/asm/dtrace_syscall.h - create mode 100644 arch/arm64/include/asm/dtrace_syscall_types.h - create mode 100644 arch/arm64/include/asm/dtrace_util.h - create mode 100644 arch/arm64/include/asm/kdebug.h - create mode 100644 arch/arm64/kernel/dtrace_fbt.c - create mode 100644 arch/arm64/kernel/dtrace_sdt.c - create mode 100644 arch/arm64/kernel/dtrace_syscall.c - create mode 100644 arch/arm64/kernel/dtrace_syscall_stubs.S - create mode 100644 arch/arm64/kernel/dtrace_util.c - create mode 100644 arch/arm64/kernel/fbt_blacklist.h - create mode 100755 scripts/dtrace_sdt_arm64.sh - -diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig -index a6b5b7ef40aea08f036e58d2684f87f378773644..72a0be5f171780292bc9e668b839f15b95860eb6 100644 ---- a/arch/arm64/Kconfig -+++ b/arch/arm64/Kconfig -@@ -323,6 +323,9 @@ config PGTABLE_LEVELS - config ARCH_SUPPORTS_UPROBES - def_bool y - -+config ARCH_SUPPORTS_DTRACE -+ def_bool y -+ - config ARCH_PROC_KCORE_TEXT - def_bool y - -diff --git a/arch/arm64/dtrace/Makefile.arch b/arch/arm64/dtrace/Makefile.arch -new file mode 100644 -index 0000000000000000000000000000000000000000..393b5cea3f7c0af4eb0bb280d1e65b4c468c1f3c ---- /dev/null -+++ b/arch/arm64/dtrace/Makefile.arch -@@ -0,0 +1,17 @@ -+# -+# Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. -+# -+ -+DTARCHDIR = ../arch/arm64/dtrace -+ -+ccflags-y += -I$(srctree)/arch/arm64/dtrace/include -Idtrace -+ -+dtrace-obj += dtrace_asm_arm64.o dtrace_isa_arm64.o -+fasttrap-obj += fasttrap_arm64.o -+fbt-obj += fbt_arm64.o -+sdt-obj += sdt_arm64.o -+ -+dtrace-y += $(addprefix $(DTARCHDIR)/, $(dtrace-obj)) -+fasttrap-y += $(addprefix $(DTARCHDIR)/, $(fasttrap-obj)) -+fbt-y += $(addprefix $(DTARCHDIR)/, $(fbt-obj)) -+sdt-y += $(addprefix $(DTARCHDIR)/, $(sdt-obj)) -diff --git a/arch/arm64/dtrace/dtrace_asm_arm64.S b/arch/arm64/dtrace/dtrace_asm_arm64.S -new file mode 100644 -index 0000000000000000000000000000000000000000..d0f7bad5fb0bc687a1eca65a99582f36834995ce ---- /dev/null -+++ b/arch/arm64/dtrace/dtrace_asm_arm64.S -@@ -0,0 +1,51 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Dynamic Tracing for Linux - ARM64 specific assembly -+ * -+ * Copyright (c) 2017 Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/linkage.h> -+ -+SYM_CODE_START(dtrace_caller) -+ mov x0, #-1 -+ ret -+SYM_CODE_END(dtrace_caller) -+ -+SYM_CODE_START(dtrace_copy) -+ ret -+SYM_CODE_END(dtrace_copy) -+ -+SYM_CODE_START(dtrace_copystr) -+ ret -+SYM_CODE_END(dtrace_copystr) -+ -+SYM_CODE_START(dtrace_fuword8_nocheck) -+ ldrb w0, [x0] -+ ret -+SYM_CODE_END(dtrace_fuword8_nocheck) -+ -+SYM_CODE_START(dtrace_fuword16_nocheck) -+ ldrh w0, [x0] -+ ret -+SYM_CODE_END(dtrace_fuword16_nocheck) -+ -+SYM_CODE_START(dtrace_fuword32_nocheck) -+ ldr w0, [x0] -+ ret -+SYM_CODE_END(dtrace_fuword32_nocheck) -+ -+SYM_CODE_START(dtrace_fuword64_nocheck) -+ ldr x0, [x0] -+ ret -+SYM_CODE_END(dtrace_fuword64_nocheck) -diff --git a/arch/arm64/dtrace/dtrace_isa_arm64.c b/arch/arm64/dtrace/dtrace_isa_arm64.c -new file mode 100644 -index 0000000000000000000000000000000000000000..2eb530149c5b4176b776d673bd3441e8afed8767 ---- /dev/null -+++ b/arch/arm64/dtrace/dtrace_isa_arm64.c -@@ -0,0 +1,164 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_isa_arm64.c -+ * DESCRIPTION: DTrace - arm64 architecture specific support functions -+ * -+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <asm/stacktrace.h> -+#include <linux/ptrace.h> -+ -+#include "dtrace.h" -+ -+uintptr_t _userlimit = 0x0000ffffffffffffLL; -+ -+void dtrace_copyin_arch(uintptr_t uaddr, uintptr_t kaddr, size_t size, -+ volatile uint16_t *flags) -+{ -+} -+ -+void dtrace_copyinstr_arch(uintptr_t uaddr, uintptr_t kaddr, size_t size, -+ volatile uint16_t *flags) -+{ -+} -+ -+void dtrace_copyout(uintptr_t uaddr, uintptr_t kaddr, size_t size, -+ volatile uint16_t *flags) -+{ -+} -+ -+void dtrace_copyoutstr(uintptr_t uaddr, uintptr_t kaddr, size_t size, -+ volatile uint16_t *flags) -+{ -+} -+ -+#define DTRACE_FUWORD(bits) \ -+ uint##bits##_t dtrace_fuword##bits(void *uaddr) \ -+ { \ -+ extern uint##bits##_t dtrace_fuword##bits##_nocheck(void *);\ -+ \ -+ if ((uintptr_t)uaddr > _userlimit) { \ -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); \ -+ this_cpu_core->cpuc_dtrace_illval = (uintptr_t)uaddr; \ -+ } \ -+ \ -+ return dtrace_fuword##bits##_nocheck(uaddr); \ -+ } -+ -+DTRACE_FUWORD(8) -+DTRACE_FUWORD(16) -+DTRACE_FUWORD(32) -+DTRACE_FUWORD(64) -+ -+static int dtrace_unwind_frame(struct task_struct *task, -+ struct stackframe *frame) -+{ -+ unsigned long fp = frame->fp; -+ -+ if (fp & 0xf) -+ return -EINVAL; -+ -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); -+ frame->fp = READ_ONCE_NOCHECK(*(unsigned long *)(fp)); -+ frame->pc = READ_ONCE_NOCHECK(*(unsigned long *)(fp + 8)); -+ DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); -+ -+ if (!frame->fp && !frame->pc) -+ return -EINVAL; -+ -+ return 0; -+} -+ -+uint64_t dtrace_getarg(int argno, int aframes) -+{ -+ uint64_t *st; -+ uint64_t val; -+ int i; -+ struct stackframe frame; -+ struct task_struct *task = current; -+ -+ if (argno < 7) -+ return 0; -+ -+ if (this_cpu_core->cpu_dtrace_regs) -+ st = (uint64_t *)this_cpu_core->cpu_dtrace_regs->regs[29]; -+ else { -+ frame.fp = (unsigned long)__builtin_frame_address(0); -+ frame.pc = (unsigned long)dtrace_getarg; -+ -+ aframes += 1; /* Count this function. */ -+ for (i = 0; i < aframes; i++) { -+ if (dtrace_unwind_frame(task, &frame) < 0) -+ break; -+ } -+ -+ /* -+ * If we cannot traverse the expected number of stack frames, -+ * there is something wrong with the stack. -+ */ -+ if (i < aframes) { -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_BADSTACK); -+ -+ return 0; -+ } -+ -+ st = (uint64_t *)frame.fp; -+ } -+ -+ /* -+ * The first 7 arguments (arg0 through arg6) are passed in registers -+ * to dtrace_probe(). The remaining arguments (arg7 through arg9) are -+ * passed on the stack. -+ * -+ * Stack layout: -+ * bp[0] = pushed fp from caller -+ * bp[1] = return address -+ * bp[2] = 8th argument (arg7 -> argno = 7) -+ * bp[3] = 9th argument (arg8 -> argno = 8) -+ * ... -+ */ -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); -+ val = READ_ONCE_NOCHECK(st[2 + (argno - 7)]); -+ DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); -+ -+ return val; -+} -+ -+ulong_t dtrace_getreg(struct task_struct *task, uint_t reg) -+{ -+ struct pt_regs *rp = task_pt_regs(task); -+ -+ return regs_get_register(rp, reg * sizeof(uint64_t)); -+} -+ -+void pdata_init(struct dtrace_module *pdata, struct module *mp) -+{ -+ /* -+ * Throw away existing data as we don't support reusal at -+ * the moment. -+ */ -+ if (mp->pdata != NULL) -+ pdata_cleanup(pdata, mp); -+ -+ pdata->sdt_tab = NULL; -+ pdata->fbt_tab = NULL; -+} -+ -+void pdata_cleanup(struct dtrace_module *pdata, struct module *mp) -+{ -+ if (pdata->sdt_tab != NULL) -+ dtrace_free_text(pdata->sdt_tab); -+ if (pdata->fbt_tab != NULL) -+ dtrace_free_text(pdata->fbt_tab); -+} -diff --git a/arch/arm64/dtrace/fasttrap_arm64.c b/arch/arm64/dtrace/fasttrap_arm64.c -new file mode 100644 -index 0000000000000000000000000000000000000000..cc970a11412c7934a10ce6fc7453b1ce132bdcea ---- /dev/null -+++ b/arch/arm64/dtrace/fasttrap_arm64.c -@@ -0,0 +1,282 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: fasttrap_arm64.c -+ * DESCRIPTION: DTrace - fasttrap provider implementation for arm64 -+ * -+ * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <asm/insn.h> -+#include <linux/kernel.h> -+#include <linux/slab.h> -+#include <linux/uaccess.h> -+ -+#include "dtrace.h" -+#include "dtrace_dev.h" -+#include "fasttrap_impl.h" -+ -+static int has_jump_table(const asm_instr_t *addr, size_t size) -+{ -+ const asm_instr_t *end = addr + size; -+ -+ while (addr < end) { -+ /* -+ * If we encounter a branch-to-register instruction, we assume -+ * it is part of a jump table implementation. -+ */ -+ if (aarch64_insn_is_br(addr[0])) -+ return 1; -+ -+ addr++; -+ } -+ -+ return 0; -+} -+ -+static uint64_t *fasttrap_all_offsets(asm_instr_t *text, size_t size, -+ uint64_t *np) -+{ -+ uint64_t *offs = NULL; -+ uint64_t noffs; -+ asm_instr_t *instr; -+ asm_instr_t *end; -+ -+ /* -+ * Two passes are taken through this section of code. The first time -+ * around we merely count the number of probe points. The second time, -+ * we actually record their locations. -+ */ -+again: -+ noffs = 0; -+ instr = text; -+ end = text + size; -+ -+ while (instr < end) { -+ if (offs) -+ offs[noffs] = (uint64_t) -+ ((uintptr_t)instr - (uintptr_t)text); -+ noffs++; -+ -+ instr++; -+ } -+ -+ if (offs == NULL) { -+ /* -+ * No matching offsets found - we are done. -+ */ -+ if (noffs == 0) -+ goto fail; -+ -+ /* -+ * We know how many tracepoint locations there are for this -+ * probe, so allocate a member to record them, and kick off the -+ * second pass. -+ */ -+ offs = kmalloc(sizeof(uint64_t) * noffs, GFP_KERNEL); -+ if (!offs) -+ goto fail; -+ -+ goto again; -+ } -+ -+ *np = noffs; -+ -+ return offs; -+ -+fail: -+ *np = 0; -+ kfree(offs); -+ -+ return NULL; -+} -+ -+uint64_t *fasttrap_glob_offsets(struct fasttrap_probe_spec *probe, -+ uint64_t *np) -+{ -+ size_t size = probe->ftps_size; -+ asm_instr_t *text = NULL; -+ asm_instr_t *instr; -+ asm_instr_t *end; -+ uint64_t *offs = NULL; -+ uint64_t noffs; -+ int ret = 0; -+ char ostr[sizeof(instr) * 2 + 1]; /* 2 chars / byte + 1 */ -+ -+ if (!IS_ALIGNED(size, sizeof(instr[0]))) -+ goto fail; -+ -+ text = kmalloc(size, GFP_KERNEL); -+ if (!text) -+ goto fail; -+ -+ ret = dtrace_copy_code(probe->ftps_pid, (uint8_t *)text, -+ probe->ftps_pc, size); -+ if (ret != 0) -+ goto fail; -+ -+ /* -+ * From this point on, size will be a count of instructions rather than -+ * a byte count. We already verified earlier on that it is a multiple -+ * of the instruction size. -+ */ -+ size /= sizeof(instr[0]); -+ -+ if (has_jump_table(text, size)) -+ goto fail; -+ -+ if (probe->ftps_glen == 1 && probe->ftps_gstr[0] == '*') { -+ offs = fasttrap_all_offsets(text, size, &noffs); -+ goto out; -+ } -+ -+ /* -+ * Two passes are taken through this section of code. The first time -+ * around we merely count the number of probe points. The second time, -+ * we actually record their locations. -+ */ -+again: -+ noffs = 0; -+ instr = text; -+ end = text + size; -+ -+ while (instr < end) { -+ uint64_t off = (uint64_t) -+ ((uintptr_t)instr - (uintptr_t)text); -+ -+ snprintf(ostr, sizeof(ostr), "%llx", off); -+ if (dtrace_gmatch(ostr, probe->ftps_gstr)) { -+ if (offs) -+ offs[noffs] = off; -+ noffs++; -+ } -+ -+ instr++; -+ } -+ -+ if (offs == NULL) { -+ /* -+ * No matching offsets found - we are done. -+ */ -+ if (noffs == 0) -+ goto fail; -+ -+ /* -+ * We know how many tracepoint locations there are for this -+ * probe, so allocate member to record them, and kick off the -+ * second pass. -+ */ -+ offs = kmalloc(sizeof(uint64_t) * noffs, GFP_KERNEL); -+ if (!offs) -+ goto fail; -+ -+ goto again; -+ } -+ -+out: -+ kfree(text); -+ -+ *np = noffs; -+ -+ return offs; -+ -+fail: -+ kfree(offs); -+ kfree(text); -+ -+ *np = 0; -+ return NULL; -+} -+ -+uint64_t fasttrap_pid_getarg(void *arg, dtrace_id_t id, void *parg, int argno, -+ int aframes) -+{ -+ struct pt_regs *regs = this_cpu_core->cpu_dtrace_regs; -+ uint64_t *st; -+ uint64_t val; -+ -+ if (regs == NULL) -+ return 0; -+ -+ if (argno < 8) -+ return regs->regs[argno]; -+ -+ pagefault_disable(); -+ st = (uint64_t *)regs->sp; -+ __copy_from_user_inatomic_nocache(&val, (void *)&st[argno - 8], -+ sizeof(st[0])); -+ pagefault_enable(); -+ -+ return val; -+} -+ -+uint64_t fasttrap_usdt_getarg(void *arg, dtrace_id_t id, void *parg, -+ int argno, int aframes) -+{ -+ return fasttrap_pid_getarg(arg, id, parg, argno, aframes); -+} -+ -+static void fasttrap_map_args(struct fasttrap_probe *probe, -+ struct pt_regs *regs, int argc, uintptr_t *argv) -+{ -+ int i, x, cap = min(argc, (int)probe->ftp_nargs); -+ uintptr_t *st = (uintptr_t *)regs->sp; -+ -+ for (i = 0; i < cap; i++) { -+ x = probe->ftp_argmap[i]; -+ -+ if (x < 8) -+ argv[i] = regs->regs[x]; -+ else { -+ pagefault_disable(); -+ __copy_from_user_inatomic_nocache(&argv[i], -+ (void *)&st[x - 8], -+ sizeof(st[0])); -+ pagefault_enable(); -+ } -+ } -+ -+ while (i < argc) -+ argv[i++] = 0; -+} -+ -+void fasttrap_pid_probe_arch(struct fasttrap_probe *ftp, struct pt_regs *regs) -+{ -+ if (ftp->ftp_argmap == NULL) { -+ dtrace_probe(ftp->ftp_id, regs->regs[0], regs->regs[1], -+ regs->regs[2], regs->regs[3], -+ regs->regs[4], regs->regs[5], -+ regs->regs[6]); -+ } else { -+ uintptr_t t[7]; -+ -+ fasttrap_map_args(ftp, regs, sizeof(t) / sizeof(t[0]), t); -+ dtrace_probe(ftp->ftp_id, t[0], t[1], t[2], t[3], -+ t[4], t[5], t[6]); -+ } -+} -+ -+void fasttrap_pid_retprobe_arch(struct fasttrap_probe *ftp, -+ struct pt_regs *regs) -+{ -+ /* -+ * FIXME: The first argument to the probe should be the offset in the -+ * function that the return occurred at, but uprobes doesn't give -+ * us that information (or so it seems). -+ */ -+ dtrace_probe(ftp->ftp_id, 0, regs->regs[0], regs->regs[1], 0, 0, 0, 0); -+} -+ -+void fasttrap_set_enabled(struct pt_regs *regs) -+{ -+ regs->regs[0] = 1; -+} -diff --git a/arch/arm64/dtrace/fbt_arm64.c b/arch/arm64/dtrace/fbt_arm64.c -new file mode 100644 -index 0000000000000000000000000000000000000000..be9dcaf8db28aceb80cb82805407d041c4edced5 ---- /dev/null -+++ b/arch/arm64/dtrace/fbt_arm64.c -@@ -0,0 +1,152 @@ -+/* -+ * FILE: fbt_arm64.c -+ * DESCRIPTION: DTrace - FBT provider implementation for arm64 -+ * -+ * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/dtrace_fbt.h> -+#include <linux/ptrace.h> -+#include <linux/vmalloc.h> -+#include <asm/dtrace_util.h> -+#include <asm/debug-monitors.h> -+ -+#include "dtrace.h" -+#include "dtrace_dev.h" -+#include "fbt_impl.h" -+ -+static int fbt_brk_hook(struct pt_regs *regs, unsigned int esr) -+{ -+ uintptr_t ip = instruction_pointer(regs); -+ struct fbt_probe *fbp = fbt_probetab[FBT_ADDR2NDX(ip)]; -+ -+ for (; fbp != NULL; fbp = fbp->fbp_hashnext) { -+ if ((uintptr_t)fbp->fbp_patchpoint == ip) { -+ struct pt_regs *oregs; -+ -+ oregs = this_cpu_core->cpu_dtrace_regs; -+ this_cpu_core->cpu_dtrace_regs = regs; -+ -+ if (fbp->fbp_roffset == 0) { -+ dtrace_probe(fbp->fbp_id, regs->regs[0], -+ regs->regs[1], regs->regs[2], -+ regs->regs[3], regs->regs[4], -+ regs->regs[5], regs->regs[6]); -+ } else { -+ dtrace_probe(fbp->fbp_id, fbp->fbp_roffset, -+ regs->regs[0], 0, 0, 0, 0, 0); -+ } -+ -+ this_cpu_core->cpu_dtrace_regs = oregs; -+ -+ return DBG_HOOK_HANDLED; -+ } -+ } -+ -+ return DBG_HOOK_ERROR; -+} -+ -+uint64_t fbt_getarg(void *arg, dtrace_id_t id, void *parg, int argno, -+ int aframes) -+{ -+ struct pt_regs *regs = this_cpu_core->cpu_dtrace_regs; -+ uint64_t *st; -+ uint64_t val; -+ -+ if (regs == NULL) -+ regs = current_pt_regs(); -+ -+ if (argno < 8) -+ return regs->regs[argno]; -+ -+ /* -+ * Arguments are passed by register for the first 8 arguments, and the -+ * rest is placed on the stack. The frame pointer (fp) points at the -+ * beginning of the current frame, and the stack pointer (sp) will -+ * point to the end of the frame. Arguments passed by stack are placed -+ * in stack slots at the end of the frame, so at (sp), (sp + 1), etc... -+ */ -+ st = (uint64_t *)regs->sp; -+ -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); -+ val = READ_ONCE_NOCHECK(st[argno - 8]); -+ DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); -+ -+ return 0; -+} -+ -+void fbt_provide_probe_arch(struct fbt_probe *fbp, int type, int stype) -+{ -+ fbp->fbp_patchval = type == FBT_ENTRY ? BRK64_OPCODE_DPROBE_FBE -+ : BRK64_OPCODE_DPROBE_FBR; -+ fbp->fbp_savedval = dtrace_text_peek(fbp->fbp_patchpoint); -+} -+ -+int fbt_can_patch_return_arch(asm_instr_t *addr) -+{ -+ return 1; -+} -+ -+int fbt_provide_module_arch(void *arg, struct module *mp) -+{ -+ return 1; -+} -+ -+void fbt_destroy_module(void *arg, struct module *mp) -+{ -+} -+ -+void fbt_enable_arch(struct fbt_probe *fbp, dtrace_id_t id, void *arg) -+{ -+ dtrace_text_poke(fbp->fbp_patchpoint, fbp->fbp_patchval); -+} -+ -+void fbt_disable_arch(struct fbt_probe *fbp, dtrace_id_t id, void *arg) -+{ -+ dtrace_text_poke(fbp->fbp_patchpoint, fbp->fbp_savedval); -+} -+ -+static struct break_hook dtrace_fbe_break_hook = { -+ .imm = DPROBES_FBE_BRK_IMM, -+ .fn = fbt_brk_hook, -+}; -+ -+static struct break_hook dtrace_fbr_break_hook = { -+ .imm = DPROBES_FBR_BRK_IMM, -+ .fn = fbt_brk_hook, -+}; -+ -+int fbt_dev_init_arch(void) -+{ -+ fbt_probetab_mask = fbt_probetab_size - 1; -+ fbt_probetab = dtrace_vzalloc_try(fbt_probetab_size * -+ sizeof(struct fbt_probe *)); -+ -+ if (fbt_probetab == NULL) -+ return -ENOMEM; -+ -+ dtrace_kernel_brk_start(&dtrace_fbe_break_hook); -+ dtrace_kernel_brk_start(&dtrace_fbr_break_hook); -+ -+ return 0; -+} -+ -+void fbt_dev_exit_arch(void) -+{ -+ dtrace_kernel_brk_stop(&dtrace_fbr_break_hook); -+ dtrace_kernel_brk_stop(&dtrace_fbe_break_hook); -+ -+ vfree(fbt_probetab); -+ fbt_probetab_mask = 0; -+ fbt_probetab_size = 0; -+} -diff --git a/arch/arm64/dtrace/include/dtrace/fasttrap_arch.h b/arch/arm64/dtrace/include/dtrace/fasttrap_arch.h -new file mode 100644 -index 0000000000000000000000000000000000000000..d5ffa6e711dbd015e7958fbf2288afc0b72f50fe ---- /dev/null -+++ b/arch/arm64/dtrace/include/dtrace/fasttrap_arch.h -@@ -0,0 +1,30 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Dynamic Tracing for Linux - Fasttrap provider implementation defines -+ * -+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _ARM64_FASTTRAP_ARCH_H -+#define _ARM64_FASTTRAP_ARCH_H -+ -+#define FASTTRAP_ENTRY_AFRAMES 8 -+#define FASTTRAP_RETURN_AFRAMES 8 -+#define FASTTRAP_OFFSET_AFRAMES 8 -+ -+#endif /* _ARM64_FASTTRAP_ARCH_H */ -diff --git a/arch/arm64/dtrace/include/dtrace/fbt_arch.h b/arch/arm64/dtrace/include/dtrace/fbt_arch.h -new file mode 100644 -index 0000000000000000000000000000000000000000..ed1cd785b3ba277a966ae9c6a15faf17be1a77a7 ---- /dev/null -+++ b/arch/arm64/dtrace/include/dtrace/fbt_arch.h -@@ -0,0 +1,53 @@ -+/* -+ * Dynamic Tracing for Linux - FBT Implementation defines -+ * -+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _ARM64_FBT_ARCH_H -+#define _ARM64_FBT_ARCH_H -+ -+/* -+ * FBT entry probes are triggered from a breakpoint. The following stack trace -+ * illustrates the frames that are involved in the call sequence prior to the -+ * actual FBT provider handler. -+ * -+ * vmlinux`brk_handler+0x70 <- to be skipped -+ * vmlinux`do_debug_exception+0x9c <- to be skipped -+ * vmlinux`el1_sync+0x1d8 <- to be skipped -+ * vmlinux`SyS_read+0x4 -+ * -+ * Therefore, 3 frames need to be skipped. -+ */ -+#define FBT_AFRAMES 3 -+ -+struct fbt_probe { -+ char *fbp_name; /* name of probe */ -+ dtrace_id_t fbp_id; /* probe ID */ -+ struct module *fbp_module; /* defining module */ -+ int fbp_primary; /* non-zero if primary mod */ -+ asm_instr_t *fbp_patchpoint;/* patch point */ -+ asm_instr_t fbp_patchval; /* instruction to patch */ -+ asm_instr_t fbp_savedval; /* saved instruction value */ -+ uint64_t fbp_roffset; /* relative offset */ -+ struct fbt_probe *fbp_next; /* next probe */ -+ struct fbt_probe *fbp_hashnext; /* next on hash */ -+ int fbp_isret; -+}; -+ -+#endif /* _ARM64_FBT_ARCH_H */ -diff --git a/arch/arm64/dtrace/include/dtrace/sdt_arch.h b/arch/arm64/dtrace/include/dtrace/sdt_arch.h -new file mode 100644 -index 0000000000000000000000000000000000000000..237922a77495d960081082c20666afdad3ee569e ---- /dev/null -+++ b/arch/arm64/dtrace/include/dtrace/sdt_arch.h -@@ -0,0 +1,28 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Dynamic Tracing for Linux - SDT Implementation defines -+ * -+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+/* -+ * Note: The contents of this file are private to the implementation of the -+ * DTrace subsystem and are subject to change at any time without notice. -+ */ -+ -+#ifndef _ARM64_SDT_ARCH_H -+#define _ARM64_SDT_ARCH_H -+ -+#define SDT_AFRAMES 1 -+ -+#endif /* _ARM64_SDT_ARCH_H */ -diff --git a/arch/arm64/dtrace/sdt_arm64.c b/arch/arm64/dtrace/sdt_arm64.c -new file mode 100644 -index 0000000000000000000000000000000000000000..ba25824e413ecc22280bcc5aa8e4fa70bad2555f ---- /dev/null -+++ b/arch/arm64/dtrace/sdt_arm64.c -@@ -0,0 +1,122 @@ -+/* -+ * FILE: sdt_arm64.c -+ * DESCRIPTION: DTrace - SDT provider implementation for arm64 -+ * -+ * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. -+ * -+ * 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. -+ */ -+ -+#include <linux/ptrace.h> -+#include <linux/sdt.h> -+#include <asm/debug-monitors.h> -+ -+#include "dtrace.h" -+#include "dtrace_dev.h" -+#include "sdt_impl.h" -+ -+static int sdt_brk_hook(struct pt_regs *regs, unsigned int esr) -+{ -+ uintptr_t ip = instruction_pointer(regs); -+ struct sdt_probe *sdt = sdt_probetab[SDT_ADDR2NDX(ip)]; -+ -+ for (; sdt != NULL; sdt = sdt->sdp_hashnext) { -+ if ((uintptr_t)sdt->sdp_patchpoint == ip) { -+ if (sdt->sdp_ptype == SDTPT_IS_ENABLED) -+ regs->regs[0] = 1; -+ else { -+ this_cpu_core->cpu_dtrace_regs = regs; -+ dtrace_probe(sdt->sdp_id, regs->regs[0], -+ regs->regs[1], regs->regs[2], -+ regs->regs[3], regs->regs[4], -+ regs->regs[5], regs->regs[6]); -+ this_cpu_core->cpu_dtrace_regs = NULL; -+ } -+ -+ instruction_pointer_set(regs, -+ instruction_pointer(regs) + 4); -+ -+ return DBG_HOOK_HANDLED; -+ } -+ } -+ -+ return DBG_HOOK_ERROR; -+} -+ -+void sdt_provide_probe_arch(struct sdt_probe *sdp, struct module *mp, int idx) -+{ -+ sdp->sdp_patchval = BRK64_OPCODE_DPROBE_SDT; -+ sdp->sdp_savedval = dtrace_text_peek(sdp->sdp_patchpoint); -+} -+ -+int sdt_provide_module_arch(void *arg, struct module *mp) -+{ -+ return 1; -+} -+ -+void sdt_destroy_module(void *arg, struct module *mp) -+{ -+} -+ -+void sdt_enable_arch(struct sdt_probe *sdp, dtrace_id_t id, void *arg) -+{ -+ dtrace_text_poke(sdp->sdp_patchpoint, sdp->sdp_patchval); -+} -+ -+void sdt_disable_arch(struct sdt_probe *sdp, dtrace_id_t id, void *arg) -+{ -+ dtrace_text_poke(sdp->sdp_patchpoint, sdp->sdp_savedval); -+} -+ -+static struct break_hook dtrace_sdt_break_hook = { -+ .imm = DPROBES_SDT_BRK_IMM, -+ .fn = sdt_brk_hook, -+}; -+ -+int sdt_dev_init_arch(void) -+{ -+ dtrace_kernel_brk_start(&dtrace_sdt_break_hook); -+ return 0; -+} -+ -+void sdt_dev_exit_arch(void) -+{ -+ dtrace_kernel_brk_stop(&dtrace_sdt_break_hook); -+} -+ -+uint64_t sdt_getarg(void *arg, dtrace_id_t id, void *parg, int argno, -+ int aframes) -+{ -+ struct pt_regs *regs = this_cpu_core->cpu_dtrace_regs; -+ uint64_t *st; -+ uint64_t val; -+ -+ if (regs == NULL) -+ regs = current_pt_regs(); -+ -+ if (argno < 8) -+ return regs->regs[argno]; -+ -+ /* -+ * Arguments are passed by register for the first 8 arguments, and the -+ * rest is placed on the stack. The frame pointer (fp) points at the -+ * beginning of the current frame, and the stack pointer (sp) will -+ * point to the end of the frame. Arguments passed by stack are placed -+ * in stack slots at the end of the frame, so at (sp), (sp + 1), etc... -+ */ -+ st = (uint64_t *)regs->sp; -+ -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); -+ val = READ_ONCE_NOCHECK(st[argno - 8]); -+ DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); -+ -+ return val; -+} -diff --git a/arch/arm64/include/asm/brk-imm.h b/arch/arm64/include/asm/brk-imm.h -index ec7720dbe2c801bc44344d7893cfc510fed7d0d7..405cfb7da5ea39f0bb2ed4a2208fb512ed9129df 100644 ---- a/arch/arm64/include/asm/brk-imm.h -+++ b/arch/arm64/include/asm/brk-imm.h -@@ -11,6 +11,9 @@ - * 0x004: for installing kprobes - * 0x005: for installing uprobes - * 0x006: for kprobe software single-step -+ * 0x007: for installing DTrace SDT probes -+ * 0x008: for installing DTrace function-boundary tracing entry probes -+ * 0x009: for installing DTrace function-boundary tracing return probes - * Allowed values for kgdb are 0x400 - 0x7ff - * 0x100: for triggering a fault on purpose (reserved) - * 0x400: for dynamic BRK instruction -@@ -21,6 +24,9 @@ - #define KPROBES_BRK_IMM 0x004 - #define UPROBES_BRK_IMM 0x005 - #define KPROBES_BRK_SS_IMM 0x006 -+#define DPROBES_SDT_BRK_IMM 0x007 -+#define DPROBES_FBE_BRK_IMM 0x008 -+#define DPROBES_FBR_BRK_IMM 0x009 - #define FAULT_BRK_IMM 0x100 - #define KGDB_DYN_DBG_BRK_IMM 0x400 - #define KGDB_COMPILED_DBG_BRK_IMM 0x401 -diff --git a/arch/arm64/include/asm/cpu.h b/arch/arm64/include/asm/cpu.h -index 7faae6ff3ab4d5c27896305d609494cdb13d54e6..496e8df36b56d85a7616b38a56797ee83500c0dd 100644 ---- a/arch/arm64/include/asm/cpu.h -+++ b/arch/arm64/include/asm/cpu.h -@@ -60,6 +60,7 @@ struct cpuinfo_arm64 { - }; - - DECLARE_PER_CPU(struct cpuinfo_arm64, cpu_data); -+#define cpu_data(cpu) per_cpu(cpu_data, (cpu)) - - void cpuinfo_store_cpu(void); - void __init cpuinfo_store_boot_cpu(void); -diff --git a/arch/arm64/include/asm/debug-monitors.h b/arch/arm64/include/asm/debug-monitors.h -index 657c921fd784a7c12a0e45d814c6bc089f9ca0ec..030756b7e008e52e0e5d8a5ea82521a23ae7045a 100644 ---- a/arch/arm64/include/asm/debug-monitors.h -+++ b/arch/arm64/include/asm/debug-monitors.h -@@ -56,6 +56,10 @@ - #define BRK64_OPCODE_KPROBES_SS (AARCH64_BREAK_MON | (KPROBES_BRK_SS_IMM << 5)) - /* uprobes BRK opcodes with ESR encoding */ - #define BRK64_OPCODE_UPROBES (AARCH64_BREAK_MON | (UPROBES_BRK_IMM << 5)) -+/* DTrace probes BRK opcodes with ESR encoding */ -+#define BRK64_OPCODE_DPROBE_SDT (AARCH64_BREAK_MON | (DPROBES_SDT_BRK_IMM << 5)) -+#define BRK64_OPCODE_DPROBE_FBE (AARCH64_BREAK_MON | (DPROBES_FBE_BRK_IMM << 5)) -+#define BRK64_OPCODE_DPROBE_FBR (AARCH64_BREAK_MON | (DPROBES_FBR_BRK_IMM << 5)) - - /* AArch32 */ - #define DBG_ESR_EVT_BKPT 0x4 -diff --git a/arch/arm64/include/asm/dtrace_arch.h b/arch/arm64/include/asm/dtrace_arch.h -new file mode 100644 -index 0000000000000000000000000000000000000000..89f883e20aa7a4ff816bbd5be125c3afd98ab5ee ---- /dev/null -+++ b/arch/arm64/include/asm/dtrace_arch.h -@@ -0,0 +1,31 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. */ -+ -+#ifndef _ASM_ARM64_DTRACE_ARCH_H -+#define _ASM_ARM64_DTRACE_ARCH_H -+ -+/* Number of argumens stored inside the mstate. */ -+#define DTRACE_MSTATE_ARGS_MAX 7 -+ -+typedef uint32_t asm_instr_t; -+ -+typedef int (*prov_exit_f)(void); -+ -+/* -+ * Structure to hold DTrace specific information about modules (including the -+ * core kernel module). Note that each module (and the main kernel) already -+ * has three fields that relate to probing: -+ * - sdt_probes: description of SDT probes in the module -+ * - sdt_probec: number of SDT probes in the module -+ * - pdata: pointer to a dtrace_module struct (for DTrace) -+ */ -+struct dtrace_module { -+ int enabled_cnt; -+ size_t sdt_probe_cnt; -+ asm_instr_t *sdt_tab; -+ size_t fbt_probe_cnt; -+ asm_instr_t *fbt_tab; -+ prov_exit_f prov_exit; /* Called with module_mutex held */ -+}; -+ -+#endif /* _ASM_ARM64_DTRACE_ARCH_H */ -diff --git a/arch/arm64/include/asm/dtrace_cpuinfo.h b/arch/arm64/include/asm/dtrace_cpuinfo.h -new file mode 100644 -index 0000000000000000000000000000000000000000..4e0ab793c92cd1e757c06754744ce799d14ed72c ---- /dev/null -+++ b/arch/arm64/include/asm/dtrace_cpuinfo.h -@@ -0,0 +1,13 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* Copyright (C) 2018 Oracle, Inc. */ -+ -+#ifndef _ASM_ARM64_DTRACE_CPUINFO_H_ -+#define _ASM_ARM64_DTRACE_CPUINFO_H_ -+ -+#include <asm/cpu.h> -+ -+typedef struct cpuinfo_arm64 cpuinfo_arch_t; -+ -+#define dtrace_cpuinfo_chip(ci) ((ci)->cpu.node_id) -+ -+#endif /* _ASM_ARM64_DTRACE_CPUINFO_H_ */ -diff --git a/arch/arm64/include/asm/dtrace_sdt_arch.h b/arch/arm64/include/asm/dtrace_sdt_arch.h -new file mode 100644 -index 0000000000000000000000000000000000000000..b93a03c215b3f19c6a0ad70353c404bf0a9f1b20 ---- /dev/null -+++ b/arch/arm64/include/asm/dtrace_sdt_arch.h -@@ -0,0 +1,15 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* Copyright (C) 2018 Oracle, Inc. */ -+ -+#ifndef _ASM_ARM64_DTRACE_SDT_ARCH_H -+#define _ASM_ARM64_DTRACE_SDT_ARCH_H -+ -+#include <asm/dtrace_arch.h> -+ -+#define NOP_INSTR 0xd503201f -+#define MOV_INSTR 0xd2800000 /* mov x0, #0x0 - default = false */ -+ -+#define __DTRACE_SDT_ISENABLED_PROTO void -+#define __DTRACE_SDT_ISENABLED_ARGS -+ -+#endif /* _ASM_ARM64_DTRACE_SDT_ARCH_H */ -diff --git a/arch/arm64/include/asm/dtrace_syscall.h b/arch/arm64/include/asm/dtrace_syscall.h -new file mode 100644 -index 0000000000000000000000000000000000000000..402826562478213976f122510d4082af23028fd3 ---- /dev/null -+++ b/arch/arm64/include/asm/dtrace_syscall.h -@@ -0,0 +1,3 @@ -+/* -+ * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. -+ */ -diff --git a/arch/arm64/include/asm/dtrace_syscall_types.h b/arch/arm64/include/asm/dtrace_syscall_types.h -new file mode 100644 -index 0000000000000000000000000000000000000000..88e6eca6e169fb6b1b82aec04a57adc7ac2bdb6b ---- /dev/null -+++ b/arch/arm64/include/asm/dtrace_syscall_types.h -@@ -0,0 +1,11 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+#include <linux/types.h> -+#include <linux/dtrace_types.h> -+ -+typedef asmlinkage long (*dt_sys_call_t)(const struct pt_regs *regs); -+ -+#define DTRACE_SYSCALL_WRAP_PREFIX "__arm64_" -diff --git a/arch/arm64/include/asm/dtrace_util.h b/arch/arm64/include/asm/dtrace_util.h -new file mode 100644 -index 0000000000000000000000000000000000000000..003bd34524d6351d1d9ae569c5703b127e9e6814 ---- /dev/null -+++ b/arch/arm64/include/asm/dtrace_util.h -@@ -0,0 +1,14 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* Copyright (C) 2019, Oracle and/or its affiliates. All rights reserved. */ -+ -+#ifndef _ASM_ARM64_DTRACE_UTIL_H -+#define _ASM_ARM64_DTRACE_UTIL_H -+ -+#include <asm/dtrace_arch.h> -+ -+extern asm_instr_t dtrace_text_peek(asm_instr_t *addr); -+extern void dtrace_text_poke(asm_instr_t *addr, asm_instr_t opcode); -+extern void dtrace_kernel_brk_start(void *arg); -+extern void dtrace_kernel_brk_stop(void *arg); -+ -+#endif /* _ASM_ARM64_DTRACE_UTIL_H */ -diff --git a/arch/arm64/include/asm/kdebug.h b/arch/arm64/include/asm/kdebug.h -new file mode 100644 -index 0000000000000000000000000000000000000000..66c884086d0458ba15ef8f59f0dd50c4b130a52b ---- /dev/null -+++ b/arch/arm64/include/asm/kdebug.h -@@ -0,0 +1,11 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+#ifndef _ARM64_KDEBUG_H -+#define _ARM64_KDEBUG_H -+ -+/* Grossly misnamed. */ -+enum die_val { -+ DIE_OOPS = 1, -+ DIE_PAGE_FAULT, -+}; -+ -+#endif /* _ARM64_KDEBUG_H */ -diff --git a/arch/arm64/include/asm/syscall.h b/arch/arm64/include/asm/syscall.h -index cfc0672013f672aaf77a18b1c2f3a7a5e692266e..1ab1fc22cb8bde23107e4de85419ece0cb66dc48 100644 ---- a/arch/arm64/include/asm/syscall.h -+++ b/arch/arm64/include/asm/syscall.h -@@ -11,7 +11,13 @@ - - typedef long (*syscall_fn_t)(const struct pt_regs *regs); - --extern const syscall_fn_t sys_call_table[]; -+#if IS_ENABLED(CONFIG_DT_SYSTRACE) -+#define CONST_SYS_CALL_TABLE -+#else -+#define CONST_SYS_CALL_TABLE const -+#endif -+ -+extern CONST_SYS_CALL_TABLE syscall_fn_t sys_call_table[]; - - #ifdef CONFIG_COMPAT - extern const syscall_fn_t compat_sys_call_table[]; -diff --git a/arch/arm64/kernel/dtrace_fbt.c b/arch/arm64/kernel/dtrace_fbt.c -new file mode 100644 -index 0000000000000000000000000000000000000000..3761e8aa4550e163e29373d3ce1d3b4f4802f79d ---- /dev/null -+++ b/arch/arm64/kernel/dtrace_fbt.c -@@ -0,0 +1,187 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_fbt.c -+ * DESCRIPTION: Dynamic Tracing: FBT registration code (arch-specific) -+ * -+ * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/kallsyms.h> -+#include <linux/dtrace_os.h> -+#include <linux/dtrace_fbt.h> -+#include <linux/dtrace_task_impl.h> -+#include <linux/slab.h> -+#include <linux/sort.h> -+#include <asm/insn.h> -+#include <asm/sections.h> -+ -+#define FBT_REG_FP 0x1d /* fp is regiater 29 */ -+#define FBT_REG_LR 0x1e /* lr is regiater 30 */ -+#define FBT_REG_SP 0x1f /* sp is register 31 */ -+#define FBT_MOV_FP_SP 0x910003fd /* "mov x29, sp" */ -+ -+#define BL_SENTRY(tp, nm) extern tp nm; -+#define BL_DENTRY(tp, nm) -+#include "fbt_blacklist.h" -+#undef BL_DENTRY -+#undef BL_SENTRY -+ -+static void -+dtrace_fbt_populate_bl(void) -+{ -+#define BL_SENTRY(tp, nm) dtrace_fbt_bl_add((unsigned long)&nm, \ -+ __stringify(nm)); -+#define BL_DENTRY(tp, nm) dtrace_fbt_bl_add(0, __stringify(nm)); -+#include "fbt_blacklist.h" -+#undef BL_SENTRY -+#undef BL_DENTRY -+} -+ -+void dtrace_fbt_init(fbt_add_probe_fn fbt_add_probe, struct module *mp, -+ void *arg) -+{ -+ loff_t pos; -+ struct kallsym_iter sym; -+ asm_instr_t *paddr = NULL; -+ struct dt_fbt_bl_entry *blent = NULL; -+ -+ /* -+ * Look up any unresolved symbols in the blacklist, and sort the list -+ * by ascending address. -+ */ -+ dtrace_fbt_populate_bl(); -+ -+ blent = dtrace_fbt_bl_first(); -+ -+ pos = 0; -+ kallsyms_iter_reset(&sym, 0); -+ while (kallsyms_iter_update(&sym, pos++)) { -+ asm_instr_t *addr, *end; -+ asm_instr_t instr; -+ void *fbtp = NULL; -+ -+ /* -+ * There is no point considering non-function symbols for FBT, -+ * or symbols that have a zero size. We could consider weak -+ * symbols but that gets quite complicated and there is no -+ * demands for that (so far). -+ */ -+ if (sym.type != 'T' && sym.type != 't') -+ continue; -+ if (!sym.size) -+ continue; -+ -+ /* -+ * The symbol must be at a properly aligned text address. -+ */ -+ if (!IS_ALIGNED(sym.value, sizeof(asm_instr_t))) -+ continue; -+ -+ /* -+ * Handle only symbols that belong to the module we have been -+ * asked for. -+ */ -+ if (mp == dtrace_kmod && !core_kernel_text(sym.value)) -+ continue; -+ -+ /* -+ * Ensure we have not been given .init symbol from kallsyms -+ * interface. This could lead to memory corruption once DTrace -+ * tries to enable probe in already freed memory. -+ */ -+ if (mp != dtrace_kmod && !within_module_core(sym.value, mp)) -+ continue; -+ -+ /* -+ * See if the symbol is on the FBT's blacklist. Since both -+ * iterators are workng in sort order by ascending address we -+ * can use concurrent traversal. -+ */ -+ while (blent != NULL && -+ dtrace_fbt_bl_entry_addr(blent) < sym.value) { -+ blent = dtrace_fbt_bl_next(blent); -+ } -+ if (dtrace_fbt_bl_entry_addr(blent) == sym.value) -+ continue; -+ -+ /* -+ * No FBT tracing for DTrace functions, and functions that are -+ * crucial to probe processing. -+ * Also weed out symbols that are not relevant here. -+ */ -+ if (strncmp(sym.name, "dtrace_", 7) == 0) -+ continue; -+ if (strncmp(sym.name, "insn_", 5) == 0) -+ continue; -+ if (strncmp(sym.name, "inat_", 5) == 0) -+ continue; -+ if (strncmp(sym.name, "_GLOBAL_", 8) == 0) -+ continue; -+ if (strncmp(sym.name, "do_", 3) == 0) -+ continue; -+ if (strncmp(sym.name, "xen_", 4) == 0) -+ continue; -+ -+ addr = (asm_instr_t *)sym.value; -+ end = (asm_instr_t *)(sym.value + sym.size); -+ -+ /* -+ * FIXME: -+ * When there are multiple symbols for the same address, we -+ * should link them together as probes associated with the -+ * same function. When a probe for that function is triggered -+ * all associated probes should fire. -+ * -+ * For now, we ignore duplicates. -+ */ -+ if (addr == paddr) -+ continue; -+ paddr = addr; -+ -+ instr = le32_to_cpu(*addr); -+ -+ /* -+ * We can only instrument functions that begin with a proper -+ * frame set-up sequence: -+ * stp x29, x30, [sp,#-80]! -+ * mov x29, sp -+ * So, a STP instruction storing the FP (x29) and LR (x30) -+ * registers as a pair in a location relative to the SP -+ * register value. And then a MOV instruction that sets the -+ * FP (x29) register to the current SP value (effectively -+ * establishing the new stack frame). -+ * -+ * We will place our breakpoint on the MOV instruction. -+ */ -+ if (!aarch64_insn_is_stp_pre(instr) || -+ aarch64_insn_decode_register( -+ AARCH64_INSN_REGTYPE_RN, instr) != FBT_REG_SP || -+ aarch64_insn_decode_register( -+ AARCH64_INSN_REGTYPE_RT, instr) != FBT_REG_FP || -+ aarch64_insn_decode_register( -+ AARCH64_INSN_REGTYPE_RT2, instr) != FBT_REG_LR) -+ continue; -+ -+ addr++; -+ instr = le32_to_cpu(*addr); -+ if (instr != FBT_MOV_FP_SP) -+ continue; -+ -+ fbt_add_probe(mp, sym.name, FBT_ENTRY, instr, addr, 0, NULL, -+ arg); -+ -+ while (++addr < end) { -+ uintptr_t off; -+ -+ instr = le32_to_cpu(*addr); -+ if (!aarch64_insn_is_ret(instr)) -+ continue; -+ -+ off = (uintptr_t)addr - sym.value; -+ fbtp = fbt_add_probe(mp, sym.name, FBT_RETURN, instr, -+ addr, off, fbtp, arg); -+ } -+ } -+} -+EXPORT_SYMBOL(dtrace_fbt_init); -diff --git a/arch/arm64/kernel/dtrace_sdt.c b/arch/arm64/kernel/dtrace_sdt.c -new file mode 100644 -index 0000000000000000000000000000000000000000..d5a6a9d398b3b9a36711a2417dc82324db332ed5 ---- /dev/null -+++ b/arch/arm64/kernel/dtrace_sdt.c -@@ -0,0 +1,25 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_sdt.c -+ * DESCRIPTION: Dynamic Tracing: SDT registration code (arch-specific) -+ * -+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+#include <linux/module.h> -+#include <asm/insn.h> -+#include <asm/dtrace_arch.h> -+#include <asm/dtrace_sdt_arch.h> -+ -+void __init_or_module dtrace_sdt_nop_multi(asm_instr_t **addrs, -+ int *is_enabled, int cnt) -+{ -+ int i; -+ -+ for (i = 0; i < cnt; i++) { -+ if (likely(!is_enabled[i])) -+ aarch64_insn_patch_text_nosync(addrs[i], NOP_INSTR); -+ else -+ aarch64_insn_patch_text_nosync(addrs[i], MOV_INSTR); -+ } -+} -diff --git a/arch/arm64/kernel/dtrace_syscall.c b/arch/arm64/kernel/dtrace_syscall.c -new file mode 100644 -index 0000000000000000000000000000000000000000..73730e42f3b8d1ac9d492a5746beb46c43ccc01f ---- /dev/null -+++ b/arch/arm64/kernel/dtrace_syscall.c -@@ -0,0 +1,89 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_syscall.c -+ * DESCRIPTION: Dynamic Tracing: system call tracing support (arch-specific) -+ * -+ * Copyright (C) 2010, 2018 Oracle Corporation -+ */ -+ -+#include <linux/dtrace_syscall.h> -+#include <linux/ptrace.h> -+#include <asm/syscall.h> -+ -+void (*systrace_probe)(dtrace_id_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t, -+ uintptr_t, uintptr_t, uintptr_t); -+ -+void systrace_stub(dtrace_id_t id, uintptr_t arg0, uintptr_t arg1, -+ uintptr_t arg2, uintptr_t arg3, uintptr_t arg4, -+ uintptr_t arg5, uintptr_t arg6) -+{ -+} -+ -+asmlinkage long systrace_syscall(const struct pt_regs *regs); -+ -+static struct systrace_info systrace_info = { -+ &systrace_probe, -+ systrace_stub, -+ systrace_syscall, -+ {}, -+ { -+#undef __SYSCALL -+#define __SYSCALL(nr, sym) [nr] { .name = __stringify(sym), }, -+#include <asm/unistd.h> -+#undef __SYSCALL -+ } -+ }; -+ -+ -+asmlinkage long systrace_syscall(const struct pt_regs *regs) -+{ -+ long rc = 0; -+ unsigned long sysnum; -+ dtrace_id_t id; -+ struct dtrace_syscalls *sc; -+ -+ sysnum = syscall_get_nr(current, (struct pt_regs *) regs); -+ sc = &systrace_info.sysent[sysnum]; -+ -+ id = sc->stsy_entry; -+ /* TODO: arg 6. */ -+ if (id != DTRACE_IDNONE) -+ (*systrace_probe)(id, regs->regs[0], regs->regs[1], -+ regs->regs[2], regs->regs[3], regs->regs[4], -+ regs->regs[5], 0); -+ -+ /* -+ * FIXME: Add stop functionality for DTrace. -+ */ -+ -+ if (sc->stsy_underlying != NULL) -+ rc = (*sc->stsy_underlying)(regs); -+ -+ id = sc->stsy_return; -+ if (id != DTRACE_IDNONE) -+ (*systrace_probe)(id, (uintptr_t)rc, (uintptr_t)rc, -+ (uintptr_t)((uint64_t)rc >> 32), 0, 0, 0, 0); -+ -+ return rc; -+} -+ -+struct systrace_info *dtrace_syscalls_init() -+{ -+ int i; -+ -+ /* -+ * Only initialize this stuff once... -+ */ -+ if (systrace_info.sysent[0].stsy_tblent != NULL) -+ return &systrace_info; -+ -+ for (i = 0; i < NR_syscalls; i++) { -+ systrace_info.sysent[i].stsy_tblent = -+ (dt_sys_call_t *)&sys_call_table[i]; -+ systrace_info.sysent[i].stsy_underlying = -+ (dt_sys_call_t)sys_call_table[i]; -+ } -+ -+ return &systrace_info; -+} -+EXPORT_SYMBOL(dtrace_syscalls_init); -diff --git a/arch/arm64/kernel/dtrace_syscall_stubs.S b/arch/arm64/kernel/dtrace_syscall_stubs.S -new file mode 100644 -index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 -diff --git a/arch/arm64/kernel/dtrace_util.c b/arch/arm64/kernel/dtrace_util.c -new file mode 100644 -index 0000000000000000000000000000000000000000..8142cf0459c28781f3b7ad981ac470e4425941fc ---- /dev/null -+++ b/arch/arm64/kernel/dtrace_util.c -@@ -0,0 +1,292 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * FILE: dtrace_util.c -+ * DESCRIPTION: Dynamic Tracing: Architecture utility functions -+ * -+ * Copyright (c) 2010, 2019, Oracle and/or its affiliates. All rights reserved. -+ */ -+ -+#include <linux/dtrace_cpu.h> -+#include <linux/dtrace_os.h> -+#include <linux/dtrace_task_impl.h> -+#include <linux/kdebug.h> -+#include <linux/notifier.h> -+#include <linux/ptrace.h> -+#include <linux/uaccess.h> -+#include <linux/uprobes.h> -+#include <asm/debug-monitors.h> -+#include <asm/insn.h> -+ -+void dtrace_skip_instruction(struct pt_regs *regs) -+{ -+ instruction_pointer_set(regs, instruction_pointer(regs) + 4); -+} -+ -+void dtrace_handle_badaddr(struct pt_regs *regs) -+{ -+ unsigned long addr = current->thread.fault_address; -+ -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); -+ this_cpu_core->cpuc_dtrace_illval = addr; -+ -+ dtrace_skip_instruction(regs); -+} -+ -+int dtrace_die_notifier(struct notifier_block *nb, unsigned long val, -+ void *args) -+{ -+ struct die_args *dargs = args; -+ -+ switch (val) { -+ case DIE_PAGE_FAULT: { -+ if (!DTRACE_CPUFLAG_ISSET(CPU_DTRACE_NOFAULT)) -+ return NOTIFY_DONE; -+ -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); -+ this_cpu_core->cpuc_dtrace_illval = dargs->err; -+ -+ dtrace_skip_instruction(dargs->regs); -+ -+ return NOTIFY_OK | NOTIFY_STOP_MASK; -+ } -+ case DIE_OOPS: { -+ pr_info("DTrace: last probe %u\n", -+ this_cpu_core->cpuc_current_probe); -+ return NOTIFY_DONE; -+ } -+ default: -+ return NOTIFY_DONE; -+ } -+} -+ -+struct user_stackframe { -+ struct user_stackframe __user *fp; -+ unsigned long lr; -+} __packed; -+ -+static int dtrace_unwind_frame(struct user_stackframe *frame) -+{ -+ struct user_stackframe __user *ofp = frame->fp; -+ unsigned long ret; -+ -+ /* Verify alignment. */ -+ if ((unsigned long)ofp & 0xf) -+ return -EINVAL; -+ -+ /* Verify read access. */ -+ if (!access_ok(ofp, sizeof(struct user_stackframe))) -+ return -EINVAL; -+ -+ pagefault_disable(); -+ ret = __copy_from_user_inatomic(frame, ofp, -+ sizeof(struct user_stackframe)); -+ pagefault_enable(); -+ -+ /* Make sure the read worked. */ -+ if (ret) { -+ frame->fp = ofp; -+ return -EINVAL; -+ } -+ -+ /* -+ * If the frame pointer in the current frame is NULL, we have reached -+ * the end of the call chain. -+ */ -+ if (frame->fp == NULL) -+ return 0; -+ -+ /* -+ * In older glibc versions, the call chain did not end with an initial -+ * frame with NULL frame pointer. Instead, the initial frame stored -+ * the beginning of the stack as frame pointer. We look for that here -+ * as a special case, and return a frame where the frame pointer is -+ * set to NULL (as it ought to be). -+ * -+ * If we do not know the beginning of the stack, we are out of luck. -+ */ -+ if (current->dt_task && current->dt_task->dt_ustack == frame->fp) { -+ frame->fp = NULL; -+ return 0; -+ } -+ -+ /* -+ * Verify strictly increasing consecutive values. Since the stack -+ * grows downward, walking the call chain in reverse must yield ever -+ * increasing frame pointers. -+ */ -+ if (ofp >= frame->fp) -+ return -EINVAL; -+ -+ return 0; -+} -+ -+void dtrace_user_stacktrace(struct stacktrace_state *st) -+{ -+ struct pt_regs *regs = current_pt_regs(); -+ uint64_t *pcs = st->pcs; -+ int limit = st->limit; -+ int fixups, patches, skip; -+ struct user_stackframe frame0, frame; -+ struct user_stackframe *bos = current->dt_task -+ ? current->dt_task->dt_ustack -+ : NULL; -+ struct return_instance *rilist = current->utask -+ ? current->utask->return_instances -+ : NULL; -+ struct return_instance *ri; -+ -+ /* -+ * If we do not have user-mode registers, or if there is no known -+ * bottom of stack, we cannot collect a call chain. -+ */ -+ if (!user_mode(regs)) -+ goto out; -+ if (!bos) -+ goto out; -+ if (!limit) -+ goto out; -+ -+ frame0.fp = (struct user_stackframe __user *)regs->regs[29]; -+ frame0.lr = regs->regs[30]; -+ -+ /* -+ * The first special situation we need to deal with here is the rare -+ * case of tracing the instruction after a call, when the current -+ * program counter just got loaded from the link register, i.e. they -+ * will be the same. In that case, we don't want to record both pc -+ * and lr in the trace. -+ * -+ * Uretprobes are also tricky because if we are asked to provide a -+ * ustack() while processing a uretprobe firing, we are still in the -+ * middle of handling the probe. Things are not back to normal yet. -+ */ -+ if (regs->pc != frame0.lr) { -+ ri = rilist; -+ if (pcs) { -+ if (uprobe_return_addr_is_hijacked(frame0.lr) && -+ ri && ri->orig_ret_vaddr == regs->pc) -+ *pcs++ = ri->func; -+ else -+ *pcs++ = regs->pc; -+ } -+ -+ limit--; -+ st->depth++; -+ -+ if (!limit) -+ goto out; -+ } -+ -+ /* -+ * First pass: determine how many return addresses need to be fixed up, -+ * and how many return instances we have. -+ */ -+ frame = frame0; -+ fixups = 0; -+ do { -+ if (uprobe_return_addr_is_hijacked(frame.lr)) -+ fixups++; -+ -+ if (frame.fp == NULL) -+ break; -+ -+ if (dtrace_unwind_frame(&frame) < 0) { -+ this_cpu_core->cpuc_dtrace_illval = (uintptr_t)frame.fp; -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_BADSTACK); -+ break; -+ } -+ } while (frame.lr); -+ -+ patches = 0; -+ for (ri = rilist; ri != NULL; ri = ri->next) -+ patches++; -+ -+ /* -+ * It is possible that we think we need one more fixup than we can -+ * satisfy with the return instances. This is because we cannot quite -+ * determine whether the first one is actually needed or not (due to -+ * lack of proper state when the uretprobe implementation interferes -+ * with frame chain walking). -+ */ -+ skip = fixups - patches; -+ if (skip > 1) { -+ this_cpu_core->cpuc_dtrace_illval = 0; -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_BADSTACK); -+ goto out; -+ } -+ -+ /* -+ * Second pass: fill in the actual stack trace. -+ */ -+ frame = frame0; -+ ri = rilist; -+ do { -+ if (uprobe_return_addr_is_hijacked(frame.lr)) { -+ if (skip) { -+ skip = 0; -+ goto skip_frame; -+ } -+ -+ frame.lr = ri->orig_ret_vaddr; -+ ri = ri->next; -+ } -+ -+ if (pcs) -+ *pcs++ = frame.lr; -+ -+ limit--; -+ st->depth++; -+ -+skip_frame: -+ if (frame.fp == NULL) -+ break; -+ -+ if (dtrace_unwind_frame(&frame) < 0) { -+ this_cpu_core->cpuc_dtrace_illval = (uintptr_t)frame.fp; -+ DTRACE_CPUFLAG_SET(CPU_DTRACE_BADSTACK); -+ break; -+ } -+ } while (limit); -+ -+out: -+ if (pcs) { -+ while (limit--) -+ *pcs++ = 0; -+ } -+} -+ -+asm_instr_t dtrace_text_peek(asm_instr_t *addr) -+{ -+ asm_instr_t opcode; -+ -+ aarch64_insn_read(addr, &opcode); -+ -+ return opcode; -+} -+EXPORT_SYMBOL(dtrace_text_peek); -+ -+void dtrace_text_poke(asm_instr_t *addr, asm_instr_t opcode) -+{ -+ aarch64_insn_patch_text_nosync(addr, opcode); -+} -+EXPORT_SYMBOL(dtrace_text_poke); -+ -+void dtrace_kernel_brk_start(void *arg) -+{ -+ register_kernel_break_hook((struct break_hook *)arg); -+} -+EXPORT_SYMBOL(dtrace_kernel_brk_start); -+ -+void dtrace_kernel_brk_stop(void *arg) -+{ -+ unregister_kernel_break_hook((struct break_hook *)arg); -+} -+EXPORT_SYMBOL(dtrace_kernel_brk_stop); -+ -+void dtrace_mod_pdata_init(struct dtrace_module *pdata) -+{ -+} -+ -+void dtrace_mod_pdata_cleanup(struct dtrace_module *pdata) -+{ -+} -diff --git a/arch/arm64/kernel/entry-common.c b/arch/arm64/kernel/entry-common.c -index 70e0a7591245d6a1cc1ec07c3e13a3d8e10f95e7..b4f8280d9ce322099393bde54afd382f9f412560 100644 ---- a/arch/arm64/kernel/entry-common.c -+++ b/arch/arm64/kernel/entry-common.c -@@ -199,8 +199,7 @@ static void noinstr el1_fpac(struct pt_regs *regs, unsigned long esr) - local_daif_mask(); - exit_to_kernel_mode(regs); - } -- --asmlinkage void noinstr el1_sync_handler(struct pt_regs *regs) -+asmlinkage int noinstr el1_sync_handler(struct pt_regs *regs) - { - unsigned long esr = read_sysreg(esr_el1); - -@@ -225,13 +224,14 @@ asmlinkage void noinstr el1_sync_handler(struct pt_regs *regs) - case ESR_ELx_EC_WATCHPT_CUR: - case ESR_ELx_EC_BRK64: - el1_dbg(regs, esr); -- break; -+ return 1; - case ESR_ELx_EC_FPAC: - el1_fpac(regs, esr); - break; - default: - el1_inv(regs, esr); - } -+ return 0; - } - - asmlinkage void noinstr enter_from_user_mode(void) -diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S -index d72c818b019ca7530569fd810f356ad426f0cdf1..6ac1846a645e428f5d1ab629ca91b8b471ee36de 100644 ---- a/arch/arm64/kernel/entry.S -+++ b/arch/arm64/kernel/entry.S -@@ -28,6 +28,7 @@ - #include <asm/thread_info.h> - #include <asm/asm-uaccess.h> - #include <asm/unistd.h> -+#include <asm/debug-monitors.h> - - /* - * Context tracking and irqflag tracing need to instrument transitions between -@@ -276,7 +277,7 @@ alternative_else_nop_endif - */ - .endm - -- .macro kernel_exit, el -+ .macro kernel_exit, el, fbt_emu = 0 - .if \el != 0 - disable_daif - -@@ -332,7 +333,11 @@ alternative_else_nop_endif - - msr elr_el1, x21 // set up the return data - msr spsr_el1, x22 -- ldp x0, x1, [sp, #16 * 0] -+ -+ /* -+ * No need to restore x0 and x1 - we may still clobber them. We will -+ * restore them right before we return. -+ */ - ldp x2, x3, [sp, #16 * 1] - ldp x4, x5, [sp, #16 * 2] - ldp x6, x7, [sp, #16 * 3] -@@ -348,7 +353,44 @@ alternative_else_nop_endif - ldp x26, x27, [sp, #16 * 13] - ldp x28, x29, [sp, #16 * 14] - ldr lr, [sp, #S_LR] -+ -+ .if \fbt_emu != 0 // FBT emulation needed? -+ mrs x0, esr_el1 // check if ESR is FBT probe -+ and x0, x0, #0x1f // ... mask code -+ cmp x0, #DPROBES_FBE_BRK_IMM // ... compare with FBE code -+ beq 6f // FBT entry -> emulate instr. -+ cmp x0, #DPROBES_FBR_BRK_IMM // ... compare with FBR code -+ beq 7f // FBT return -> emulate instr. -+ b 8f // not FBT -> skip next section -+ -+6: -+ mrs x0, elr_el1 // retrieve xeceptionx link reg -+ add x0, x0, #0x4 // advance to next instr -+ msr elr_el1, x0 // set exception link reg -+ -+ ldp x0, x1, [sp, #16 * 0] // done with x0, restore orig - add sp, sp, #S_FRAME_SIZE // restore sp -+ mov x29, sp // instr we put probe on -+ b 9f // FBT done -> branch to eret -+ -+7: -+ msr elr_el1, lr // set exception link reg to -+ // link register value, to -+ // simulate the 'ret' instr. -+ -+ ldp x0, x1, [sp, #16 * 0] // done with x0, restore orig -+ add sp, sp, #S_FRAME_SIZE // restore sp -+ b 9f // FBT done -> branch to eret -+ -+8: -+ ldp x0, x1, [sp, #16 * 0] // done with x0, restore orig -+ add sp, sp, #S_FRAME_SIZE // restore sp -+9: -+ .else -+ ldp x0, x1, [sp, #16 * 0] // done with x0, restore orig -+ add sp, sp, #S_FRAME_SIZE // restore sp -+ -+ .endif - - .if \el == 0 - alternative_insn eret, nop, ARM64_UNMAP_KERNEL_AT_EL0 -@@ -625,7 +667,12 @@ SYM_CODE_START_LOCAL_NOALIGN(el1_sync) - kernel_entry 1 - mov x0, sp - bl el1_sync_handler -- kernel_exit 1 -+#if IS_ENABLED(CONFIG_DT_FBT) -+ cmp x0, 1 -+ b.ne 1020f -+ kernel_exit 1, 1 -+#endif -+1020: kernel_exit 1 - SYM_CODE_END(el1_sync) - - .align 6 -diff --git a/arch/arm64/kernel/fbt_blacklist.h b/arch/arm64/kernel/fbt_blacklist.h -new file mode 100644 -index 0000000000000000000000000000000000000000..7ad327515c8f9e2b35097f44fa4d1f0bcf76aaa2 ---- /dev/null -+++ b/arch/arm64/kernel/fbt_blacklist.h -@@ -0,0 +1,91 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Functions used in die notifier chain calling. -+ */ -+BL_SENTRY(void *, notify_die) -+BL_DENTRY(void *, notifier_call_chain) -+BL_SENTRY(typeof(atomic_notifier_call_chain_robust), atomic_notifier_call_chain_robust) -+BL_SENTRY(typeof(atomic_notifier_call_chain), atomic_notifier_call_chain) -+BL_SENTRY(typeof(raw_notifier_call_chain_robust), raw_notifier_call_chain_robust) -+BL_SENTRY(typeof(raw_notifier_call_chain), raw_notifier_call_chain) -+BL_DENTRY(void *, hw_breakpoint_exceptions_notify) -+BL_DENTRY(void *, kprobe_exceptions_notify) -+ -+/* -+ * Functions used to update vtime in probe context. -+ */ -+BL_SENTRY(typeof(ktime_get_raw_fast_ns), ktime_get_raw_fast_ns) -+BL_DENTRY(void *, raw_read_seqcount) -+BL_DENTRY(void *, read_seqcount_retry) -+BL_DENTRY(void *, __read_seqcount_retry) -+ -+/* xen_clocksource */ -+BL_DENTRY(void *, xen_clocksource_get_cycles) -+BL_DENTRY(void *, xen_clocksource_read) -+BL_DENTRY(void *, pvclock_clocksource_read) -+BL_DENTRY(void *, pvclock_touch_watchdogs) -+BL_DENTRY(void *, touch_softlockup_watchdog_sync) -+BL_DENTRY(void *, clocksource_touch_watchdog) -+BL_DENTRY(void *, clocksource_resume_watchdog) -+BL_DENTRY(void *, reset_hung_task_detector) -+/* clocksource_tsc */ -+BL_DENTRY(void *, read_tsc) -+BL_DENTRY(void *, get_cycles) -+/* clocksource_hpet */ -+BL_DENTRY(void *, read_hpet) -+BL_DENTRY(void *, hpet_readl) -+/* kvm_clock */ -+BL_DENTRY(void *, kvm_clock_get_cycles) -+BL_DENTRY(void *, kvm_clock_read) -+/* arm_arch */ -+BL_DENTRY(void *, arch_counter_get_cntvct); -+BL_DENTRY(void *, arch_counter_get_cntvct_mem); -+BL_DENTRY(void *, arch_counter_get_cntpct); -+BL_DENTRY(void *, arch_counter_read); -+ -+/* -+ * Functions used in trap handling. -+ */ -+BL_DENTRY(void *, fixup_exception) -+BL_DENTRY(void *, paranoid_entry) -+BL_DENTRY(void *, kgdb_ll_trap) -+BL_DENTRY(void *, error_entry) -+BL_DENTRY(void *, xen_int3) -+BL_DENTRY(void *, ftrace_int3_handler) -+BL_DENTRY(typeof(poke_int3_handler), poke_int3_handler) -+BL_DENTRY(void *, fixup_bad_iret) -+BL_DENTRY(void *, xen_adjust_exception_frame) -+BL_DENTRY(void *, paravirt_nop) -+BL_DENTRY(void *, ist_enter) -+BL_DENTRY(void *, rcu_nmi_enter) -+BL_DENTRY(void *, rcu_dynticks_curr_cpu_in_eqs) -+BL_DENTRY(void *, rcu_dynticks_eqs_exit) -+BL_DENTRY(void *, rcu_nmi_exit) -+BL_DENTRY(void *, rcu_dynticks_eqs_enter) -+BL_DENTRY(void *, ist_exit) -+ -+/* -+ * Functions used in page fault handling. -+ */ -+BL_DENTRY(void *, do_page_fault) -+BL_DENTRY(void *, __do_page_fault) -+BL_DENTRY(void *, down_read_trylock) -+BL_DENTRY(void *, __get_user_pages_fast) -+BL_DENTRY(void *, gup_pud_range) -+BL_DENTRY(void *, gup_huge_pud) -+BL_DENTRY(void *, gup_pmd_range) -+BL_DENTRY(void *, gup_huge_pmd) -+BL_DENTRY(void *, gup_pte_range) -+BL_DENTRY(void *, pte_mfn_to_pfn) -+ -+/* -+ * Functions used under 4.19 idr_find -+ */ -+BL_DENTRY(void *, idr_find) -+BL_DENTRY(void *, find_next_bit) -+BL_DENTRY(void *, _find_next_bit) -+BL_DENTRY(void *, radix_tree_lookup) -+BL_DENTRY(void *, __radix_tree_lookup) -+BL_DENTRY(void *, radix_tree_load_root) -+BL_DENTRY(void *, radix_tree_descend) -+BL_DENTRY(void *, is_sibling_entry) -diff --git a/arch/arm64/kernel/probes/uprobes.c b/arch/arm64/kernel/probes/uprobes.c -index a412d8edbcd24428150a16e93ae059d45817b355..49482af77b9f2d698cffc8c1cd8a64c128aa271a 100644 ---- a/arch/arm64/kernel/probes/uprobes.c -+++ b/arch/arm64/kernel/probes/uprobes.c -@@ -179,7 +179,8 @@ static int uprobe_single_step_handler(struct pt_regs *regs, - { - struct uprobe_task *utask = current->utask; - -- WARN_ON(utask && (instruction_pointer(regs) != utask->xol_vaddr + 4)); -+ WARN_ON(utask && utask->active_uprobe && -+ (instruction_pointer(regs) != utask->xol_vaddr + 4)); - if (uprobe_post_sstep_notifier(regs)) - return DBG_HOOK_HANDLED; - -diff --git a/arch/arm64/kernel/sys.c b/arch/arm64/kernel/sys.c -index d5ffaaab31a7d1ed433e8e7bf01ae1f52848cd22..4563f0a4d0db806c52c29c80ff7eb47f75d35b04 100644 ---- a/arch/arm64/kernel/sys.c -+++ b/arch/arm64/kernel/sys.c -@@ -55,7 +55,7 @@ asmlinkage long __arm64_sys_ni_syscall(const struct pt_regs *__unused) - #undef __SYSCALL - #define __SYSCALL(nr, sym) [nr] = __arm64_##sym, - --const syscall_fn_t sys_call_table[__NR_syscalls] = { -+CONST_SYS_CALL_TABLE syscall_fn_t sys_call_table[__NR_syscalls] = { - [0 ... __NR_syscalls - 1] = __arm64_sys_ni_syscall, - #include <asm/unistd.h> - }; -diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c -index 795d224f184ff2ce63d8427f5e70d4a9a89fd4ef..d2725a8ac9f321e4f551b907e6cacbbddc88bcd3 100644 ---- a/arch/arm64/mm/fault.c -+++ b/arch/arm64/mm/fault.c -@@ -14,6 +14,7 @@ - #include <linux/mm.h> - #include <linux/hardirq.h> - #include <linux/init.h> -+#include <linux/kdebug.h> - #include <linux/kprobes.h> - #include <linux/uaccess.h> - #include <linux/page-flags.h> -@@ -60,6 +61,19 @@ static inline const struct fault_info *esr_to_debug_fault_info(unsigned int esr) - return debug_fault_info + DBG_ESR_EVT(esr); - } - -+#ifdef CONFIG_DTRACE -+static int dtrace_fault(struct pt_regs *regs, unsigned long addr) -+{ -+ preempt_disable(); -+ if (notify_die(DIE_PAGE_FAULT, "page fault", regs, addr, 14, -+ SIGKILL) == NOTIFY_STOP) -+ return 1; -+ preempt_enable(); -+ -+ return 0; -+} -+#endif -+ - static void data_abort_decode(unsigned int esr) - { - pr_alert("Data abort info:\n"); -@@ -459,6 +473,10 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr, - - if (kprobe_page_fault(regs, esr)) - return 0; -+#ifdef CONFIG_DTRACE -+ if (dtrace_fault(regs, addr)) -+ return 0; -+#endif - - /* - * If we're in an interrupt or have no user context, we must not take -diff --git a/include/linux/uprobes.h b/include/linux/uprobes.h -index f46e0ca0169c722b4d5b749b2c1b0b04ab79c380..b278859820665f0fbe0509e27582fd1de41332e1 100644 ---- a/include/linux/uprobes.h -+++ b/include/linux/uprobes.h -@@ -124,6 +124,7 @@ extern void uprobe_copy_process(struct task_struct *t, unsigned long flags); - extern int uprobe_post_sstep_notifier(struct pt_regs *regs); - extern int uprobe_pre_sstep_notifier(struct pt_regs *regs); - extern void uprobe_notify_resume(struct pt_regs *regs); -+extern bool uprobe_return_addr_is_hijacked(unsigned long addr); - extern bool uprobe_deny_signal(void); - extern bool arch_uprobe_skip_sstep(struct arch_uprobe *aup, struct pt_regs *regs); - extern void uprobe_clear_state(struct mm_struct *mm); -diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c -index 00b0358739ab3b6b66b780e20f3374bbef4d4d34..5a7a1c0198708f54175fe6de9d3fb12d0146a3c7 100644 ---- a/kernel/events/uprobes.c -+++ b/kernel/events/uprobes.c -@@ -1845,6 +1845,16 @@ static unsigned long get_trampoline_vaddr(void) - return trampoline_vaddr; - } - -+/* -+ * Verify whether a return address is a trampoline address or a regular return -+ * address. This is used by stack unwinders to determine whether a return -+ * address in a stack trace needs to be adjusted. -+ */ -+bool uprobe_return_addr_is_hijacked(unsigned long addr) -+{ -+ return addr == get_trampoline_vaddr(); -+} -+ - static void cleanup_return_instances(struct uprobe_task *utask, bool chained, - struct pt_regs *regs) - { -diff --git a/scripts/dtrace_sdt_arm64.sh b/scripts/dtrace_sdt_arm64.sh -new file mode 100755 -index 0000000000000000000000000000000000000000..a8fdc4ae0bc440e2ad9ad3a09f804a2ea9fd21c6 ---- /dev/null -+++ b/scripts/dtrace_sdt_arm64.sh -@@ -0,0 +1,425 @@ -+#!/bin/sh -+ -+LANG=C -+export LANG -+ -+# -+# Syntax: -+# dtrace_sdt_arm64.sh sdtinfo <S-file> <l-file> <o-file> -+# This is used to generate DTrace SDT probe definitions for a -+# linked kernel image file <l-file>, based on relocation info -+# from the kernel object file <o-file>. The output is written -+# to <S-file>. -+# -+ -+opr="$1" -+shift -+if [ -z "$opr" ]; then -+ echo "ERROR: Missing operation" > /dev/stderr -+ exit 1 -+elif [ "$opr" != "sdtinfo" ]; then -+ echo "ERROR: Invalid operation: ${opr}" > /dev/stderr -+ exit 1 -+fi -+ -+tfn="$1" -+shift -+if [ -z "$tfn" ]; then -+ echo "ERROR: Missing target filename" > /dev/stderr -+ exit 1 -+fi -+ -+lfn="$1" -+ofn="$2" -+ -+if [ -z "$lfn" ]; then -+ echo "ERROR: Missing linked kernel file argument" > /dev/stderr -+ exit 1 -+elif [ -z "$ofn" ]; then -+ echo "ERROR: Missing kernel object file argument" > /dev/stderr -+ exit 1 -+fi -+ -+# For arm64, the kernel is built using "-ffunction-sections -fdata-sections" -+# which due to the linked bug conflicts with "--emit-relocs". Probe discovery -+# therefore is a bit more complicated. -+# -+# First we collect the VMA address of all the code sections in the linked -+# kernel image. -+# -+# Subsequently, we go through the list of symbols in the linked kernel image, -+# and write out records for some select symbols that are used in the processing -+# of probe locations: -+# -+# <section> <address> B <name> -+# Named identifier at a specific address (global variable). -+# -+# We also process any function symbols, and build a lookup map for section-name -+# pairs and just name. Due to the possibility of having symbols with identical -+# names (in the same section, e.g. global and/or one or more local), we append -+# -<n> to every 2nd and later copy of the same symbol name in the current -+# section. -+# section and name -+# name -+# (If multiple symbols map to any of the above combinations, that specific -+# combination is omitted from the mapping.) -+# -+# Next, we process the list of function symbols, and for any function that -+# is not located in a section that starts with .exit.text, .init.text, or -+# .meminit.text) we determine its in-section offset and output a record: -+# -+# <section> <offset> F <name> <address> <section-base-address> -+# Named function at a specific address. -+# -+# Finally, each relocation record from a non-init or exit section that relates -+# to SDT probes is written to the output stream: -+# -+# <section> <address> R <value> -+# Relocation within a section at a specific address -+# -+# Probes are identified in the relocation records as symbols with either a -+# __dtrace_probe_ or __dtrace_isenabled_ prefix. -+# -+# All these records are sorted by section and offset, and any SDT probe -+# location relocation records (R) result in writing out an entry that records -+# its offset relative to the _stext symbol, along with the name of the function -+# it was found in, and the probe name. -+ -+( -+ objdump -ht ${lfn} -+ objdump -tr ${ofn} -+) | \ -+ gawk 'function subl(v0, v1, v0h, v0l, v1h, v1l, d, tmp) { -+ tmp = $0; -+ if (length(v0) > 8) { -+ d = length(v0); -+ v0h = strtonum("0x"substr(v0, 1, d - 8)); -+ v0l = strtonum("0x"substr(v0, d - 8 + 1)); -+ d = length(v1); -+ v1h = strtonum("0x"substr(v1, 1, d - 8)); -+ v1l = strtonum("0x"substr(v1, d - 8 + 1)); -+ -+ if (v0l >= v1l) { -+ if (v0h >= v1h) { -+ d = sprintf("%08x%08x", v0h - v1h, v0l - v1l); -+ } else { -+ printf "ERROR: [stage 1.a] Invalid addresses: %s - %s\n", v0, v1; -+ d = 0; -+ errc++; -+ } -+ } else { -+ if (v0h > v1h) { -+ v0h--; -+ v0l += 4294967296; -+ d = sprintf("%08x%08x", v0h - v1h, v0l - v1l); -+ } else { -+ printf "ERROR: [stage 1.b] Invalid addresses: %s - %s\n", v0, v1; -+ d = 0; -+ errc++; -+ } -+ } -+ } else { -+ v0 = strtonum("0x"v0); -+ v1 = strtonum("0x"v1); -+ d = sprintf("%016x", v0 - v1); -+ } -+ $0 = tmp; -+ -+ return d; -+ } -+ -+ BEGIN { -+ phase = 0; -+ } -+ -+ /^SYMBOL / { -+ phase++; -+ delete scnt; -+ next; -+ } -+ -+ phase == 0 && /^ *[1-9][0-9]* / { -+ snam = $2; -+ addr = $4; -+ getline; -+ if (/CODE/) -+ secs[snam] = addr; -+ -+ next; -+ } -+ -+ phase == 1 && $NF ~ /_(stext|_init_(begin|end))$/ { -+ print ". " $1 " B " $NF; -+ next; -+ } -+ -+ phase == 1 && / F / { -+ if ($4 ~ /^\.(exit|init|meminit)\.text/) -+ next; -+ -+ off = subl($1, secs[$4]); -+ -+ sym = $NF; -+ scnt[sym]++; -+ if (scnt[sym] > 1) -+ sym = sym"-"(scnt[sym] - 1); -+ -+ # section and name -+ id = $4 " " sym; -+ if (id in smap) { -+ if (smap[id] != $1) -+ smap[id] = 0; -+ } else -+ smap[id] = $1; -+ -+ # name -+ id = sym; -+ if (id in smap) { -+ if (smap[id] != $1) -+ smap[id] = 0; -+ } else -+ smap[id] = $1; -+ -+ next; -+ } -+ -+ phase == 2 && / F / { -+ if ($4 ~ /^\.(exit|init|meminit)\.text/) -+ next; -+ -+ sym = $NF; -+ scnt[sym]++; -+ if (scnt[sym] > 1) -+ sym = sym"-"(scnt[sym] - 1); -+ -+ # section and name -+ id = $4 " " sym; -+ if (!(id in smap)) -+ id = sym; -+ # name -+ if (id in smap) { -+ addr = smap[id]; -+ if (!addr) -+ print "ERROR: Non-unique symbol: " $4 " " $6 " " $1 " ["sym"]"; -+ } else { -+ print "ERROR: Could not find " $4 " " $6 " " $1 " ["sym"]"; -+ addr = 0; -+ } -+ -+ print $4 " " $1 " F " $6 " " addr " " secs[$4]; -+ next; -+ } -+ -+ /^RELOC/ { -+ sect = substr($4, 2, length($4) - 3); -+ next; -+ } -+ -+ sect ~ /^\.(exit|init|meminit)\.text/ { -+ next; -+ } -+ -+ sect && /__dtrace_probe_/ { -+ $3 = substr($3, 16); -+ sub(/[\-+].*$/, "", $3); -+ print sect " " $1 " R " $3; -+ next; -+ } -+ -+ sect && /__dtrace_isenabled_/ { -+ $3 = substr($3, 20); -+ sub(/[\-+].*$/, "", $3); -+ print sect " " $1 " R ?" $3; -+ next; -+ }' | \ -+ sort -u | \ -+ gawk 'function addl(v0, v1, v0h, v0l, v1h, v1l, d, tmp) { -+ tmp = $0; -+ if (length(v0) > 8 || length(v1) > 8) { -+ d = length(v0); -+ v0h = strtonum("0x"substr(v0, 1, d - 8)); -+ v0l = strtonum("0x"substr(v0, d - 8 + 1)); -+ d = length(v1); -+ v1h = strtonum("0x"substr(v1, 1, d - 8)); -+ v1l = strtonum("0x"substr(v1, d - 8 + 1)); -+ -+ v0l += v1l; -+ v0h += v1h; -+ d = sprintf("%x", v0l); -+ if (length(d) > 8) { -+ v0h++; -+ v0l -= 4294967296; -+ } -+ d = sprintf("%x", v0h); -+ if (length(d) <= 8) { -+ d = sprintf("%08x%08x", v0h, v0l); -+ } else { -+ printf "#error [stage 2.a] Invalid addresses: %s + %s\n", v0, v1 \ -+ >"/dev/stderr"; -+ errc++; -+ } -+ } else { -+ v0 = strtonum("0x"v0); -+ v1 = strtonum("0x"v1); -+ d = sprintf("%016x", v0 + v1); -+ } -+ $0 = tmp; -+ -+ return d; -+ } -+ -+ function subl(v0, v1, v0h, v0l, v1h, v1l, d, tmp) { -+ tmp = $0; -+ if (length(v0) > 8) { -+ d = length(v0); -+ v0h = strtonum("0x"substr(v0, 1, d - 8)); -+ v0l = strtonum("0x"substr(v0, d - 8 + 1)); -+ d = length(v1); -+ v1h = strtonum("0x"substr(v1, 1, d - 8)); -+ v1l = strtonum("0x"substr(v1, d - 8 + 1)); -+ -+ if (v0l >= v1l) { -+ if (v0h >= v1h) { -+ d = sprintf("%08x%08x", v0h - v1h, v0l - v1l); -+ } else { -+ printf "#error [stage 2.b] Invalid addresses: %s - %s\n", v0, v1 \ -+ >"/dev/stderr"; -+ errc++; -+ } -+ } else { -+ if (v0h > v1h) { -+ v0h--; -+ v0l += 4294967296; -+ d = sprintf("%08x%08x", v0h - v1h, v0l - v1l); -+ } else { -+ printf "#error [stage 2.c] Invalid addresses: %s - %s\n", v0, v1 \ -+ >"/dev/stderr"; -+ errc++; -+ } -+ } -+ } else { -+ v0 = strtonum("0x"v0); -+ v1 = strtonum("0x"v1); -+ d = sprintf("%016x", v0 - v1); -+ } -+ $0 = tmp; -+ -+ return d; -+ } -+ -+ function map_string(str, off) { -+ if (str in strmap) -+ off = strmap[str]; -+ else { -+ off = strsz; -+ strmap[str] = strsz; -+ strv[strc++] = str; -+ strsz += length(str) + 1; -+ } -+ -+ return off; -+ } -+ -+ BEGIN { -+ print "#include <asm/types.h>"; -+ print "#if BITS_PER_LONG == 64"; -+ print "# define PTR .quad"; -+ if (arch == "aarch64") -+ print "# define ALGN .align 3"; -+ else -+ print "# define ALGN .align 8"; -+ print "#else"; -+ print "# define PTR .long"; -+ if (arch == "aarch64") -+ print "# define ALGN .align 2"; -+ else -+ print "# define ALGN .align 4"; -+ print "#endif"; -+ -+ print "\t.section .rodata, \042a\042"; -+ print ""; -+ -+ print ".globl dtrace_sdt_probes"; -+ print "\tALGN"; -+ print "dtrace_sdt_probes:"; -+ -+ probec = 0; -+ stroff = 0; -+ strc = 0; -+ } -+ -+ $1 == "ERROR:" { -+ next; -+ } -+ -+ $4 == "_stext" { -+ stext = $2; -+ next; -+ } -+ -+ $4 == "__init_begin" { -+ init_beg = $2; -+ next; -+ } -+ -+ $4 == "__init_end" { -+ init_end = $2; -+ next; -+ } -+ -+ $3 == "F" { -+ fnam = $4; -+ sub(/\..*$/, "", fnam); -+ foff = $2; -+ fadr = $5; -+ -+ if (fadr != padr) -+ funcc++; -+ padr = fadr; -+ -+ next; -+ } -+ -+ $3 == "R" { -+ addr = addl(fadr, subl($2, foff)); -+ if (addr >= init_beg && addr <= init_end) -+ next; -+ addr = subl(addr, stext); -+ -+ print "/*"; -+ print " * " $1 " " foff " F " fnam " " fadr; -+ print " * " $0; -+ print " * (" fadr " + (" $2 " - " foff ")) - " stext; -+ print " */"; -+ printf "\tPTR\t_stext + 0x%s\n", addr; -+ printf "\tPTR\t%d\n", map_string($4); -+ printf "\tPTR\t%d\n", map_string(fnam); -+ -+ probec++; -+ -+ next; -+ } -+ -+ END { -+ print ""; -+ print ".globl dtrace_sdt_strings"; -+ print "\tALGN"; -+ print "dtrace_sdt_strings:"; -+ -+ -+ for (i = 0; i < strc; i++) -+ printf "\t.asciz\t\042%s\042\n", strv[i]; -+ -+ print ""; -+ print ".globl dtrace_sdt_nprobes"; -+ print ".globl dtrace_fbt_nfuncs"; -+ print "\tALGN"; -+ print "dtrace_sdt_nprobes:"; -+ printf "\tPTR\t%d\n", probec; -+ print "dtrace_fbt_nfuncs:"; -+ printf "\tPTR\t%d\n", funcc; -+ -+ exit(errc == 0 ? 0 : 1); -+ }' > ${tfn} -+ -+exit $? -diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh -index 0b2f3bb60936f81449de21f296bdaddd466c9569..aa4c70504d8c36a523d11a668c7e0c9cb5b36458 100755 ---- a/scripts/link-vmlinux.sh -+++ b/scripts/link-vmlinux.sh -@@ -63,7 +63,12 @@ sdtinfo() - { - info SDTINF ${2} - -- ${srctree}/scripts/dtrace_sdt.sh sdtinfo .tmp_sdtinfo.S ${1} -+ if [ -n "${CONFIG_ARM64}" ]; then -+ ${srctree}/scripts/dtrace_sdt_arm64.sh sdtinfo .tmp_sdtinfo.S \ -+ ${1} ${3} -+ else -+ ${srctree}/scripts/dtrace_sdt.sh sdtinfo .tmp_sdtinfo.S ${1} -+ fi - - local aflags="${KBUILD_AFLAGS} ${KBUILD_AFLAGS_KERNEL} \ - ${NOSTDINC_FLAGS} ${LINUXINCLUDE} ${KBUILD_CPPFLAGS}" -@@ -389,16 +394,14 @@ if [ -n "${CONFIG_KALLSYMS}" ]; then - - # step 1 - if [ -n "${CONFIG_DTRACE}" ]; then -- sdtinfo vmlinux.o ${sdtinfoo} -+ sdtinfo vmlinux.o ${sdtinfoo} vmlinux.o - fi - - kallsyms_step 1 - - if [ -n "${CONFIG_DTRACE}" ]; then -- if [ -n "${CONFIG_ARM64}" ]; then -- kallsyms_step 1 -- else -- kallsyms_step 1 -r -+ if [ -n "${CONFIG_X86_64}" ]; then -+ kallsyms_step 1 --emit-relocs - fi - sdtinfo ${kallsyms_vmlinux} ${sdtinfoo} vmlinux.o - fi --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/dtrace-patches/0017-dtrace-add-SDT-probes.patch b/sys-kernel/cairn-sources/files/5.10.14/dtrace-patches/0017-dtrace-add-SDT-probes.patch deleted file mode 100644 index cbb268285643..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/dtrace-patches/0017-dtrace-add-SDT-probes.patch +++ /dev/null @@ -1,3307 +0,0 @@ -From 5694e5386d32e8fe708a76177b44244d18bd8f7b Mon Sep 17 00:00:00 2001 -From: Kris Van Hees <kris.van.hees@oracle.com> -Date: Thu, 8 Nov 2018 18:59:39 +0000 -Subject: [PATCH 17/19] dtrace: add SDT probes - -This adds a variety of SDT probes. - -XXX add documentation here from the commit messages - -Signed-off-by: Nick Alcock <nick.alcock@oracle.com> -Signed-off-by: Kris Van Hees <kris.van.hees@oracle.com> -Signed-off-by: Tomas Jedlicka <tomas.jedlicka@oracle.com> -Signed-off-by: Eugene Loh <eugene.loh@oracle.com> -Signed-off-by: Alan Maguire <alan.maguire@oracle.com> -Signed-off-by: David Mc Lean <david.mclean@oracle.com> -Signed-off-by: Vincent Lim <vincent.lim@oracle.com> ---- - block/bio.c | 7 ++ - block/blk-core.c | 4 + - fs/exec.c | 8 ++ - fs/nfs/internal.h | 13 +++ - fs/nfs/read.c | 3 + - fs/nfs/write.c | 2 + - fs/xfs/xfs_buf.c | 19 ++++ - include/linux/rwlock_api_smp.h | 38 +++++++ - include/linux/spinlock_api_smp.h | 12 ++ - kernel/exit.c | 5 + - kernel/fork.c | 3 + - kernel/locking/mutex.c | 52 ++++++++- - kernel/locking/qrwlock.c | 24 +++- - kernel/locking/qspinlock.c | 20 +++- - kernel/sched/core.c | 31 +++++- - kernel/signal.c | 31 +++++- - kernel/time/timer.c | 3 + - net/ipv4/ip_input.c | 66 +++++++++-- - net/ipv4/ip_output.c | 71 +++++++++++- - net/ipv4/raw.c | 49 ++++++-- - net/ipv4/tcp.c | 26 +++++ - net/ipv4/tcp_input.c | 43 +++++++ - net/ipv4/tcp_ipv4.c | 114 ++++++++++++++++++- - net/ipv4/tcp_minisocks.c | 15 +++ - net/ipv4/tcp_output.c | 29 +++++ - net/ipv4/udp.c | 26 ++++- - net/ipv6/ip6_input.c | 103 ++++++++++++++--- - net/ipv6/ip6_output.c | 186 ++++++++++++++++++++++++++----- - net/ipv6/mcast.c | 72 +++++++++--- - net/ipv6/ndisc.c | 9 ++ - net/ipv6/output_core.c | 9 ++ - net/ipv6/raw.c | 38 ++++++- - net/ipv6/tcp_ipv6.c | 107 +++++++++++++++++- - net/ipv6/udp.c | 26 ++++- - 34 files changed, 1153 insertions(+), 111 deletions(-) - -diff --git a/block/bio.c b/block/bio.c -index fa01bef35bb1fe77b26d797cfdb76e7e04082ac3..f2cde8dc402cab42db908b29b2ebf775bc19c85e 100644 ---- a/block/bio.c -+++ b/block/bio.c -@@ -1153,6 +1153,8 @@ int submit_bio_wait(struct bio *bio) - bio->bi_opf |= REQ_SYNC; - submit_bio(bio); - -+ DTRACE_IO(wait__start, struct bio * : (bufinfo_t *, devinfo_t *), bio, -+ struct file * : fileinfo_t *, NULL); - /* Prevent hang_check timer from firing at us during very long I/O */ - hang_check = sysctl_hung_task_timeout_secs; - if (hang_check) -@@ -1161,6 +1163,8 @@ int submit_bio_wait(struct bio *bio) - ; - else - wait_for_completion_io(&done); -+ DTRACE_IO(wait__done, struct bio * : (bufinfo_t *, devinfo_t *), bio, -+ struct file * : fileinfo_t *, NULL); - - return blk_status_to_errno(bio->bi_status); - } -@@ -1444,6 +1448,9 @@ void bio_endio(struct bio *bio) - } - - blk_throtl_bio_endio(bio); -+ DTRACE_IO(done, struct bio * : -+ (bufinfo_t *, devinfo_t *), bio, -+ struct file * : fileinfo_t *, NULL); - /* release cgroup info */ - bio_uninit(bio); - if (bio->bi_end_io) -diff --git a/block/blk-core.c b/block/blk-core.c -index 2d53e2ff48ff889889d978665eccf365d5feea8a..67523a6729fb00fe6fb401c0d31f34410fbb5e55 100644 ---- a/block/blk-core.c -+++ b/block/blk-core.c -@@ -913,11 +913,15 @@ static noinline_for_stack bool submit_bio_checks(struct bio *bio) - */ - bio_set_flag(bio, BIO_TRACE_COMPLETION); - } -+ DTRACE_IO(start, struct bio * : (bufinfo_t *, devinfo_t *), bio, -+ struct file * : fileinfo_t *, NULL); - return true; - - not_supported: - status = BLK_STS_NOTSUPP; - end_io: -+ DTRACE_IO(start, struct bio * : (bufinfo_t *, devinfo_t *), bio, -+ struct file * : fileinfo_t *, NULL); - bio->bi_status = status; - bio_endio(bio); - return false; -diff --git a/fs/exec.c b/fs/exec.c -index 4340b28030047552a40dfa962e08d994d3f33278..acd96c0e0e5f9506f9954802dd3ecd9d5f0b2568 100644 ---- a/fs/exec.c -+++ b/fs/exec.c -@@ -64,6 +64,7 @@ - #include <linux/compat.h> - #include <linux/vmalloc.h> - #include <linux/io_uring.h> - #include <linux/random.h> -+#include <linux/sdt.h> - #include <linux/dtrace_os.h> - - #include <linux/uaccess.h> -@@ -1797,6 +1798,7 @@ static int bprm_execve(struct linux_binprm *bprm, - current->in_execve = 1; - - file = do_open_execat(fd, filename, flags); -+ DTRACE_PROC(exec, char *, filename->name); - retval = PTR_ERR(file); - if (IS_ERR(file)) - goto out_unmark; -@@ -1834,6 +1836,8 @@ static int bprm_execve(struct linux_binprm *bprm, - task_numa_free(current, false); - if (displaced) - put_files_struct(displaced); -+ -+ DTRACE_PROC(exec__success); - return retval; - - out: -@@ -1923,6 +1927,8 @@ static int do_execveat_common(int fd, struct filename *filename, - - out_ret: - putname(filename); -+ if (retval < 0) -+ DTRACE_PROC(exec__failure, int, retval); - return retval; - } - -@@ -1976,6 +1982,8 @@ int kernel_execve(const char *kernel_filename, - free_bprm(bprm); - out_ret: - putname(filename); -+ if (retval < 0) -+ DTRACE_PROC(exec__failure, int, retval); - return retval; - } - -diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h -index 98554dd18a7157619c2b5f85c751b4dd88c7311a..1e13fb97d642d3978fb2ae68e9caa5072ec3008c 100644 ---- a/fs/nfs/internal.h -+++ b/fs/nfs/internal.h -@@ -10,6 +10,7 @@ - #include <linux/sunrpc/addr.h> - #include <linux/nfs_page.h> - #include <linux/wait_bit.h> -+#include <linux/sdt.h> - - #define NFS_SB_MASK (SB_RDONLY|SB_NOSUID|SB_NODEV|SB_NOEXEC|SB_SYNCHRONOUS) - -@@ -832,3 +833,15 @@ static inline void nfs_set_port(struct sockaddr *sap, int *port, - - rpc_set_port(sap, *port); - } -+ -+#define DTRACE_IO_NFS(name, rw, size, inode) \ -+ if (DTRACE_IO_ENABLED(name)) { \ -+ struct bio bio __maybe_unused = { \ -+ .bi_opf = rw, \ -+ .bi_iter.bi_size = size, \ -+ .bi_iter.bi_sector = NFS_FILEID(inode), \ -+ }; \ -+ DTRACE_IO(name, struct bio * : (bufinfo_t *, \ -+ devinfo_t *), &bio, \ -+ struct file * : fileinfo_t *, NULL); \ -+} -diff --git a/fs/nfs/read.c b/fs/nfs/read.c -index eb854f1f86e2eb10cd3ecf2a9b4559761f5027dc..7049b4540f94059b73b79941629ac1b04f53f8c3 100644 ---- a/fs/nfs/read.c -+++ b/fs/nfs/read.c -@@ -212,6 +212,8 @@ static void nfs_initiate_read(struct nfs_pgio_header *hdr, - struct inode *inode = hdr->inode; - int swap_flags = IS_SWAPFILE(inode) ? NFS_RPC_SWAPFLAGS : 0; - -+ DTRACE_IO_NFS(start, REQ_OP_READ, hdr->args.count, hdr->inode); -+ - task_setup_data->flags |= swap_flags; - rpc_ops->read_setup(hdr, msg); - trace_nfs_initiate_read(hdr); -@@ -243,6 +245,7 @@ static int nfs_readpage_done(struct rpc_task *task, - struct inode *inode) - { - int status = NFS_PROTO(inode)->read_done(task, hdr); -+ DTRACE_IO_NFS(done, REQ_OP_READ, hdr->res.count, hdr->inode); - if (status != 0) - return status; - -diff --git a/fs/nfs/write.c b/fs/nfs/write.c -index 639c34fec04a8488dd3a5df5b1b1c9ba0f170753..8bd0bd4e5b76435043c364688338cf2e7980e4a0 100644 ---- a/fs/nfs/write.c -+++ b/fs/nfs/write.c -@@ -1403,6 +1403,7 @@ static void nfs_initiate_write(struct nfs_pgio_header *hdr, - task_setup_data->priority = priority; - rpc_ops->write_setup(hdr, msg, &task_setup_data->rpc_client); - trace_nfs_initiate_write(hdr); -+ DTRACE_IO_NFS(start, REQ_OP_WRITE, hdr->args.count, hdr->inode); - } - - /* If a nfs_flush_* function fails, it should remove reqs from @head and -@@ -1562,6 +1563,7 @@ static int nfs_writeback_done(struct rpc_task *task, - * depend on tighter cache coherency when writing. - */ - status = NFS_PROTO(inode)->write_done(task, hdr); -+ DTRACE_IO_NFS(done, REQ_OP_WRITE, hdr->res.count, hdr->inode); - if (status != 0) - return status; - -diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c -index 4e4cf91f4f9fe7c5f44368a114d7aabe7bdc2e25..6550a3447816620bf0cfff58fd8f019ae51afdfa 100644 ---- a/fs/xfs/xfs_buf.c -+++ b/fs/xfs/xfs_buf.c -@@ -52,6 +52,21 @@ static kmem_zone_t *xfs_buf_zone; - * b_lock (trylock due to inversion) - */ - -+#define DTRACE_IO_XFS_WAIT(name, bp, is_write) \ -+ if (DTRACE_IO_ENABLED(name)) { \ -+ struct bio bio __maybe_unused = { \ -+ .bi_iter.bi_sector = (bp)->b_bn, \ -+ .bi_iter.bi_size = (bp)->b_length, \ -+ .bi_opf = is_write ? \ -+ REQ_OP_WRITE : REQ_OP_READ, \ -+ .bi_disk = (bp)->b_target->bt_bdev->bd_disk, \ -+ .bi_partno = (bp)->b_target->bt_bdev->bd_partno,\ -+ }; \ -+ DTRACE_IO(name, struct bio * : (bufinfo_t *, \ -+ devinfo_t *), &bio, \ -+ struct file * : fileinfo_t *, NULL); \ -+ } -+ - static int __xfs_buf_submit(struct xfs_buf *bp, bool wait); - - static inline int -@@ -1633,10 +1648,14 @@ static int - xfs_buf_iowait( - struct xfs_buf *bp) - { -+ int orig_flags __attribute__((unused)) = bp->b_flags; -+ - ASSERT(!(bp->b_flags & XBF_ASYNC)); - - trace_xfs_buf_iowait(bp, _RET_IP_); -+ DTRACE_IO_XFS_WAIT(wait__start, bp, orig_flags & XBF_WRITE); - wait_for_completion(&bp->b_iowait); -+ DTRACE_IO_XFS_WAIT(wait__done, bp, orig_flags & XBF_WRITE); - trace_xfs_buf_iowait_done(bp, _RET_IP_); - - return bp->b_error; -diff --git a/include/linux/rwlock_api_smp.h b/include/linux/rwlock_api_smp.h -index abfb53ab11beb4f527cea7203cda03495850ed37..2531929ccb580171256af12e81aa571ad3786227 100644 ---- a/include/linux/rwlock_api_smp.h -+++ b/include/linux/rwlock_api_smp.h -@@ -5,6 +5,8 @@ - # error "please don't include this file directly" - #endif - -+#include <linux/sdt.h> -+ - /* - * include/linux/rwlock_api_smp.h - * -@@ -119,6 +121,8 @@ static inline int __raw_read_trylock(rwlock_t *lock) - preempt_disable(); - if (do_raw_read_trylock(lock)) { - rwlock_acquire_read(&lock->dep_map, 0, 1, _RET_IP_); -+ DTRACE_LOCKSTAT(rw__acquire, struct rwlock *, lock, int, -+ DTRACE_LOCKSTAT_RW_READER); - return 1; - } - preempt_enable(); -@@ -130,6 +134,8 @@ static inline int __raw_write_trylock(rwlock_t *lock) - preempt_disable(); - if (do_raw_write_trylock(lock)) { - rwlock_acquire(&lock->dep_map, 0, 1, _RET_IP_); -+ DTRACE_LOCKSTAT(rw__acquire, struct rwlock *, lock, int, -+ DTRACE_LOCKSTAT_RW_WRITER); - return 1; - } - preempt_enable(); -@@ -148,6 +154,8 @@ static inline void __raw_read_lock(rwlock_t *lock) - preempt_disable(); - rwlock_acquire_read(&lock->dep_map, 0, 0, _RET_IP_); - LOCK_CONTENDED(lock, do_raw_read_trylock, do_raw_read_lock); -+ DTRACE_LOCKSTAT(rw__acquire, struct rwlock *, lock, int, -+ DTRACE_LOCKSTAT_RW_READER); - } - - static inline unsigned long __raw_read_lock_irqsave(rwlock_t *lock) -@@ -159,6 +167,8 @@ static inline unsigned long __raw_read_lock_irqsave(rwlock_t *lock) - rwlock_acquire_read(&lock->dep_map, 0, 0, _RET_IP_); - LOCK_CONTENDED_FLAGS(lock, do_raw_read_trylock, do_raw_read_lock, - do_raw_read_lock_flags, &flags); -+ DTRACE_LOCKSTAT(rw__acquire, struct rwlock *, lock, int, -+ DTRACE_LOCKSTAT_RW_READER); - return flags; - } - -@@ -168,6 +178,8 @@ static inline void __raw_read_lock_irq(rwlock_t *lock) - preempt_disable(); - rwlock_acquire_read(&lock->dep_map, 0, 0, _RET_IP_); - LOCK_CONTENDED(lock, do_raw_read_trylock, do_raw_read_lock); -+ DTRACE_LOCKSTAT(rw__acquire, struct rwlock *, lock, int, -+ DTRACE_LOCKSTAT_RW_READER); - } - - static inline void __raw_read_lock_bh(rwlock_t *lock) -@@ -175,6 +187,8 @@ static inline void __raw_read_lock_bh(rwlock_t *lock) - __local_bh_disable_ip(_RET_IP_, SOFTIRQ_LOCK_OFFSET); - rwlock_acquire_read(&lock->dep_map, 0, 0, _RET_IP_); - LOCK_CONTENDED(lock, do_raw_read_trylock, do_raw_read_lock); -+ DTRACE_LOCKSTAT(rw__acquire, struct rwlock *, lock, int, -+ DTRACE_LOCKSTAT_RW_READER); - } - - static inline unsigned long __raw_write_lock_irqsave(rwlock_t *lock) -@@ -186,6 +200,8 @@ static inline unsigned long __raw_write_lock_irqsave(rwlock_t *lock) - rwlock_acquire(&lock->dep_map, 0, 0, _RET_IP_); - LOCK_CONTENDED_FLAGS(lock, do_raw_write_trylock, do_raw_write_lock, - do_raw_write_lock_flags, &flags); -+ DTRACE_LOCKSTAT(rw__acquire, struct rwlock *, lock, int, -+ DTRACE_LOCKSTAT_RW_WRITER); - return flags; - } - -@@ -195,6 +211,8 @@ static inline void __raw_write_lock_irq(rwlock_t *lock) - preempt_disable(); - rwlock_acquire(&lock->dep_map, 0, 0, _RET_IP_); - LOCK_CONTENDED(lock, do_raw_write_trylock, do_raw_write_lock); -+ DTRACE_LOCKSTAT(rw__acquire, struct rwlock *, lock, int, -+ DTRACE_LOCKSTAT_RW_WRITER); - } - - static inline void __raw_write_lock_bh(rwlock_t *lock) -@@ -202,6 +220,8 @@ static inline void __raw_write_lock_bh(rwlock_t *lock) - __local_bh_disable_ip(_RET_IP_, SOFTIRQ_LOCK_OFFSET); - rwlock_acquire(&lock->dep_map, 0, 0, _RET_IP_); - LOCK_CONTENDED(lock, do_raw_write_trylock, do_raw_write_lock); -+ DTRACE_LOCKSTAT(rw__acquire, struct rwlock *, lock, int, -+ DTRACE_LOCKSTAT_RW_WRITER); - } - - static inline void __raw_write_lock(rwlock_t *lock) -@@ -209,6 +229,8 @@ static inline void __raw_write_lock(rwlock_t *lock) - preempt_disable(); - rwlock_acquire(&lock->dep_map, 0, 0, _RET_IP_); - LOCK_CONTENDED(lock, do_raw_write_trylock, do_raw_write_lock); -+ DTRACE_LOCKSTAT(rw__acquire, struct rwlock *, lock, int, -+ DTRACE_LOCKSTAT_RW_WRITER); - } - - #endif /* !CONFIG_GENERIC_LOCKBREAK || CONFIG_DEBUG_LOCK_ALLOC */ -@@ -217,6 +239,8 @@ static inline void __raw_write_unlock(rwlock_t *lock) - { - rwlock_release(&lock->dep_map, _RET_IP_); - do_raw_write_unlock(lock); -+ DTRACE_LOCKSTAT(rw__release, struct rwlock *, lock, int, -+ DTRACE_LOCKSTAT_RW_WRITER); - preempt_enable(); - } - -@@ -224,6 +248,8 @@ static inline void __raw_read_unlock(rwlock_t *lock) - { - rwlock_release(&lock->dep_map, _RET_IP_); - do_raw_read_unlock(lock); -+ DTRACE_LOCKSTAT(rw__release, struct rwlock *, lock, int, -+ DTRACE_LOCKSTAT_RW_READER); - preempt_enable(); - } - -@@ -232,6 +258,8 @@ __raw_read_unlock_irqrestore(rwlock_t *lock, unsigned long flags) - { - rwlock_release(&lock->dep_map, _RET_IP_); - do_raw_read_unlock(lock); -+ DTRACE_LOCKSTAT(rw__release, struct rwlock *, lock, int, -+ DTRACE_LOCKSTAT_RW_READER); - local_irq_restore(flags); - preempt_enable(); - } -@@ -240,6 +268,8 @@ static inline void __raw_read_unlock_irq(rwlock_t *lock) - { - rwlock_release(&lock->dep_map, _RET_IP_); - do_raw_read_unlock(lock); -+ DTRACE_LOCKSTAT(rw__release, struct rwlock *, lock, int, -+ DTRACE_LOCKSTAT_RW_READER); - local_irq_enable(); - preempt_enable(); - } -@@ -248,6 +278,8 @@ static inline void __raw_read_unlock_bh(rwlock_t *lock) - { - rwlock_release(&lock->dep_map, _RET_IP_); - do_raw_read_unlock(lock); -+ DTRACE_LOCKSTAT(rw__release, struct rwlock *, lock, int, -+ DTRACE_LOCKSTAT_RW_READER); - __local_bh_enable_ip(_RET_IP_, SOFTIRQ_LOCK_OFFSET); - } - -@@ -256,6 +288,8 @@ static inline void __raw_write_unlock_irqrestore(rwlock_t *lock, - { - rwlock_release(&lock->dep_map, _RET_IP_); - do_raw_write_unlock(lock); -+ DTRACE_LOCKSTAT(rw__release, struct rwlock *, lock, int, -+ DTRACE_LOCKSTAT_RW_WRITER); - local_irq_restore(flags); - preempt_enable(); - } -@@ -264,6 +298,8 @@ static inline void __raw_write_unlock_irq(rwlock_t *lock) - { - rwlock_release(&lock->dep_map, _RET_IP_); - do_raw_write_unlock(lock); -+ DTRACE_LOCKSTAT(rw__release, struct rwlock *, lock, int, -+ DTRACE_LOCKSTAT_RW_WRITER); - local_irq_enable(); - preempt_enable(); - } -@@ -272,6 +308,8 @@ static inline void __raw_write_unlock_bh(rwlock_t *lock) - { - rwlock_release(&lock->dep_map, _RET_IP_); - do_raw_write_unlock(lock); -+ DTRACE_LOCKSTAT(rw__release, struct rwlock *, lock, int, -+ DTRACE_LOCKSTAT_RW_WRITER); - __local_bh_enable_ip(_RET_IP_, SOFTIRQ_LOCK_OFFSET); - } - -diff --git a/include/linux/spinlock_api_smp.h b/include/linux/spinlock_api_smp.h -index 19a9be9d97ee531f236be5f1953ac80ce729238b..e7601d01b87d4789a3d4a3498a55a51955354e90 100644 ---- a/include/linux/spinlock_api_smp.h -+++ b/include/linux/spinlock_api_smp.h -@@ -5,6 +5,8 @@ - # error "please don't include this file directly" - #endif - -+#include <linux/sdt.h> -+ - /* - * include/linux/spinlock_api_smp.h - * -@@ -88,6 +90,7 @@ static inline int __raw_spin_trylock(raw_spinlock_t *lock) - preempt_disable(); - if (do_raw_spin_trylock(lock)) { - spin_acquire(&lock->dep_map, 0, 1, _RET_IP_); -+ DTRACE_LOCKSTAT(spin__acquire, spinlock_t *, lock); - return 1; - } - preempt_enable(); -@@ -118,6 +121,7 @@ static inline unsigned long __raw_spin_lock_irqsave(raw_spinlock_t *lock) - #else - do_raw_spin_lock_flags(lock, &flags); - #endif -+ DTRACE_LOCKSTAT(spin__acquire, spinlock_t *, lock); - return flags; - } - -@@ -127,6 +131,7 @@ static inline void __raw_spin_lock_irq(raw_spinlock_t *lock) - preempt_disable(); - spin_acquire(&lock->dep_map, 0, 0, _RET_IP_); - LOCK_CONTENDED(lock, do_raw_spin_trylock, do_raw_spin_lock); -+ DTRACE_LOCKSTAT(spin__acquire, spinlock_t *, lock); - } - - static inline void __raw_spin_lock_bh(raw_spinlock_t *lock) -@@ -134,6 +139,7 @@ static inline void __raw_spin_lock_bh(raw_spinlock_t *lock) - __local_bh_disable_ip(_RET_IP_, SOFTIRQ_LOCK_OFFSET); - spin_acquire(&lock->dep_map, 0, 0, _RET_IP_); - LOCK_CONTENDED(lock, do_raw_spin_trylock, do_raw_spin_lock); -+ DTRACE_LOCKSTAT(spin__acquire, spinlock_t *, lock); - } - - static inline void __raw_spin_lock(raw_spinlock_t *lock) -@@ -141,6 +147,7 @@ static inline void __raw_spin_lock(raw_spinlock_t *lock) - preempt_disable(); - spin_acquire(&lock->dep_map, 0, 0, _RET_IP_); - LOCK_CONTENDED(lock, do_raw_spin_trylock, do_raw_spin_lock); -+ DTRACE_LOCKSTAT(spin__acquire, spinlock_t *, lock); - } - - #endif /* !CONFIG_GENERIC_LOCKBREAK || CONFIG_DEBUG_LOCK_ALLOC */ -@@ -149,6 +156,7 @@ static inline void __raw_spin_unlock(raw_spinlock_t *lock) - { - spin_release(&lock->dep_map, _RET_IP_); - do_raw_spin_unlock(lock); -+ DTRACE_LOCKSTAT(spin__release, spinlock_t *, lock); - preempt_enable(); - } - -@@ -157,6 +165,7 @@ static inline void __raw_spin_unlock_irqrestore(raw_spinlock_t *lock, - { - spin_release(&lock->dep_map, _RET_IP_); - do_raw_spin_unlock(lock); -+ DTRACE_LOCKSTAT(spin__release, spinlock_t *, lock); - local_irq_restore(flags); - preempt_enable(); - } -@@ -165,6 +174,7 @@ static inline void __raw_spin_unlock_irq(raw_spinlock_t *lock) - { - spin_release(&lock->dep_map, _RET_IP_); - do_raw_spin_unlock(lock); -+ DTRACE_LOCKSTAT(spin__release, spinlock_t *, lock); - local_irq_enable(); - preempt_enable(); - } -@@ -173,6 +183,7 @@ static inline void __raw_spin_unlock_bh(raw_spinlock_t *lock) - { - spin_release(&lock->dep_map, _RET_IP_); - do_raw_spin_unlock(lock); -+ DTRACE_LOCKSTAT(spin__release, spinlock_t *, lock); - __local_bh_enable_ip(_RET_IP_, SOFTIRQ_LOCK_OFFSET); - } - -@@ -181,6 +192,7 @@ static inline int __raw_spin_trylock_bh(raw_spinlock_t *lock) - __local_bh_disable_ip(_RET_IP_, SOFTIRQ_LOCK_OFFSET); - if (do_raw_spin_trylock(lock)) { - spin_acquire(&lock->dep_map, 0, 1, _RET_IP_); -+ DTRACE_LOCKSTAT(spin__acquire, spinlock_t *, lock); - return 1; - } - __local_bh_enable_ip(_RET_IP_, SOFTIRQ_LOCK_OFFSET); -diff --git a/kernel/exit.c b/kernel/exit.c -index da498c5f029c20d162f8665cee6cd49c6de9a06c..285b0c0ff00d99eb46f0c7bc94f03abdfcbb289c 100644 ---- a/kernel/exit.c -+++ b/kernel/exit.c -@@ -64,6 +64,7 @@ - #include <linux/rcuwait.h> - #include <linux/compat.h> - #include <linux/io_uring.h> -+#include <linux/sdt.h> - #include <linux/dtrace_os.h> - - #include <linux/uaccess.h> -@@ -796,6 +797,10 @@ void __noreturn do_exit(long code) - tsk->exit_code = code; - taskstats_exit(tsk, group_dead); - -+ DTRACE_PROC(lwp__exit); -+ if (group_dead) -+ DTRACE_PROC(exit, int, code & 0x80 ? 3 : code & 0x7f ? 2 : 1); -+ - /* Remove DTrace state for this task */ - dtrace_task_free(tsk); - -diff --git a/kernel/fork.c b/kernel/fork.c -index 0d8a2b12fd90565fccba06804f9c0a58cbc6a064..0729e80e4ad88c3bc9919a588a771b7b91cc2706 100644 ---- a/kernel/fork.c -+++ b/kernel/fork.c -@@ -96,6 +96,7 @@ - #include <linux/kasan.h> - #include <linux/scs.h> - #include <linux/io_uring.h> -+#include <linux/sdt.h> - #include <linux/dtrace_task_impl.h> - - #include <asm/pgalloc.h> -@@ -2513,6 +2514,8 @@ pid_t kernel_clone(struct kernel_clone_args *args) - } - - put_pid(pid); -+ DTRACE_PROC(lwp__create, struct task_struct * : (lwpsinfo_t *, psinfo_t *), p); -+ DTRACE_PROC(create, struct task_struct * : psinfo_t *, p); - return nr; - } - -diff --git a/kernel/locking/mutex.c b/kernel/locking/mutex.c -index 5352ce50a97e309b5bf8cdd2059378b17a8f14ec..e784dd89d924c4867de23c0eb60e65b2a47cad52 100644 ---- a/kernel/locking/mutex.c -+++ b/kernel/locking/mutex.c -@@ -29,6 +29,7 @@ - #include <linux/interrupt.h> - #include <linux/debug_locks.h> - #include <linux/osq_lock.h> -+#include <linux/sdt.h> - - #ifdef CONFIG_DEBUG_MUTEXES - # include "mutex-debug.h" -@@ -282,6 +283,7 @@ void __sched mutex_lock(struct mutex *lock) - - if (!__mutex_trylock_fast(lock)) - __mutex_lock_slowpath(lock); -+ DTRACE_LOCKSTAT(adaptive__acquire, struct mutex *, lock); - } - EXPORT_SYMBOL(mutex_lock); - #endif -@@ -734,10 +736,14 @@ static noinline void __sched __mutex_unlock_slowpath(struct mutex *lock, unsigne - void __sched mutex_unlock(struct mutex *lock) - { - #ifndef CONFIG_DEBUG_LOCK_ALLOC -- if (__mutex_unlock_fast(lock)) -+ if (__mutex_unlock_fast(lock)) { -+ DTRACE_LOCKSTAT(adaptive__release, struct mutex *, lock); - return; -+ } - #endif -+ - __mutex_unlock_slowpath(lock, _RET_IP_); -+ DTRACE_LOCKSTAT(adaptive__release, struct mutex *, lock); - } - EXPORT_SYMBOL(mutex_unlock); - -@@ -927,6 +933,8 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass, - struct lockdep_map *nest_lock, unsigned long ip, - struct ww_acquire_ctx *ww_ctx, const bool use_ww_ctx) - { -+ u64 spinstart = 0, spinend, spintotal = 0; -+ u64 waitstart, waitend, waittotal = 0; - struct mutex_waiter waiter; - bool first = false; - struct ww_mutex *ww; -@@ -958,9 +966,11 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass, - if (__mutex_trylock(lock) || - mutex_optimistic_spin(lock, ww_ctx, use_ww_ctx, NULL)) { - /* got the lock, yay! */ -+ - lock_acquired(&lock->dep_map, ip); - if (use_ww_ctx && ww_ctx) - ww_mutex_set_context_fastpath(ww, ww_ctx); -+ DTRACE_LOCKSTAT(adaptive__acquire, struct mutex *, lock); - preempt_enable(); - return 0; - } -@@ -1003,6 +1013,9 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass, - waiter.task = current; - - set_current_state(state); -+ if (DTRACE_LOCKSTAT_ENABLED(adaptive__spin)) -+ spinstart = dtrace_gethrtime_ns(); -+ - for (;;) { - /* - * Once we hold wait_lock, we're serialized against -@@ -1030,7 +1043,15 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass, - } - - spin_unlock(&lock->wait_lock); -- schedule_preempt_disabled(); -+ -+ if (DTRACE_LOCKSTAT_ENABLED(adaptive__block)) { -+ waitstart = dtrace_gethrtime_ns(); -+ schedule_preempt_disabled(); -+ waitend = dtrace_gethrtime_ns(); -+ if (waitend > waitstart) -+ waittotal += waitend - waitstart; -+ } else -+ schedule_preempt_disabled(); - - /* - * ww_mutex needs to always recheck its position since its waiter -@@ -1082,6 +1103,19 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass, - ww_mutex_lock_acquired(ww, ww_ctx); - - spin_unlock(&lock->wait_lock); -+ -+ if (DTRACE_LOCKSTAT_ENABLED(adaptive__spin) && spinstart) { -+ spinend = dtrace_gethrtime_ns(); -+ spintotal = (spinend > spinstart) ? (spinend - spinstart) : 0; -+ spintotal = (spintotal > waittotal) ? -+ (spintotal - waittotal) : 0; -+ DTRACE_LOCKSTAT(adaptive__spin, struct mutex *, lock, -+ uint64_t, spintotal); -+ } -+ if (DTRACE_LOCKSTAT_ENABLED(adaptive__block) && waittotal) -+ DTRACE_LOCKSTAT(adaptive__block, struct mutex *, lock, -+ uint64_t, waittotal); -+ DTRACE_LOCKSTAT(adaptive__acquire, struct mutex *, lock); - preempt_enable(); - return 0; - -@@ -1092,6 +1126,8 @@ __mutex_lock_common(struct mutex *lock, long state, unsigned int subclass, - spin_unlock(&lock->wait_lock); - debug_mutex_free_waiter(&waiter); - mutex_release(&lock->dep_map, ip); -+ DTRACE_LOCKSTAT(adaptive__acquire__error, struct mutex *, lock, -+ int, ret); - preempt_enable(); - return ret; - } -@@ -1307,8 +1343,10 @@ int __sched mutex_lock_interruptible(struct mutex *lock) - { - might_sleep(); - -- if (__mutex_trylock_fast(lock)) -+ if (__mutex_trylock_fast(lock)) { -+ DTRACE_LOCKSTAT(adaptive__acquire, struct mutex *, lock); - return 0; -+ } - - return __mutex_lock_interruptible_slowpath(lock); - } -@@ -1331,8 +1369,10 @@ int __sched mutex_lock_killable(struct mutex *lock) - { - might_sleep(); - -- if (__mutex_trylock_fast(lock)) -+ if (__mutex_trylock_fast(lock)) { -+ DTRACE_LOCKSTAT(adaptive__acquire, struct mutex *, lock); - return 0; -+ } - - return __mutex_lock_killable_slowpath(lock); - } -@@ -1416,8 +1456,10 @@ int __sched mutex_trylock(struct mutex *lock) - #endif - - locked = __mutex_trylock(lock); -- if (locked) -+ if (locked) { - mutex_acquire(&lock->dep_map, 0, 1, _RET_IP_); -+ DTRACE_LOCKSTAT(adaptive__acquire, struct mutex *, lock); -+ } - - return locked; - } -diff --git a/kernel/locking/qrwlock.c b/kernel/locking/qrwlock.c -index fe9ca92faa2a7a7b0915a6ae420f31b2e4fc4dd8..6b1511be7805cb9de3869367230a81ae9758df9c 100644 ---- a/kernel/locking/qrwlock.c -+++ b/kernel/locking/qrwlock.c -@@ -11,6 +11,7 @@ - #include <linux/cpumask.h> - #include <linux/percpu.h> - #include <linux/hardirq.h> -+#include <linux/sdt.h> - #include <linux/spinlock.h> - #include <asm/qrwlock.h> - -@@ -20,9 +21,13 @@ - */ - void queued_read_lock_slowpath(struct qrwlock *lock) - { -+ u64 spinstart = 0, spinend, spintime; -+ - /* - * Readers come here when they cannot get the lock without waiting - */ -+ if (DTRACE_LOCKSTAT_ENABLED(rw__spin)) -+ spinstart = dtrace_gethrtime_ns(); - if (unlikely(in_interrupt())) { - /* - * Readers in interrupt context will get the lock immediately -@@ -31,7 +36,7 @@ void queued_read_lock_slowpath(struct qrwlock *lock) - * without waiting in the queue. - */ - atomic_cond_read_acquire(&lock->cnts, !(VAL & _QW_LOCKED)); -- return; -+ goto done; - } - atomic_sub(_QR_BIAS, &lock->cnts); - -@@ -52,6 +57,13 @@ void queued_read_lock_slowpath(struct qrwlock *lock) - * Signal the next one in queue to become queue head - */ - arch_spin_unlock(&lock->wait_lock); -+done: -+ if (DTRACE_LOCKSTAT_ENABLED(rw__spin) && spinstart) { -+ spinend = dtrace_gethrtime_ns(); -+ spintime = spinend > spinstart ? spinend - spinstart : 0; -+ DTRACE_LOCKSTAT(rw__spin, rwlock_t *, lock, uint64_t, spintime, -+ int, DTRACE_LOCKSTAT_RW_READER); -+ } - } - EXPORT_SYMBOL(queued_read_lock_slowpath); - -@@ -61,7 +73,11 @@ EXPORT_SYMBOL(queued_read_lock_slowpath); - */ - void queued_write_lock_slowpath(struct qrwlock *lock) - { -+ u64 spinstart = 0, spinend, spintime; -+ - /* Put the writer into the wait queue */ -+ if (DTRACE_LOCKSTAT_ENABLED(rw__spin)) -+ spinstart = dtrace_gethrtime_ns(); - arch_spin_lock(&lock->wait_lock); - - /* Try to acquire the lock directly if no reader is present */ -@@ -79,5 +95,11 @@ void queued_write_lock_slowpath(struct qrwlock *lock) - _QW_LOCKED) != _QW_WAITING); - unlock: - arch_spin_unlock(&lock->wait_lock); -+ if (DTRACE_LOCKSTAT_ENABLED(rw__spin) && spinstart) { -+ spinend = dtrace_gethrtime_ns(); -+ spintime = spinend > spinstart ? spinend - spinstart : 0; -+ DTRACE_LOCKSTAT(rw__spin, rwlock_t *, lock, uint64_t, spintime, -+ int, DTRACE_LOCKSTAT_RW_WRITER); -+ } - } - EXPORT_SYMBOL(queued_write_lock_slowpath); -diff --git a/kernel/locking/qspinlock.c b/kernel/locking/qspinlock.c -index cbff6ba53d563634791e27ad8d11e7a683065679..44853c2b018375ca95edd18237496eb4706e3779 100644 ---- a/kernel/locking/qspinlock.c -+++ b/kernel/locking/qspinlock.c -@@ -20,6 +20,7 @@ - #include <linux/hardirq.h> - #include <linux/mutex.h> - #include <linux/prefetch.h> -+#include <linux/sdt.h> - #include <asm/byteorder.h> - #include <asm/qspinlock.h> - -@@ -315,16 +316,20 @@ static __always_inline u32 __pv_wait_head_or_lock(struct qspinlock *lock, - void queued_spin_lock_slowpath(struct qspinlock *lock, u32 val) - { - struct mcs_spinlock *prev, *next, *node; -+ u64 spinstart = 0, spinend, spintime; - u32 old, tail; - int idx; - - BUILD_BUG_ON(CONFIG_NR_CPUS >= (1U << _Q_TAIL_CPU_BITS)); - -+ if (DTRACE_LOCKSTAT_ENABLED(spin__spin)) -+ spinstart = dtrace_gethrtime_ns(); -+ - if (pv_enabled()) - goto pv_queue; - - if (virt_spin_lock(lock)) -- return; -+ goto out; - - /* - * Wait for in-progress pending->locked hand-overs with a bounded -@@ -388,7 +393,7 @@ void queued_spin_lock_slowpath(struct qspinlock *lock, u32 val) - */ - clear_pending_set_locked(lock); - lockevent_inc(lock_pending); -- return; -+ goto out; - - /* - * End of pending bit optimistic spinning and beginning of MCS -@@ -558,6 +563,17 @@ void queued_spin_lock_slowpath(struct qspinlock *lock, u32 val) - * release the node - */ - __this_cpu_dec(qnodes[0].mcs.count); -+ -+ /* -+ * Fire spin-spin probe to note time waiting for a lock. -+ */ -+out: -+ if (DTRACE_LOCKSTAT_ENABLED(spin__spin)) { -+ spinend = dtrace_gethrtime_ns(); -+ spintime = spinend > spinstart ? spinend - spinstart : 0; -+ DTRACE_LOCKSTAT(spin__spin, spinlock_t *, lock, -+ uint64_t, spintime); -+ } - } - EXPORT_SYMBOL(queued_spin_lock_slowpath); - -diff --git a/kernel/sched/core.c b/kernel/sched/core.c -index db893818f3ea5d645ae2418906acd27889722a65..f035f9859ae71cae7880fae416acf72dccd5ffbb 100644 ---- a/kernel/sched/core.c -+++ b/kernel/sched/core.c -@@ -1561,6 +1561,9 @@ static inline void init_uclamp(void) { } - - static inline void enqueue_task(struct rq *rq, struct task_struct *p, int flags) - { -+ DTRACE_SCHED(enqueue, struct task_struct * : (lwpsinfo_t *, -+ psinfo_t *), p, -+ cpuinfo_t *, rq->dtrace_cpu_info); - if (!(flags & ENQUEUE_NOCLOCK)) - update_rq_clock(rq); - -@@ -1575,6 +1578,10 @@ static inline void enqueue_task(struct rq *rq, struct task_struct *p, int flags) - - static inline void dequeue_task(struct rq *rq, struct task_struct *p, int flags) - { -+ DTRACE_SCHED(dequeue, struct task_struct * : (lwpsinfo_t *, -+ psinfo_t *), p, -+ cpuinfo_t *, rq->dtrace_cpu_info, -+ int, 0); - if (!(flags & DEQUEUE_NOCLOCK)) - update_rq_clock(rq); - -@@ -2864,6 +2871,8 @@ try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags) - goto unlock; - - trace_sched_waking(p); -+ DTRACE_SCHED(wakeup, struct task_struct * : (lwpsinfo_t *, -+ psinfo_t *), p); - - /* We're going to change ->state: */ - success = 1; -@@ -3552,6 +3561,8 @@ prepare_task_switch(struct rq *rq, struct task_struct *prev, - sched_info_switch(rq, prev, next); - perf_event_task_sched_out(prev, next); - rseq_preempt(prev); -+ DTRACE_SCHED(off__cpu, struct task_struct * : (lwpsinfo_t *, -+ psinfo_t *), next); - fire_sched_out_preempt_notifiers(prev, next); - prepare_task(next); - prepare_arch_switch(next); -@@ -3625,6 +3636,7 @@ static struct rq *finish_task_switch(struct task_struct *prev) - finish_arch_post_lock_switch(); - kcov_finish_switch(current); - -+ DTRACE_SCHED(on__cpu); - fire_sched_in_preempt_notifiers(current); - /* - * When switching through a kernel thread, the loop in -@@ -3725,6 +3737,8 @@ asmlinkage __visible void schedule_tail(struct task_struct *prev) - put_user(task_pid_vnr(current), current->set_child_tid); - - calculate_sigpending(); -+ DTRACE_PROC(start); -+ DTRACE_PROC(lwp__start); - } - - /* -@@ -4467,6 +4481,7 @@ static void __sched notrace __schedule(bool preempt) - */ - prev_state = prev->state; - if (!preempt && prev_state) { -+ DTRACE_SCHED(sleep); - if (signal_pending_state(prev_state, prev)) { - prev->state = TASK_RUNNING; - } else { -@@ -4497,7 +4512,8 @@ static void __sched notrace __schedule(bool preempt) - } - } - switch_count = &prev->nvcsw; -- } -+ } else -+ DTRACE_SCHED(preempt); - - next = pick_next_task(rq, prev, &rf); - clear_tsk_need_resched(prev); -@@ -4534,6 +4550,7 @@ static void __sched notrace __schedule(bool preempt) - rq = context_switch(rq, prev, next, &rf); - } else { - rq->clock_update_flags &= ~(RQCF_ACT_SKIP|RQCF_REQ_SKIP); -+ DTRACE_SCHED(remain__cpu); - rq_unlock_irq(rq, &rf); - } - -@@ -4999,6 +5016,9 @@ void set_user_nice(struct task_struct *p, long nice) - old_prio = p->prio; - p->prio = effective_prio(p); - -+ DTRACE_SCHED(change__pri, struct task_struct * : (lwpsinfo_t *, -+ psinfo_t *), p, -+ int, old_prio); - if (queued) - enqueue_task(rq, p, ENQUEUE_RESTORE | ENQUEUE_NOCLOCK); - if (running) -@@ -6110,6 +6130,9 @@ static void do_sched_yield(void) - rq_unlock_irq(rq, &rf); - sched_preempt_enable_no_resched(); - -+ DTRACE_SCHED(surrender, -+ struct task_struct * : (lwpsinfo_t *, psinfo_t *), -+ current); - schedule(); - } - -@@ -6256,8 +6279,12 @@ int __sched yield_to(struct task_struct *p, bool preempt) - out_irq: - local_irq_restore(flags); - -- if (yielded > 0) -+ if (yielded > 0) { -+ DTRACE_SCHED(surrender, -+ struct task_struct * : (lwpsinfo_t *, psinfo_t *), -+ curr); - schedule(); -+ } - - return yielded; - } -diff --git a/kernel/signal.c b/kernel/signal.c -index ef8f2a28d37c525b0994701448c026469a533259..23cefab66287227cc4e169a880e67914cb0da978 100644 ---- a/kernel/signal.c -+++ b/kernel/signal.c -@@ -49,6 +49,7 @@ - - #define CREATE_TRACE_POINTS - #include <trace/events/signal.h> -+#include <linux/sdt.h> - - #include <asm/param.h> - #include <linux/uaccess.h> -@@ -1079,8 +1080,12 @@ static int __send_signal(int sig, struct kernel_siginfo *info, struct task_struc - assert_spin_locked(&t->sighand->siglock); - - result = TRACE_SIGNAL_IGNORED; -- if (!prepare_signal(sig, t, force)) -+ if (!prepare_signal(sig, t, force)) { -+ DTRACE_PROC(signal__discard, -+ struct task_struct * : (lwpsinfo_t *, psinfo_t *), t, -+ int, sig); - goto ret; -+ } - - pending = (type != PIDTYPE_PID) ? &t->signal->shared_pending : &t->pending; - /* -@@ -1179,6 +1184,9 @@ static int __send_signal(int sig, struct kernel_siginfo *info, struct task_struc - } - - complete_signal(sig, t, type); -+ DTRACE_PROC(signal__send, -+ struct task_struct * : (lwpsinfo_t *, psinfo_t *), t, -+ int, sig); - ret: - trace_signal_generate(sig, info, t, type != PIDTYPE_PID, result); - return ret; -@@ -1879,6 +1887,9 @@ int send_sigqueue(struct sigqueue *q, struct pid *pid, enum pid_type type) - list_add_tail(&q->list, &pending->list); - sigaddset(&pending->signal, sig); - complete_signal(sig, t, type); -+ DTRACE_PROC(signal__send, -+ struct task_struct * : (lwpsinfo_t *, psinfo_t *), t, -+ int, sig); - result = TRACE_SIGNAL_DELIVERED; - out: - trace_signal_generate(sig, &q->info, t, type != PIDTYPE_PID, result); -@@ -2601,6 +2612,11 @@ bool get_signal(struct ksignal *ksig) - - /* Has this task already been marked for death? */ - if (signal_group_exit(signal)) { -+ DTRACE_PROC(signal__handle, -+ int, signal->group_exit_code -+ ? signal->group_exit_code -+ : signr, -+ siginfo_t *, NULL, void (*)(void), NULL); - ksig->info.si_signo = signr = SIGKILL; - sigdelset(¤t->pending.signal, SIGKILL); - trace_signal_deliver(SIGKILL, SEND_SIG_NOINFO, -@@ -2658,6 +2674,15 @@ bool get_signal(struct ksignal *ksig) - - ka = &sighand->action[signr-1]; - -+ DTRACE_PROC(signal__handle, -+ int, signal->group_exit_code -+ ? signal->group_exit_code -+ : signr, -+ siginfo_t *, ksig->ka.sa.sa_handler != SIG_DFL -+ ? NULL -+ : &ksig->info, -+ void (*)(void), ksig->ka.sa.sa_handler); -+ - /* Trace actually delivered signals. */ - trace_signal_deliver(signr, &ksig->info, ka); - -@@ -3498,8 +3523,10 @@ static int do_sigtimedwait(const sigset_t *which, kernel_siginfo_t *info, - } - spin_unlock_irq(&tsk->sighand->siglock); - -- if (sig) -+ if (sig) { -+ DTRACE_PROC(signal__clear, int, sig); - return sig; -+ } - return ret ? -EINTR : -EAGAIN; - } - -diff --git a/kernel/time/timer.c b/kernel/time/timer.c -index c3ad64fb9d8bd12151cb460e9142976b2460d1f4..a1b822cbdb80561afb288a91baa690f9181dc950 100644 ---- a/kernel/time/timer.c -+++ b/kernel/time/timer.c -@@ -44,6 +44,7 @@ - #include <linux/slab.h> - #include <linux/compat.h> - #include <linux/random.h> -+#include <linux/sdt.h> - - #include <linux/uaccess.h> - #include <asm/unistd.h> -@@ -1702,6 +1703,8 @@ void update_process_times(int user_tick) - struct task_struct *p = current; - - PRANDOM_ADD_NOISE(jiffies, user_tick, p, 0); -+ DTRACE_SCHED(tick, struct task_struct * : (lwpsinfo_t *, psinfo_t *), -+ p); - - /* Note: this timer irq context must be accounted for as well. */ - account_process_tick(p, user_tick); -diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c -index b0c244af1e4d587322b4e3490ad3d878805be670..038868b61cd803760759d6f79fef442d1fe89132 100644 ---- a/net/ipv4/ip_input.c -+++ b/net/ipv4/ip_input.c -@@ -141,6 +141,7 @@ - #include <linux/mroute.h> - #include <linux/netlink.h> - #include <net/dst_metadata.h> -+#include <linux/sdt.h> - - /* - * Process Router Attention IP option (RFC 2113) -@@ -239,16 +240,26 @@ static int ip_local_deliver_finish(struct net *net, struct sock *sk, struct sk_b - */ - int ip_local_deliver(struct sk_buff *skb) - { -+ struct iphdr *iph = ip_hdr(skb); -+ - /* - * Reassemble IP fragments. - */ - struct net *net = dev_net(skb->dev); - -- if (ip_is_fragment(ip_hdr(skb))) { -+ if (ip_is_fragment(iph)) { - if (ip_defrag(net, skb, IP_DEFRAG_LOCAL_DELIVER)) - return 0; - } - -+ DTRACE_IP(receive, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, skb->sk, -+ void_ip_t * : ipinfo_t *, iph, -+ struct net_device * : ifinfo_t *, skb->dev, -+ struct iphdr * : ipv4info_t *, iph, -+ struct ipv6hdr * : ipv6info_t *, NULL); -+ - return NF_HOOK(NFPROTO_IPV4, NF_INET_LOCAL_IN, - net, NULL, skb, skb->dev, NULL, - ip_local_deliver_finish); -@@ -257,7 +268,8 @@ int ip_local_deliver(struct sk_buff *skb) - static inline bool ip_rcv_options(struct sk_buff *skb, struct net_device *dev) - { - struct ip_options *opt; -- const struct iphdr *iph; -+ const struct iphdr *iph = NULL; -+ const char *dropreason; - - /* It looks as overkill, because not all - IP options require packet mangling. -@@ -267,6 +279,7 @@ static inline bool ip_rcv_options(struct sk_buff *skb, struct net_device *dev) - --ANK (980813) - */ - if (skb_cow(skb, skb_headroom(skb))) { -+ dropreason = "copy-on-write failed"; - __IP_INC_STATS(dev_net(dev), IPSTATS_MIB_INDISCARDS); - goto drop; - } -@@ -276,6 +289,7 @@ static inline bool ip_rcv_options(struct sk_buff *skb, struct net_device *dev) - opt->optlen = iph->ihl*4 - sizeof(struct iphdr); - - if (ip_options_compile(dev_net(dev), opt, skb)) { -+ dropreason = "invalid options"; - __IP_INC_STATS(dev_net(dev), IPSTATS_MIB_INHDRERRORS); - goto drop; - } -@@ -289,16 +303,28 @@ static inline bool ip_rcv_options(struct sk_buff *skb, struct net_device *dev) - net_info_ratelimited("source route option %pI4 -> %pI4\n", - &iph->saddr, - &iph->daddr); -+ dropreason = "invalid source route options"; - goto drop; - } - } - -- if (ip_options_rcv_srr(skb, dev)) -+ if (ip_options_rcv_srr(skb, dev)) { -+ dropreason = "invalid options"; - goto drop; -+ } - } - - return false; - drop: -+ DTRACE_IP(drop__in, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, skb->sk, -+ void_ip_t * : ipinfo_t *, iph, -+ struct net_device * : ifinfo_t *, skb->dev, -+ struct iphdr * : ipv4info_t *, iph, -+ struct ipv6hdr * : ipv6info_t *, NULL, -+ const char * : string, dropreason); -+ - return true; - } - -@@ -432,27 +458,35 @@ static int ip_rcv_finish(struct net *net, struct sock *sk, struct sk_buff *skb) - /* - * Main IP Receive routine. - */ --static struct sk_buff *ip_rcv_core(struct sk_buff *skb, struct net *net) -+static struct sk_buff *ip_rcv_core(struct sk_buff *skb, struct net *net, -+ struct net_device *dev -+ __attribute__((__unused__))) - { -- const struct iphdr *iph; -+ const struct iphdr *iph = NULL; - u32 len; -+ const char *dropreason = "header invalid"; - - /* When the interface is in promisc. mode, drop all the crap - * that it receives, do not try to analyse it. - */ -- if (skb->pkt_type == PACKET_OTHERHOST) -+ if (skb->pkt_type == PACKET_OTHERHOST) { -+ dropreason = "for other host"; - goto drop; -+ } - - __IP_UPD_PO_STATS(net, IPSTATS_MIB_IN, skb->len); - - skb = skb_share_check(skb, GFP_ATOMIC); - if (!skb) { -+ dropreason = "could not clone shared buffer"; - __IP_INC_STATS(net, IPSTATS_MIB_INDISCARDS); -- goto out; -+ goto drop; - } - -- if (!pskb_may_pull(skb, sizeof(struct iphdr))) -+ if (!pskb_may_pull(skb, sizeof(struct iphdr))) { -+ dropreason = "could not pull skb"; - goto inhdr_error; -+ } - - iph = ip_hdr(skb); - -@@ -487,6 +521,7 @@ static struct sk_buff *ip_rcv_core(struct sk_buff *skb, struct net *net) - - len = ntohs(iph->tot_len); - if (skb->len < len) { -+ dropreason = "packet too short"; - __IP_INC_STATS(net, IPSTATS_MIB_INTRUNCATEDPKTS); - goto drop; - } else if (len < (iph->ihl*4)) -@@ -497,6 +532,7 @@ static struct sk_buff *ip_rcv_core(struct sk_buff *skb, struct net *net) - * Note this now means skb->len holds ntohs(iph->tot_len). - */ - if (pskb_trim_rcsum(skb, len)) { -+ dropreason = "could not trim buffer"; - __IP_INC_STATS(net, IPSTATS_MIB_INDISCARDS); - goto drop; - } -@@ -516,11 +552,19 @@ static struct sk_buff *ip_rcv_core(struct sk_buff *skb, struct net *net) - - csum_error: - __IP_INC_STATS(net, IPSTATS_MIB_CSUMERRORS); -+ dropreason = "checksum error"; - inhdr_error: - __IP_INC_STATS(net, IPSTATS_MIB_INHDRERRORS); - drop: -+ DTRACE_IP(drop__in, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, skb ? skb->sk : NULL, -+ void_ip_t * : ipinfo_t *, iph, -+ struct net_device * : ifinfo_t *, dev, -+ struct iphdr * : ipv4info_t *, iph, -+ void * : ipv6info_t *, NULL, -+ const char * : string, dropreason); - kfree_skb(skb); --out: - return NULL; - } - -@@ -532,7 +576,7 @@ int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, - { - struct net *net = dev_net(dev); - -- skb = ip_rcv_core(skb, net); -+ skb = ip_rcv_core(skb, net, dev); - if (skb == NULL) - return NET_RX_DROP; - -@@ -623,7 +667,7 @@ void ip_list_rcv(struct list_head *head, struct packet_type *pt, - struct net *net = dev_net(dev); - - skb_list_del_init(skb); -- skb = ip_rcv_core(skb, net); -+ skb = ip_rcv_core(skb, net, dev); - if (skb == NULL) - continue; - -diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c -index 97975bed491addd6bfbe461298a1ce7264f845d7..9e194f4e205055cdbefad6047f7438abaf108275 100644 ---- a/net/ipv4/ip_output.c -+++ b/net/ipv4/ip_output.c -@@ -82,6 +82,7 @@ - #include <linux/netfilter_bridge.h> - #include <linux/netlink.h> - #include <linux/tcp.h> -+#include <linux/sdt.h> - - static int - ip_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, -@@ -112,6 +113,14 @@ int __ip_local_out(struct net *net, struct sock *sk, struct sk_buff *skb) - - skb->protocol = htons(ETH_P_IP); - -+ DTRACE_IP(send, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, sk, -+ void_ip_t * : ipinfo_t *, iph, -+ struct net_device * : ifinfo_t *, skb->dev, -+ struct iphdr * : ipv4info_t *, iph, -+ struct ipv6hdr * : ipv6info_t *, NULL); -+ - return nf_hook(NFPROTO_IPV4, NF_INET_LOCAL_OUT, - net, sk, skb, NULL, skb_dst(skb)->dev, - dst_output); -@@ -983,6 +992,7 @@ static int __ip_append_data(struct sock *sk, - unsigned int wmem_alloc_delta = 0; - bool paged, extra_uref = false; - u32 tskey = 0; -+ const char *dropreason; - - skb = skb_peek_tail(queue); - -@@ -1001,9 +1011,13 @@ static int __ip_append_data(struct sock *sk, - maxnonfragsize = ip_sk_ignore_df(sk) ? IP_MAX_MTU : mtu; - - if (cork->length + length > maxnonfragsize - fragheaderlen) { -+ struct iphdr *iph __attribute__((unused)) = ip_hdr(skb); -+ - ip_local_error(sk, EMSGSIZE, fl4->daddr, inet->inet_dport, - mtu - (opt ? opt->optlen : 0)); -- return -EMSGSIZE; -+ dropreason = "packet too big"; -+ err = -EMSGSIZE; -+ goto error2; - } - - /* -@@ -1103,8 +1117,10 @@ static int __ip_append_data(struct sock *sk, - 2 * sk->sk_sndbuf) - skb = alloc_skb(alloclen + hh_len + 15, - sk->sk_allocation); -- if (unlikely(!skb)) -+ if (unlikely(!skb)) { -+ dropreason = "no buffers"; - err = -ENOBUFS; -+ } - } - if (!skb) - goto error; -@@ -1138,7 +1154,9 @@ static int __ip_append_data(struct sock *sk, - copy = datalen - transhdrlen - fraggap - pagedlen; - if (copy > 0 && getfrag(from, data + transhdrlen, offset, copy, fraggap, skb) < 0) { - err = -EFAULT; -+ dropreason = "could not fragment packet"; - kfree_skb(skb); -+ skb = NULL; - goto error; - } - -@@ -1181,6 +1199,7 @@ static int __ip_append_data(struct sock *sk, - if (getfrag(from, skb_put(skb, copy), - offset, copy, off, skb) < 0) { - __skb_trim(skb, off); -+ dropreason = "could not fragment packet"; - err = -EFAULT; - goto error; - } -@@ -1188,14 +1207,18 @@ static int __ip_append_data(struct sock *sk, - int i = skb_shinfo(skb)->nr_frags; - - err = -ENOMEM; -- if (!sk_page_frag_refill(sk, pfrag)) -+ if (!sk_page_frag_refill(sk, pfrag)) { -+ dropreason = "no memory"; - goto error; -+ } - - if (!skb_can_coalesce(skb, i, pfrag->page, - pfrag->offset)) { - err = -EMSGSIZE; -- if (i == MAX_SKB_FRAGS) -+ if (i == MAX_SKB_FRAGS) { -+ dropreason = "too many fragments"; - goto error; -+ } - - __skb_fill_page_desc(skb, i, pfrag->page, - pfrag->offset, 0); -@@ -1205,8 +1228,10 @@ static int __ip_append_data(struct sock *sk, - copy = min_t(int, copy, pfrag->size - pfrag->offset); - if (getfrag(from, - page_address(pfrag->page) + pfrag->offset, -- offset, copy, skb->len, skb) < 0) -+ offset, copy, skb->len, skb) < 0) { -+ dropreason = "could not framgent packet"; - goto error_efault; -+ } - - pfrag->offset += copy; - skb_frag_size_add(&skb_shinfo(skb)->frags[i - 1], copy); -@@ -1235,6 +1260,16 @@ static int __ip_append_data(struct sock *sk, - cork->length -= length; - IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTDISCARDS); - refcount_add(wmem_alloc_delta, &sk->sk_wmem_alloc); -+error2: -+ DTRACE_IP(drop__out, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, skb ? skb->sk : NULL, -+ void_ip_t * : ipinfo_t *, skb ? ip_hdr(skb) : NULL, -+ struct net_device * : ifinfo_t *, skb ? skb->dev : NULL, -+ struct iphdr * : ipv4info_t *, skb ? ip_hdr(skb) : NULL, -+ struct ipv6hdr * : ipv6info_t *, NULL, -+ const char * : string, dropreason); -+ - return err; - } - -@@ -1338,6 +1373,8 @@ ssize_t ip_append_page(struct sock *sk, struct flowi4 *fl4, struct page *page, - int len; - int err; - unsigned int maxfraglen, fragheaderlen, fraggap, maxnonfragsize; -+ struct iphdr *iph; -+ const char *dropreason; - - if (inet->hdrincl) - return -EPERM; -@@ -1391,6 +1428,7 @@ ssize_t ip_append_page(struct sock *sk, struct flowi4 *fl4, struct page *page, - alloclen = fragheaderlen + hh_len + fraggap + 15; - skb = sock_wmalloc(sk, alloclen, 1, sk->sk_allocation); - if (unlikely(!skb)) { -+ dropreason = "no buffers"; - err = -ENOBUFS; - goto error; - } -@@ -1430,6 +1468,7 @@ ssize_t ip_append_page(struct sock *sk, struct flowi4 *fl4, struct page *page, - len = size; - - if (skb_append_pagefrags(skb, page, offset, len)) { -+ dropreason = "packet too big"; - err = -EMSGSIZE; - goto error; - } -@@ -1452,6 +1491,16 @@ ssize_t ip_append_page(struct sock *sk, struct flowi4 *fl4, struct page *page, - error: - cork->length -= size; - IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTDISCARDS); -+ iph = skb ? ip_hdr(skb) : NULL; -+ DTRACE_IP(drop__out, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, skb ? skb->sk : NULL, -+ void_ip_t * : ipinfo_t *, iph, -+ struct net_device * : ifinfo_t *, skb ? skb->dev : NULL, -+ struct iphdr * : ipv4info_t *, iph, -+ struct ipv6hdr * : ipv6info_t *, NULL, -+ const char * : string, dropreason); -+ - return err; - } - -@@ -1569,8 +1618,18 @@ int ip_send_skb(struct net *net, struct sk_buff *skb) - if (err) { - if (err > 0) - err = net_xmit_errno(err); -- if (err) -+ if (err) { - IP_INC_STATS(net, IPSTATS_MIB_OUTDISCARDS); -+ /* skb may have been freed */ -+ DTRACE_IP(drop__out, -+ struct sk_buff * : pktinfo_t *, NULL, -+ struct sock * : csinfo_t *, NULL, -+ void_ip_t * : ipinfo_t *, NULL, -+ struct net_device * : ifinfo_t *, NULL, -+ struct iphdr * : ipv4info_t *, NULL, -+ struct ipv6hdr * : ipv6info_t *, NULL, -+ char * : string, "packet too short"); -+ } - } - - return err; -diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c -index 7d26e0f8bdaeb5f334e77deb5966a976db3d3ff4..7ae1ad2bad09f98f57f04fe7c034c4e649f489f2 100644 ---- a/net/ipv4/raw.c -+++ b/net/ipv4/raw.c -@@ -75,6 +75,7 @@ - #include <linux/netfilter_ipv4.h> - #include <linux/compat.h> - #include <linux/uio.h> -+#include <linux/sdt.h> - - struct raw_frag_vec { - struct msghdr *msg; -@@ -349,19 +350,25 @@ static int raw_send_hdrinc(struct sock *sk, struct flowi4 *fl4, - struct inet_sock *inet = inet_sk(sk); - struct net *net = sock_net(sk); - struct iphdr *iph; -- struct sk_buff *skb; -+ struct sk_buff *skb = NULL; - unsigned int iphlen; - int err; - struct rtable *rt = *rtp; - int hlen, tlen; -+ const char *dropreason; - - if (length > rt->dst.dev->mtu) { - ip_local_error(sk, EMSGSIZE, fl4->daddr, inet->inet_dport, - rt->dst.dev->mtu); -- return -EMSGSIZE; -+ dropreason = "packet too big"; -+ err = -EMSGSIZE; -+ goto trace_drop; -+ } -+ if (length < sizeof(struct iphdr)) { -+ dropreason = "packet too short"; -+ err = -EINVAL; -+ goto trace_drop; - } -- if (length < sizeof(struct iphdr)) -- return -EINVAL; - - if (flags&MSG_PROBE) - goto out; -@@ -371,8 +378,10 @@ static int raw_send_hdrinc(struct sock *sk, struct flowi4 *fl4, - skb = sock_alloc_send_skb(sk, - length + hlen + tlen + 15, - flags & MSG_DONTWAIT, &err); -- if (!skb) -+ if (!skb) { -+ dropreason = "out of memory"; - goto error; -+ } - skb_reserve(skb, hlen); - - skb->priority = sk->sk_priority; -@@ -394,8 +403,10 @@ static int raw_send_hdrinc(struct sock *sk, struct flowi4 *fl4, - - skb->transport_header = skb->network_header; - err = -EFAULT; -- if (memcpy_from_msg(iph, msg, length)) -+ if (memcpy_from_msg(iph, msg, length)) { -+ dropreason = "could not copy msg"; - goto error_free; -+ } - - iphlen = iph->ihl * 4; - -@@ -407,8 +418,10 @@ static int raw_send_hdrinc(struct sock *sk, struct flowi4 *fl4, - * in, reject the frame as invalid - */ - err = -EINVAL; -- if (iphlen > length) -+ if (iphlen > length) { -+ dropreason = "IP header too big"; - goto error_free; -+ } - - if (iphlen >= sizeof(*iph)) { - if (!iph->saddr) -@@ -426,20 +439,40 @@ static int raw_send_hdrinc(struct sock *sk, struct flowi4 *fl4, - skb_transport_header(skb))->type); - } - -+ DTRACE_IP(send, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, sk, -+ void_ip_t * : ipinfo_t *, iph, -+ struct net_device * : ifinfo_t *, skb->dev, -+ struct iphdr * : ipv4info_t *, iph, -+ struct ipv6hdr * : ipv6info_t *, NULL); -+ - err = NF_HOOK(NFPROTO_IPV4, NF_INET_LOCAL_OUT, - net, sk, skb, NULL, rt->dst.dev, - dst_output); - if (err > 0) - err = net_xmit_errno(err); -- if (err) -+ if (err) { -+ dropreason = "device dropping packets of this priority"; - goto error; -+ } - out: - return 0; - - error_free: - kfree_skb(skb); -+ skb = NULL; - error: - IP_INC_STATS(net, IPSTATS_MIB_OUTDISCARDS); -+trace_drop: -+ DTRACE_IP(drop__out, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, skb ? skb->sk : NULL, -+ void_ip_t * : ipinfo_t *, skb ? ip_hdr(skb) : NULL, -+ struct net_device * : ifinfo_t *, skb ? skb->dev : NULL, -+ struct iphdr * : ipv4info_t *, skb ? ip_hdr(skb) : NULL, -+ struct ipv6hdr * : ipv6info_t *, NULL, -+ const char * : string, dropreason); - if (err == -ENOBUFS && !inet->recverr) - err = 0; - return err; -diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c -index 41d03683b13d6bf613c3bd39b64fdaaa48d2870a..19794603862669bebedb6475604c7415c6407cdb 100644 ---- a/net/ipv4/tcp.c -+++ b/net/ipv4/tcp.c -@@ -267,6 +267,7 @@ - #include <linux/slab.h> - #include <linux/errqueue.h> - #include <linux/static_key.h> -+#include <linux/sdt.h> - - #include <net/icmp.h> - #include <net/inet_common.h> -@@ -2277,6 +2278,19 @@ int tcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int nonblock, - } - EXPORT_SYMBOL(tcp_recvmsg); - -+/* We wish to avoid instrumenting TCP state transitions to SYN_SENT as we trace -+ * those state changes later once the destination address is committed to the -+ * sk. We also need to deal with the fact that separate timewait sockets are -+ * used to handle the TIME_WAIT state. We do not want to trace direct -+ * transitions from CLOSING/FIN_WAIT2 -> CLOSE since they do not represent -+ * connection close, rather a transition to using the timewait socket. -+ * Accordingly skip instrumentation of transitions from CLOSING/FIN_WAIT2 to -+ * CLOSE. -+ */ -+#define REAL_STATE_CHANGE(old, new) \ -+ (old != new && new != TCP_SYN_SENT && \ -+ ((old != TCP_CLOSING && old != TCP_FIN_WAIT2) || new != TCP_CLOSE)) -+ - void tcp_set_state(struct sock *sk, int state) - { - int oldstate = sk->sk_state; -@@ -2329,6 +2343,18 @@ void tcp_set_state(struct sock *sk, int state) - * socket sitting in hash tables. - */ - inet_sk_state_store(sk, state); -+ -+ if (DTRACE_TCP_ENABLED(state__change) && -+ REAL_STATE_CHANGE(oldstate, state)) -+ DTRACE_TCP_NOCHECK(state__change, -+ struct sk_buff * : pktinfo_t *, NULL, -+ struct sock * : csinfo_t *, sk, -+ __dtrace_tcp_void_ip_t * : ipinfo_t *, NULL, -+ struct tcp_sock * : tcpsinfo_t *, tcp_sk(sk), -+ struct tcphdr * : tcpinfo_t *, NULL, -+ int : tcplsinfo_t *, oldstate, -+ int : int, state, -+ int : int, DTRACE_NET_PROBE_OUTBOUND); - } - EXPORT_SYMBOL_GPL(tcp_set_state); - -diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c -index 6bf066f924c15a1e14fe70dd1c90fc4d159bf7f0..e29846f273280fdbc88d491db59ec5ad0c170f20 100644 ---- a/net/ipv4/tcp_input.c -+++ b/net/ipv4/tcp_input.c -@@ -80,6 +80,7 @@ - #include <linux/jump_label_ratelimit.h> - #include <net/busy_poll.h> - #include <net/mptcp.h> -+#include <linux/sdt.h> - - int sysctl_tcp_max_orphans __read_mostly = NR_FILE; - -@@ -5914,6 +5915,14 @@ void tcp_finish_connect(struct sock *sk, struct sk_buff *skb) - struct tcp_sock *tp = tcp_sk(sk); - struct inet_connection_sock *icsk = inet_csk(sk); - -+ DTRACE_TCP(connect__established, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, sk, -+ __dtrace_tcp_void_ip_t * : ipinfo_t *, ip_hdr(skb), -+ struct tcp_sock * : tcpsinfo_t *, tp, -+ struct tcphdr * : tcpinfo_t *, tcp_hdr(skb), -+ int : tcplsinfo_t *, TCP_ESTABLISHED, -+ int, TCP_ESTABLISHED, int, DTRACE_NET_PROBE_INBOUND); - tcp_set_state(sk, TCP_ESTABLISHED); - icsk->icsk_ack.lrcvtime = tcp_jiffies32; - -@@ -6078,6 +6087,17 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, - */ - - if (th->rst) { -+ DTRACE_TCP(connect__refused, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, sk, -+ __dtrace_tcp_void_ip_t * : ipinfo_t *, -+ ip_hdr(skb), -+ struct tcp_sock * : tcpsinfo_t *, tp, -+ struct tcphdr * : tcpinfo_t *, th, -+ int : tcplsinfo_t *, -+ sk ? sk->sk_state : TCP_CLOSE, -+ int, sk ? sk->sk_state : TCP_CLOSE, -+ int, DTRACE_NET_PROBE_INBOUND); - tcp_reset(sk); - goto discard; - } -@@ -6400,6 +6420,16 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb) - WRITE_ONCE(tp->copied_seq, tp->rcv_nxt); - } - smp_mb(); -+ -+ DTRACE_TCP(accept__established, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, sk, -+ __dtrace_tcp_void_ip_t * : ipinfo_t *, ip_hdr(skb), -+ struct tcp_sock * : tcpsinfo_t *, tp, -+ struct tcphdr * : tcpinfo_t *, tcp_hdr(skb), -+ int : tcplsinfo_t *, TCP_ESTABLISHED, -+ int, TCP_ESTABLISHED, -+ int, DTRACE_NET_PROBE_INBOUND); - tcp_set_state(sk, TCP_ESTABLISHED); - sk->sk_state_change(sk); - -@@ -6873,6 +6903,19 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops, - !want_cookie ? TCP_SYNACK_NORMAL : - TCP_SYNACK_COOKIE, - skb); -+ /* Do not pass in tcp sock as ports/addresses are not yet -+ * populated - instead translators will fill them in from -+ * skb data. -+ */ -+ DTRACE_TCP(state__change, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, sk, -+ __dtrace_tcp_void_ip_t * : ipinfo_t *, ip_hdr(skb), -+ struct tcp_sock * : tcpsinfo_t *, NULL, -+ struct tcphdr * : tcpinfo_t *, tcp_hdr(skb), -+ int : tcplsinfo_t *, TCP_LISTEN, -+ int, TCP_SYN_RECV, int, DTRACE_NET_PROBE_INBOUND); -+ - if (want_cookie) { - reqsk_free(req); - return 0; -diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c -index ab8ed0fc476976021332c2fe7d04b55222c8c81d..5f76469093a201b3c5d9916c24725cb305ef4980 100644 ---- a/net/ipv4/tcp_ipv4.c -+++ b/net/ipv4/tcp_ipv4.c -@@ -80,6 +80,7 @@ - - #include <crypto/hash.h> - #include <linux/scatterlist.h> -+#include <linux/sdt.h> - - #include <trace/events/tcp.h> - -@@ -642,6 +643,21 @@ void tcp_v4_send_check(struct sock *sk, struct sk_buff *skb) - } - EXPORT_SYMBOL(tcp_v4_send_check); - -+/* Since we want to trace send events in TCP prior to pushing the segment to -+ * IP - where the IP header is added - we need to construct an argument -+ * containing relevant IP info so that TCP probe consumers can utilize it. -+ */ -+static inline void dtrace_tcp_build_iphdr(__be32 saddr, __be32 daddr, -+ struct iphdr *iph) -+{ -+ iph->version = 4; -+ iph->ihl = 5; -+ iph->tot_len = 5; -+ iph->protocol = IPPROTO_TCP; -+ iph->saddr = saddr; -+ iph->daddr = daddr; -+} -+ - /* - * This routine will send an RST to the other tcp. - * -@@ -800,6 +816,39 @@ static void tcp_v4_send_reset(const struct sock *sk, struct sk_buff *skb) - inet_twsk(sk)->tw_priority : sk->sk_priority; - transmit_time = tcp_transmit_time(sk); - } -+ -+ if (DTRACE_TCP_ENABLED(send) || -+ DTRACE_TCP_ENABLED(accept__refused)) { -+ struct iphdr iph; -+ -+ dtrace_tcp_build_iphdr(ip_hdr(skb)->daddr, ip_hdr(skb)->saddr, -+ &iph); -+ -+ DTRACE_TCP_NOCHECK(send, -+ struct sk_buff * : pktinfo_t *, NULL, -+ struct sock * : csinfo_t *, NULL, -+ __dtrace_tcp_void_ip_t * : ipinfo_t *, &iph, -+ struct tcp_sock * : tcpsinfo_t *, NULL, -+ struct tcphdr * : tcpinfo_t *, &rep.th, -+ int : tcplsinfo_t *, TCP_CLOSE, -+ int : int, TCP_CLOSE, -+ int : int, DTRACE_NET_PROBE_OUTBOUND); -+ if (th->syn && rep.th.seq == 0) -+ DTRACE_TCP_NOCHECK(accept__refused, -+ struct sk_buff * : pktinfo_t *, NULL, -+ struct sock * : csinfo_t *, NULL, -+ __dtrace_tcp_void_ip_t * : -+ ipinfo_t *, &iph, -+ struct tcp_sock * : tcpsinfo_t *, -+ NULL, -+ struct tcphdr * : tcpinfo_t *, -+ &rep.th, -+ int : tcplsinfo_t *, TCP_CLOSE, -+ int : int, TCP_CLOSE, -+ int : int, -+ DTRACE_NET_PROBE_OUTBOUND); -+ } -+ - ip_send_unicast_reply(ctl_sk, - skb, &TCP_SKB_CB(skb)->header.h4.opt, - ip_hdr(skb)->saddr, ip_hdr(skb)->daddr, -@@ -896,6 +945,24 @@ static void tcp_v4_send_ack(const struct sock *sk, - ctl_sk->sk_priority = (sk->sk_state == TCP_TIME_WAIT) ? - inet_twsk(sk)->tw_priority : sk->sk_priority; - transmit_time = tcp_transmit_time(sk); -+ -+ if (DTRACE_TCP_ENABLED(send)) { -+ struct iphdr iph; -+ -+ dtrace_tcp_build_iphdr(ip_hdr(skb)->daddr, ip_hdr(skb)->saddr, -+ &iph); -+ -+ DTRACE_TCP_NOCHECK(send, -+ struct sk_buff * : pktinfo_t *, NULL, -+ struct sock * : csinfo_t *, NULL, -+ __dtrace_tcp_void_ip_t * : ipinfo_t *, &iph, -+ struct tcp_sock * : tcpsinfo_t *, NULL, -+ struct tcphdr * : tcpinfo_t *, &rep, -+ int : tcplsinfo_t *, TCP_CLOSE, -+ int : int, TCP_CLOSE, -+ int : int, DTRACE_NET_PROBE_OUTBOUND); -+ } -+ - ip_send_unicast_reply(ctl_sk, - skb, &TCP_SKB_CB(skb)->header.h4.opt, - ip_hdr(skb)->saddr, ip_hdr(skb)->daddr, -@@ -992,6 +1059,30 @@ static int tcp_v4_send_synack(const struct sock *sk, struct dst_entry *dst, - tcp_bpf_ca_needs_ecn((struct sock *)req)) - tos |= INET_ECN_ECT_0; - -+ if (DTRACE_TCP_ENABLED(send)) { -+ struct iphdr iph; -+ -+ dtrace_tcp_build_iphdr(ireq->ir_loc_addr, -+ ireq->ir_rmt_addr, &iph); -+ -+ /* Do not supply tcp sk - addresses/ports are not -+ * committed yet - instead translators will fill them -+ * in from skb/IP info. -+ */ -+ DTRACE_TCP_NOCHECK(send, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, sk, -+ __dtrace_tcp_void_ip_t * : -+ ipinfo_t *, &iph, -+ struct tcp_sock * : tcpsinfo_t *, -+ NULL, -+ struct tcphdr * : tcpinfo_t *, -+ tcp_hdr(skb), -+ int : tcplsinfo_t *, TCP_LISTEN, -+ int, TCP_LISTEN, -+ int, DTRACE_NET_PROBE_OUTBOUND); -+ } -+ - rcu_read_lock(); - err = ip_build_and_send_pkt(skb, sk, ireq->ir_loc_addr, - ireq->ir_rmt_addr, -@@ -1922,7 +2013,7 @@ int tcp_v4_rcv(struct sk_buff *skb) - const struct iphdr *iph; - const struct tcphdr *th; - bool refcounted; -- struct sock *sk; -+ struct sock *sk = NULL; - int ret; - - if (skb->pkt_type != PACKET_HOST) -@@ -1957,6 +2048,15 @@ int tcp_v4_rcv(struct sk_buff *skb) - if (!sk) - goto no_tcp_socket; - -+ DTRACE_TCP(receive, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, sk, -+ __dtrace_tcp_void_ip_t * : ipinfo_t *, ip_hdr(skb), -+ struct tcp_sock * : tcpsinfo_t *, tcp_sk(sk), -+ struct tcphdr * : tcpinfo_t *, tcp_hdr(skb), -+ int : tcplsinfo_t *, sk ? sk->sk_state : TCP_CLOSE, -+ int, sk ? sk->sk_state : TCP_CLOSE, -+ int, DTRACE_NET_PROBE_INBOUND); - process: - if (sk->sk_state == TCP_TIME_WAIT) - goto do_time_wait; -@@ -2084,6 +2184,18 @@ int tcp_v4_rcv(struct sk_buff *skb) - - discard_it: - /* Discard frame. */ -+ if (DTRACE_TCP_ENABLED(receive) && skb->pkt_type == PACKET_HOST) -+ DTRACE_TCP_NOCHECK(receive, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, sk, -+ __dtrace_tcp_void_ip_t * : ipinfo_t *, -+ ip_hdr(skb), -+ struct tcp_sock * : tcpsinfo_t *, tcp_sk(sk), -+ struct tcphdr * : tcpinfo_t *, tcp_hdr(skb), -+ int : tcplsinfo_t *, -+ sk ? sk->sk_state : TCP_CLOSE, -+ int, sk ? sk->sk_state : TCP_CLOSE, -+ int, DTRACE_NET_PROBE_INBOUND); - kfree_skb(skb); - return 0; - -diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c -index 495dda2449fe5a87f78b8b03f32328328c6b8a01..d2e368b7072d2531fb38d731961d73ece3e4fd04 100644 ---- a/net/ipv4/tcp_minisocks.c -+++ b/net/ipv4/tcp_minisocks.c -@@ -24,6 +24,7 @@ - #include <linux/slab.h> - #include <linux/sysctl.h> - #include <linux/workqueue.h> -+#include <linux/sdt.h> - #include <linux/static_key.h> - #include <net/tcp.h> - #include <net/inet_common.h> -@@ -328,6 +329,20 @@ void tcp_time_wait(struct sock *sk, int state, int timeo) - */ - inet_twsk_hashdance(tw, sk, &tcp_hashinfo); - local_bh_enable(); -+ -+ if (DTRACE_TCP_ENABLED(state__change) && -+ state != sk->sk_state) -+ DTRACE_TCP_NOCHECK(state__change, -+ struct sk_buff * : pktinfo_t *, NULL, -+ struct sock * : csinfo_t *, sk, -+ __dtrace_tcp_void_ip_t * : -+ ipinfo_t *, NULL, -+ struct tcp_sock * : tcpsinfo_t *, -+ tcp_sk(sk), -+ struct tcphdr * : tcpinfo_t *, NULL, -+ int : tcplsinfo_t *, sk->sk_state, -+ int, state, -+ int, DTRACE_NET_PROBE_OUTBOUND); - } else { - /* Sorry, if we're out of memory, just CLOSE this - * socket up. We've got bigger problems than -diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c -index e58e2589d7f98f47bbf83ed57b047d02965034d1..aee3d4d6a2ae3a4c340fb41d98277078c48f53b7 100644 ---- a/net/ipv4/tcp_output.c -+++ b/net/ipv4/tcp_output.c -@@ -44,6 +44,7 @@ - #include <linux/gfp.h> - #include <linux/module.h> - #include <linux/static_key.h> -+#include <linux/sdt.h> - - #include <trace/events/tcp.h> - -@@ -1384,6 +1385,27 @@ static int __tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, - tp->bytes_sent += skb->len - tcp_header_size; - } - -+ DTRACE_TCP(send, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, sk, -+ __dtrace_tcp_void_ip_t * : ipinfo_t *, NULL, -+ struct tcp_sock * : tcpsinfo_t *, tp, -+ struct tcphdr * : tcpinfo_t *, tcp_hdr(skb), -+ int : tcplsinfo_t *, sk->sk_state, int, sk->sk_state, -+ int, DTRACE_NET_PROBE_OUTBOUND); -+ if (DTRACE_TCP_ENABLED(connect__request) && th->syn && -+ th->ack_seq == 0) -+ DTRACE_TCP_NOCHECK(connect__request, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, sk, -+ __dtrace_tcp_void_ip_t * : ipinfo_t *, -+ ip_hdr(skb), -+ struct tcp_sock * : tcpsinfo_t *, tp, -+ struct tcphdr * : tcpinfo_t *, th, -+ int : tcplsinfo_t *, sk->sk_state, -+ int, sk->sk_state, -+ int, DTRACE_NET_PROBE_OUTBOUND); -+ - if (after(tcb->end_seq, tp->snd_nxt) || tcb->seq == tcb->end_seq) - TCP_ADD_STATS(sock_net(sk), TCP_MIB_OUTSEGS, - tcp_skb_pcount(skb)); -@@ -3845,6 +3867,13 @@ int tcp_connect(struct sock *sk) - tp->retrans_stamp = tcp_time_stamp(tp); - tcp_connect_queue_skb(sk, buff); - tcp_ecn_send_syn(sk, buff); -+ DTRACE_TCP(state__change, struct sk_buff * : pktinfo_t *, NULL, -+ struct sock * : csinfo_t *, sk, -+ __dtrace_tcp_void_ip_t * : ipinfo_t *, ip_hdr(buff), -+ struct tcp_sock * : tcpsinfo_t *, tp, -+ struct tcphdr * : tcpinfo_t *, tcp_hdr(buff), -+ int : tcplsinfo_t *, TCP_CLOSE, -+ int, sk->sk_state, int, DTRACE_NET_PROBE_OUTBOUND); - tcp_rbtree_insert(&sk->tcp_rtx_queue, buff); - - /* Send off SYN; include data in Fast Open. */ -diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c -index e37a2fa65c2944c96929a05b3a882abe06228f5a..5d32f5471d8562795022f7f35853d5d1386c007a 100644 ---- a/net/ipv4/udp.c -+++ b/net/ipv4/udp.c -@@ -107,6 +107,7 @@ - #include <trace/events/udp.h> - #include <linux/static_key.h> - #include <linux/btf_ids.h> -+#include <linux/sdt.h> - #include <trace/events/skb.h> - #include <net/busy_poll.h> - #include "udp_impl.h" -@@ -945,6 +946,13 @@ static int udp_send_skb(struct sk_buff *skb, struct flowi4 *fl4, - uh->check = CSUM_MANGLED_0; - - send: -+ DTRACE_UDP(send, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, sk, -+ void_ip_t * : ipinfo_t *, ip_hdr(skb), -+ struct udp_sock * : udpsinfo_t *, udp_sk(sk), -+ struct udphdr * : udpinfo_t *, uh); -+ - err = ip_send_skb(sock_net(sk), skb); - if (err) { - if (err == -ENOBUFS && !inet->recverr) { -@@ -1845,9 +1853,16 @@ int udp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int noblock, - return err; - } - -- if (!peeking) -+ if (!peeking) { -+ DTRACE_UDP(receive, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, sk, -+ void_ip_t * : ipinfo_t *, ip_hdr(skb), -+ struct udp_sock * : udpsinfo_t *, udp_sk(sk), -+ struct udphdr * : udpinfo_t *, udp_hdr(skb)); - UDP_INC_STATS(sock_net(sk), - UDP_MIB_INDATAGRAMS, is_udplite); -+ } - - sock_recv_ts_and_drops(msg, sk, skb); - -@@ -2092,6 +2107,15 @@ static int udp_queue_rcv_one_skb(struct sock *sk, struct sk_buff *skb) - - ret = encap_rcv(sk, skb); - if (ret <= 0) { -+ DTRACE_UDP(receive, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, sk, -+ void_ip_t * : ipinfo_t *, -+ ip_hdr(skb), -+ struct udp_sock * : udpsinfo_t *, -+ udp_sk(sk), -+ struct udphdr * : udpinfo_t *, -+ udp_hdr(skb)); - __UDP_INC_STATS(sock_net(sk), - UDP_MIB_INDATAGRAMS, - is_udplite); -diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c -index e96304d8a4a7f70cae11754ac7532c58d61fb261..aed39e366b60565ac1eaf65c26aba2071f539c03 100644 ---- a/net/ipv6/ip6_input.c -+++ b/net/ipv6/ip6_input.c -@@ -43,6 +43,7 @@ - #include <net/xfrm.h> - #include <net/inet_ecn.h> - #include <net/dst_metadata.h> -+#include <linux/sdt.h> - - INDIRECT_CALLABLE_DECLARE(void udp_v6_early_demux(struct sk_buff *)); - INDIRECT_CALLABLE_DECLARE(void tcp_v6_early_demux(struct sk_buff *)); -@@ -145,13 +146,14 @@ static void ip6_list_rcv_finish(struct net *net, struct sock *sk, - static struct sk_buff *ip6_rcv_core(struct sk_buff *skb, struct net_device *dev, - struct net *net) - { -- const struct ipv6hdr *hdr; -+ const struct ipv6hdr *hdr = NULL; - u32 pkt_len; - struct inet6_dev *idev; -+ const char *dropreason; - - if (skb->pkt_type == PACKET_OTHERHOST) { -- kfree_skb(skb); -- return NULL; -+ dropreason = "for other host"; -+ goto trace_drop; - } - - rcu_read_lock(); -@@ -163,6 +165,7 @@ static struct sk_buff *ip6_rcv_core(struct sk_buff *skb, struct net_device *dev, - if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL || - !idev || unlikely(idev->cnf.disable_ipv6)) { - __IP6_INC_STATS(net, idev, IPSTATS_MIB_INDISCARDS); -+ dropreason = "could not clone shared buffer"; - goto drop; - } - -@@ -181,13 +184,18 @@ static struct sk_buff *ip6_rcv_core(struct sk_buff *skb, struct net_device *dev, - */ - IP6CB(skb)->iif = skb_valid_dst(skb) ? ip6_dst_idev(skb_dst(skb))->dev->ifindex : dev->ifindex; - -- if (unlikely(!pskb_may_pull(skb, sizeof(*hdr)))) -+ if (unlikely(!pskb_may_pull(skb, sizeof(*hdr)))) { -+ hdr = ipv6_hdr(skb); -+ dropreason = "could not pull skb"; - goto err; -+ } - - hdr = ipv6_hdr(skb); - -- if (hdr->version != 6) -+ if (hdr->version != 6) { -+ dropreason = "header invalid"; - goto err; -+ } - - __IP6_ADD_STATS(net, idev, - IPSTATS_MIB_NOECTPKTS + -@@ -203,8 +211,10 @@ static struct sk_buff *ip6_rcv_core(struct sk_buff *skb, struct net_device *dev, - if ((ipv6_addr_loopback(&hdr->saddr) || - ipv6_addr_loopback(&hdr->daddr)) && - !(dev->flags & IFF_LOOPBACK) && -- !netif_is_l3_master(dev)) -+ !netif_is_l3_master(dev)) { -+ dropreason = "loopback destination received on interface"; - goto err; -+ } - - /* RFC4291 Errata ID: 3480 - * Interface-Local scope spans only a single interface on a -@@ -215,8 +225,10 @@ static struct sk_buff *ip6_rcv_core(struct sk_buff *skb, struct net_device *dev, - if (!(skb->pkt_type == PACKET_LOOPBACK || - dev->flags & IFF_LOOPBACK) && - ipv6_addr_is_multicast(&hdr->daddr) && -- IPV6_ADDR_MC_SCOPE(&hdr->daddr) == 1) -+ IPV6_ADDR_MC_SCOPE(&hdr->daddr) == 1) { -+ dropreason = "interface-local scope received from other node"; - goto err; -+ } - - /* If enabled, drop unicast packets that were encapsulated in link-layer - * multicast or broadcast to protected against the so-called "hole-196" -@@ -225,8 +237,10 @@ static struct sk_buff *ip6_rcv_core(struct sk_buff *skb, struct net_device *dev, - if (!ipv6_addr_is_multicast(&hdr->daddr) && - (skb->pkt_type == PACKET_BROADCAST || - skb->pkt_type == PACKET_MULTICAST) && -- idev->cnf.drop_unicast_in_l2_multicast) -+ idev->cnf.drop_unicast_in_l2_multicast) { -+ dropreason = "unicast packet encapsulated in multi/broadcast"; - goto err; -+ } - - /* RFC4291 2.7 - * Nodes must not originate a packet to a multicast address whose scope -@@ -234,16 +248,21 @@ static struct sk_buff *ip6_rcv_core(struct sk_buff *skb, struct net_device *dev, - * must be silently dropped. - */ - if (ipv6_addr_is_multicast(&hdr->daddr) && -- IPV6_ADDR_MC_SCOPE(&hdr->daddr) == 0) -+ IPV6_ADDR_MC_SCOPE(&hdr->daddr) == 0) { -+ dropreason = -+ "packet to multicast address with reserved scope 0"; - goto err; -+ } - - /* - * RFC4291 2.7 - * Multicast addresses must not be used as source addresses in IPv6 - * packets or appear in any Routing header. - */ -- if (ipv6_addr_is_multicast(&hdr->saddr)) -+ if (ipv6_addr_is_multicast(&hdr->saddr)) { -+ dropreason = "multicast source address in IPv6 packet"; - goto err; -+ } - - /* While RFC4291 is not explicit about v4mapped addresses - * in IPv6 headers, it seems clear linux dual-stack -@@ -253,7 +272,10 @@ static struct sk_buff *ip6_rcv_core(struct sk_buff *skb, struct net_device *dev, - * https://tools.ietf.org/html/draft-itojun-v6ops-v4mapped-harmful-02 - */ - if (ipv6_addr_v4mapped(&hdr->saddr)) -+ { -+ dropreason = "v4-mapped address in IPv6 packet"; - goto err; -+ } - - skb->transport_header = skb->network_header + sizeof(*hdr); - IP6CB(skb)->nhoff = offsetof(struct ipv6hdr, nexthdr); -@@ -265,10 +287,12 @@ static struct sk_buff *ip6_rcv_core(struct sk_buff *skb, struct net_device *dev, - if (pkt_len + sizeof(struct ipv6hdr) > skb->len) { - __IP6_INC_STATS(net, - idev, IPSTATS_MIB_INTRUNCATEDPKTS); -+ dropreason = "truncated packet"; - goto drop; - } - if (pskb_trim_rcsum(skb, pkt_len + sizeof(struct ipv6hdr))) { - __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS); -+ dropreason = "could not trim buffer"; - goto drop; - } - hdr = ipv6_hdr(skb); -@@ -276,9 +300,10 @@ static struct sk_buff *ip6_rcv_core(struct sk_buff *skb, struct net_device *dev, - - if (hdr->nexthdr == NEXTHDR_HOP) { - if (ipv6_parse_hopopts(skb) < 0) { -- __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS); -- rcu_read_unlock(); -- return NULL; -+ dropreason = "could not parse hop opts"; -+ /* do not free skb */ -+ skb = NULL; -+ goto err; - } - } - -@@ -293,6 +318,15 @@ static struct sk_buff *ip6_rcv_core(struct sk_buff *skb, struct net_device *dev, - __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS); - drop: - rcu_read_unlock(); -+trace_drop: -+ DTRACE_IP(drop__in, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, skb ? skb->sk : NULL, -+ void_ip_t * : ipinfo_t *, hdr, -+ struct net_device * : ifinfo_t *, skb ? skb->dev : NULL, -+ struct iphdr * : ipv4info_t *, NULL, -+ struct ipv6hdr * : ipv6info_t *, hdr, -+ const char * : string, dropreason); - kfree_skb(skb); - return NULL; - } -@@ -365,6 +399,8 @@ void ip6_protocol_deliver_rcu(struct net *net, struct sk_buff *skb, int nexthdr, - struct inet6_dev *idev; - unsigned int nhoff; - bool raw; -+ const struct ipv6hdr *hdr; -+ const char *dropreason; - - /* - * Parse extension headers -@@ -374,8 +410,10 @@ void ip6_protocol_deliver_rcu(struct net *net, struct sk_buff *skb, int nexthdr, - idev = ip6_dst_idev(skb_dst(skb)); - nhoff = IP6CB(skb)->nhoff; - if (!have_final) { -- if (!pskb_pull(skb, skb_transport_offset(skb))) -+ if (!pskb_pull(skb, skb_transport_offset(skb))) { -+ dropreason = "could not pull skb"; - goto discard; -+ } - nexthdr = skb_network_header(skb)[nhoff]; - } - -@@ -392,10 +430,10 @@ void ip6_protocol_deliver_rcu(struct net *net, struct sk_buff *skb, int nexthdr, - * ones. This allows foo in UDP encapsulation - * to work. - */ -+ dropreason = "non-final protocol"; - goto discard; - } - } else if (ipprot->flags & INET6_PROTO_FINAL) { -- const struct ipv6hdr *hdr; - int sdif = inet6_sdif(skb); - struct net_device *dev; - -@@ -414,8 +452,10 @@ void ip6_protocol_deliver_rcu(struct net *net, struct sk_buff *skb, int nexthdr, - /* skb->dev passed may be master dev for vrfs. */ - if (sdif) { - dev = dev_get_by_index_rcu(net, sdif); -- if (!dev) -+ if (!dev) { -+ dropreason = "device disappeared"; - goto discard; -+ } - } else { - dev = skb->dev; - } -@@ -423,12 +463,16 @@ void ip6_protocol_deliver_rcu(struct net *net, struct sk_buff *skb, int nexthdr, - if (ipv6_addr_is_multicast(&hdr->daddr) && - !ipv6_chk_mcast_addr(dev, &hdr->daddr, - &hdr->saddr) && -- !ipv6_is_mld(skb, nexthdr, skb_network_header_len(skb))) -+ !ipv6_is_mld(skb, nexthdr, skb_network_header_len(skb))) { -+ dropreason = "destination is multicast"; - goto discard; -+ } - } - if (!(ipprot->flags & INET6_PROTO_NOPOLICY) && -- !xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) -+ !xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) { -+ dropreason = "policy failure"; - goto discard; -+ } - - ret = INDIRECT_CALL_2(ipprot->handler, tcp_v6_rcv, udpv6_rcv, - skb); -@@ -454,6 +498,8 @@ void ip6_protocol_deliver_rcu(struct net *net, struct sk_buff *skb, int nexthdr, - IPSTATS_MIB_INUNKNOWNPROTOS); - icmpv6_send(skb, ICMPV6_PARAMPROB, - ICMPV6_UNK_NEXTHDR, nhoff); -+ dropreason = "policy failure"; -+ goto trace_drop; - } - kfree_skb(skb); - } else { -@@ -465,6 +511,17 @@ void ip6_protocol_deliver_rcu(struct net *net, struct sk_buff *skb, int nexthdr, - - discard: - __IP6_INC_STATS(net, idev, IPSTATS_MIB_INDISCARDS); -+trace_drop: -+ hdr = ipv6_hdr(skb); -+ DTRACE_IP(drop__in, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, skb->sk, -+ void_ip_t * : ipinfo_t *, hdr, -+ struct net_device * : ifinfo_t *, skb->dev, -+ struct iphdr * : ipv4info_t *, NULL, -+ struct ipv6hdr * : ipv6info_t *, hdr, -+ const char * : string, dropreason); -+ rcu_read_unlock(); - kfree_skb(skb); - } - -@@ -480,6 +537,16 @@ static int ip6_input_finish(struct net *net, struct sock *sk, struct sk_buff *sk - - int ip6_input(struct sk_buff *skb) - { -+ struct ipv6hdr *hdr = ipv6_hdr(skb); -+ -+ DTRACE_IP(receive, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, skb->sk, -+ void_ip_t * : ipinfo_t *, hdr, -+ struct net_device * : ifinfo_t *, skb->dev, -+ struct iphdr * : ipv4info_t *, NULL, -+ struct ipv6hdr * : ipv6info_t *, hdr); -+ - return NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_IN, - dev_net(skb->dev), NULL, skb, skb->dev, NULL, - ip6_input_finish); -diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c -index 077d43af8226bd202be878885eaaf274776bf648..1c972fb379b5f6e21e0905cdce54e2dff39001d4 100644 ---- a/net/ipv6/ip6_output.c -+++ b/net/ipv6/ip6_output.c -@@ -55,6 +55,7 @@ - #include <net/l3mdev.h> - #include <net/lwtunnel.h> - #include <net/ip_tunnels.h> -+#include <linux/sdt.h> - - static int ip6_finish_output2(struct net *net, struct sock *sk, struct sk_buff *skb) - { -@@ -62,7 +63,8 @@ static int ip6_finish_output2(struct net *net, struct sock *sk, struct sk_buff * - struct net_device *dev = dst->dev; - const struct in6_addr *nexthop; - struct neighbour *neigh; -- int ret; -+ const char *dropreason; -+ int ret = 0; - - if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr)) { - struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb)); -@@ -83,10 +85,11 @@ static int ip6_finish_output2(struct net *net, struct sock *sk, struct sk_buff * - dev_loopback_xmit); - - if (ipv6_hdr(skb)->hop_limit == 0) { -+ dropreason = "hoplimit exceeded"; -+ - IP6_INC_STATS(net, idev, - IPSTATS_MIB_OUTDISCARDS); -- kfree_skb(skb); -- return 0; -+ goto drop; - } - } - -@@ -95,8 +98,8 @@ static int ip6_finish_output2(struct net *net, struct sock *sk, struct sk_buff * - if (IPV6_ADDR_MC_SCOPE(&ipv6_hdr(skb)->daddr) <= - IPV6_ADDR_SCOPE_NODELOCAL && - !(dev->flags & IFF_LOOPBACK)) { -- kfree_skb(skb); -- return 0; -+ dropreason = "invalid scope"; -+ goto drop; - } - } - -@@ -120,9 +123,20 @@ static int ip6_finish_output2(struct net *net, struct sock *sk, struct sk_buff * - } - rcu_read_unlock_bh(); - -+ dropreason = "no route to host"; - IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES); -+ ret = -EINVAL; -+drop: -+ DTRACE_IP(drop__out, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, skb->sk, -+ void_ip_t * : ipinfo_t *, ipv6_hdr(skb), -+ struct net_device * : ifinfo_t *, skb->dev, -+ struct iphdr * : ipv4info_t *, NULL, -+ struct ipv6hdr * : ipv6info_t *, ipv6_hdr(skb), -+ const char * : string, dropreason); - kfree_skb(skb); -- return -EINVAL; -+ return ret; - } - - static int -@@ -207,6 +221,15 @@ int ip6_output(struct net *net, struct sock *sk, struct sk_buff *skb) - skb->dev = dev; - - if (unlikely(idev->cnf.disable_ipv6)) { -+ DTRACE_IP(drop__out, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, skb->sk, -+ void_ip_t * : ipinfo_t *, NULL, -+ struct net_device * : ifinfo_t *, skb->dev, -+ struct iphdr * : ipv4info_t *, NULL, -+ struct ipv6hdr * : ipv6info_t *, NULL, -+ const char * : string, "IPv6 is disabled"); -+ - IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTDISCARDS); - kfree_skb(skb); - return 0; -@@ -243,8 +266,10 @@ int ip6_xmit(const struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6, - struct ipv6hdr *hdr; - u8 proto = fl6->flowi6_proto; - int seg_len = skb->len; -+ const char *dropreason; - int hlimit = -1; - u32 mtu; -+ int err; - - head_room = sizeof(struct ipv6hdr) + LL_RESERVED_SPACE(dst->dev); - if (opt) -@@ -253,10 +278,12 @@ int ip6_xmit(const struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6, - if (unlikely(skb_headroom(skb) < head_room)) { - struct sk_buff *skb2 = skb_realloc_headroom(skb, head_room); - if (!skb2) { -+ dropreason = "out of memory"; - IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), - IPSTATS_MIB_OUTDISCARDS); - kfree_skb(skb); -- return -ENOBUFS; -+ err = -ENOBUFS; -+ goto drop; - } - if (skb->sk) - skb_set_owner_w(skb2, skb->sk); -@@ -313,6 +340,14 @@ int ip6_xmit(const struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6, - if (unlikely(!skb)) - return 0; - -+ DTRACE_IP(send, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, skb->sk, -+ void_ip_t * : ipinfo_t *, hdr, -+ struct net_device * : ifinfo_t *, skb->dev, -+ struct iphdr * : ipv4info_t *, NULL, -+ struct ipv6hdr * : ipv6info_t *, hdr); -+ - /* hooks should never assume socket lock is held. - * we promote our socket to non const - */ -@@ -327,9 +362,21 @@ int ip6_xmit(const struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6, - */ - ipv6_local_error((struct sock *)sk, EMSGSIZE, fl6, mtu); - -+ dropreason = "fragmentation failure"; - IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_FRAGFAILS); -+ err = -EMSGSIZE; -+drop: -+ DTRACE_IP(drop__out, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, skb->sk, -+ void_ip_t * : ipinfo_t *, NULL, -+ struct net_device * : ifinfo_t *, skb->dev, -+ struct iphdr * : ipv4info_t *, NULL, -+ struct ipv6hdr * : ipv6info_t *, NULL, -+ const char * : string, dropreason); -+ - kfree_skb(skb); -- return -EMSGSIZE; -+ return err; - } - EXPORT_SYMBOL(ip6_xmit); - -@@ -464,22 +511,33 @@ int ip6_forward(struct sk_buff *skb) - struct ipv6hdr *hdr = ipv6_hdr(skb); - struct inet6_skb_parm *opt = IP6CB(skb); - struct net *net = dev_net(dst->dev); -+ const char *dropreason; -+ int err = -EINVAL; - u32 mtu; - -- if (net->ipv6.devconf_all->forwarding == 0) -+ if (net->ipv6.devconf_all->forwarding == 0) { -+ dropreason = "forwarding disabled"; - goto error; -+ } - -- if (skb->pkt_type != PACKET_HOST) -+ if (skb->pkt_type != PACKET_HOST) { -+ dropreason = "non-host packet type cannot be forwarded"; - goto drop; -+ } - -- if (unlikely(skb->sk)) -+ if (unlikely(skb->sk)) { -+ dropreason = "socket found for packet to be forwarded"; - goto drop; -+ } - -- if (skb_warn_if_lro(skb)) -+ if (skb_warn_if_lro(skb)) { -+ dropreason = "LRO warning"; - goto drop; -+ } - - if (!xfrm6_policy_check(NULL, XFRM_POLICY_FWD, skb)) { - __IP6_INC_STATS(net, idev, IPSTATS_MIB_INDISCARDS); -+ dropreason = "forwarding disabled by policy"; - goto drop; - } - -@@ -510,8 +568,9 @@ int ip6_forward(struct sk_buff *skb) - icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT, 0); - __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS); - -- kfree_skb(skb); -- return -ETIMEDOUT; -+ dropreason = "hoplimit exceeded"; -+ err = -ETIMEDOUT; -+ goto drop; - } - - /* XXX: idev->cnf.proxy_ndp? */ -@@ -521,6 +580,7 @@ int ip6_forward(struct sk_buff *skb) - if (proxied > 0) - return ip6_input(skb); - else if (proxied < 0) { -+ dropreason = "proxy router cannot forward"; - __IP6_INC_STATS(net, idev, IPSTATS_MIB_INDISCARDS); - goto drop; - } -@@ -528,6 +588,7 @@ int ip6_forward(struct sk_buff *skb) - - if (!xfrm6_route_forward(skb)) { - __IP6_INC_STATS(net, idev, IPSTATS_MIB_INDISCARDS); -+ dropreason = "forwarding disabled for destination"; - goto drop; - } - dst = skb_dst(skb); -@@ -567,9 +628,12 @@ int ip6_forward(struct sk_buff *skb) - - /* This check is security critical. */ - if (addrtype == IPV6_ADDR_ANY || -- addrtype & (IPV6_ADDR_MULTICAST | IPV6_ADDR_LOOPBACK)) -+ addrtype & (IPV6_ADDR_MULTICAST | IPV6_ADDR_LOOPBACK)) { -+ dropreason = "invalid address type for forwarding"; - goto error; -+ } - if (addrtype & IPV6_ADDR_LINKLOCAL) { -+ dropreason = "invalid address type for forwarding"; - icmpv6_send(skb, ICMPV6_DEST_UNREACH, - ICMPV6_NOT_NEIGHBOUR, 0); - goto error; -@@ -583,17 +647,20 @@ int ip6_forward(struct sk_buff *skb) - if (ip6_pkt_too_big(skb, mtu)) { - /* Again, force OUTPUT device used as source address */ - skb->dev = dst->dev; -+ - icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); - __IP6_INC_STATS(net, idev, IPSTATS_MIB_INTOOBIGERRORS); - __IP6_INC_STATS(net, ip6_dst_idev(dst), - IPSTATS_MIB_FRAGFAILS); -- kfree_skb(skb); -- return -EMSGSIZE; -+ dropreason = "packet too big"; -+ err = -EMSGSIZE; -+ goto drop; - } - - if (skb_cow(skb, dst->dev->hard_header_len)) { - __IP6_INC_STATS(net, ip6_dst_idev(dst), - IPSTATS_MIB_OUTDISCARDS); -+ dropreason = "copy-on-write failed"; - goto drop; - } - -@@ -610,6 +677,15 @@ int ip6_forward(struct sk_buff *skb) - error: - __IP6_INC_STATS(net, idev, IPSTATS_MIB_INADDRERRORS); - drop: -+ DTRACE_IP(drop__out, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, skb->sk, -+ void_ip_t * : ipinfo_t *, hdr, -+ struct net_device * : ifinfo_t *, skb->dev, -+ struct iphdr * : ipv4info_t *, NULL, -+ struct ipv6hdr * : ipv6info_t *, hdr, -+ const char * : string, dropreason); -+ - kfree_skb(skb); - return -EINVAL; - } -@@ -1445,6 +1521,7 @@ static int __ip6_append_data(struct sock *sk, - unsigned int maxnonfragsize, headersize; - unsigned int wmem_alloc_delta = 0; - bool paged, extra_uref = false; -+ const char *dropreason; - - skb = skb_peek_tail(queue); - if (!skb) { -@@ -1484,6 +1561,7 @@ static int __ip6_append_data(struct sock *sk, - sk->sk_protocol == IPPROTO_RAW)) { - ipv6_local_rxpmtu(sk, fl6, mtu - headersize + - sizeof(struct ipv6hdr)); -+ dropreason = "fragmentation needed but disabled"; - goto emsgsize; - } - -@@ -1496,7 +1574,9 @@ static int __ip6_append_data(struct sock *sk, - emsgsize: - pmtu = max_t(int, mtu - headersize + sizeof(struct ipv6hdr), 0); - ipv6_local_error(sk, EMSGSIZE, fl6, pmtu); -- return -EMSGSIZE; -+ dropreason = "packet too big"; -+ err = -EMSGSIZE; -+ goto trace_drop; - } - - /* CHECKSUM_PARTIAL only with no extension headers and when -@@ -1511,8 +1591,11 @@ static int __ip6_append_data(struct sock *sk, - - if (flags & MSG_ZEROCOPY && length && sock_flag(sk, SOCK_ZEROCOPY)) { - uarg = sock_zerocopy_realloc(sk, length, skb_zcopy(skb)); -- if (!uarg) -- return -ENOBUFS; -+ if (!uarg) { -+ err = -ENOBUFS; -+ dropreason = "out of memory"; -+ goto error; -+ } - extra_uref = !skb_zcopy(skb); /* only ref on new uarg */ - if (rt->dst.dev->features & NETIF_F_SG && - csummode == CHECKSUM_PARTIAL) { -@@ -1614,6 +1697,7 @@ static int __ip6_append_data(struct sock *sk, - copy = datalen - transhdrlen - fraggap - pagedlen; - if (copy < 0) { - err = -EINVAL; -+ dropreason = "invalid fragment"; - goto error; - } - if (transhdrlen) { -@@ -1626,11 +1710,13 @@ static int __ip6_append_data(struct sock *sk, - 2 * sk->sk_sndbuf) - skb = alloc_skb(alloclen + hh_len, - sk->sk_allocation); -- if (unlikely(!skb)) -- err = -ENOBUFS; - } -- if (!skb) -+ if (unlikely(!skb)) { -+ err = -ENOBUFS; -+ dropreason = "out of memory"; - goto error; -+ } -+ - /* - * Fill in the control structures - */ -@@ -1662,7 +1748,9 @@ static int __ip6_append_data(struct sock *sk, - getfrag(from, data + transhdrlen, offset, - copy, fraggap, skb) < 0) { - err = -EFAULT; -+ dropreason = "could not get fragment"; - kfree_skb(skb); -+ skb = NULL; - goto error; - } - -@@ -1706,20 +1794,25 @@ static int __ip6_append_data(struct sock *sk, - offset, copy, off, skb) < 0) { - __skb_trim(skb, off); - err = -EFAULT; -+ dropreason = "could not get fragment"; - goto error; - } - } else if (!uarg || !uarg->zerocopy) { - int i = skb_shinfo(skb)->nr_frags; - - err = -ENOMEM; -- if (!sk_page_frag_refill(sk, pfrag)) -+ if (!sk_page_frag_refill(sk, pfrag)) { -+ dropreason = "out of memory"; - goto error; -+ } - - if (!skb_can_coalesce(skb, i, pfrag->page, - pfrag->offset)) { - err = -EMSGSIZE; -- if (i == MAX_SKB_FRAGS) -+ if (i == MAX_SKB_FRAGS) { -+ dropreason = "too many fragments"; - goto error; -+ } - - __skb_fill_page_desc(skb, i, pfrag->page, - pfrag->offset, 0); -@@ -1729,8 +1822,10 @@ static int __ip6_append_data(struct sock *sk, - copy = min_t(int, copy, pfrag->size - pfrag->offset); - if (getfrag(from, - page_address(pfrag->page) + pfrag->offset, -- offset, copy, skb->len, skb) < 0) -+ offset, copy, skb->len, skb) < 0) { -+ dropreason = "could not get fragment"; - goto error_efault; -+ } - - pfrag->offset += copy; - skb_frag_size_add(&skb_shinfo(skb)->frags[i - 1], copy); -@@ -1740,8 +1835,10 @@ static int __ip6_append_data(struct sock *sk, - wmem_alloc_delta += copy; - } else { - err = skb_zerocopy_iter_dgram(skb, from, copy); -- if (err < 0) -+ if (err < 0) { -+ dropreason = "skb iteration failure\n"; - goto error; -+ } - } - offset += copy; - length -= copy; -@@ -1758,6 +1855,16 @@ static int __ip6_append_data(struct sock *sk, - sock_zerocopy_put_abort(uarg, extra_uref); - cork->length -= length; - IP6_INC_STATS(sock_net(sk), rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS); -+trace_drop: -+ DTRACE_IP(drop__out, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, skb ? skb->sk : NULL, -+ void_ip_t * : ipinfo_t *, NULL, -+ struct net_device * : ifinfo_t *, skb ? skb->dev : NULL, -+ struct iphdr * : ipv4info_t *, NULL, -+ struct ipv6hdr * : ipv6info_t *, NULL, -+ const char * : string, dropreason); -+ - refcount_add(wmem_alloc_delta, &sk->sk_wmem_alloc); - return err; - } -@@ -1905,9 +2012,20 @@ int ip6_send_skb(struct sk_buff *skb) - if (err) { - if (err > 0) - err = net_xmit_errno(err); -- if (err) -+ if (err) { -+ /* skb may have been freed */ -+ DTRACE_IP(drop__out, -+ struct sk_buff * : pktinfo_t *, NULL, -+ struct sock * : csinfo_t *, NULL, -+ void_ip_t * : ipinfo_t *, NULL, -+ struct net_device * : ifinfo_t *, NULL, -+ struct iphdr * : ipv4info_t *, NULL, -+ struct ipv6hdr * : ipv6info_t *, NULL, -+ const char * : string, "out of memory"); -+ - IP6_INC_STATS(net, rt->rt6i_idev, - IPSTATS_MIB_OUTDISCARDS); -+ } - } - - return err; -@@ -1933,9 +2051,19 @@ static void __ip6_flush_pending_frames(struct sock *sk, - struct sk_buff *skb; - - while ((skb = __skb_dequeue_tail(queue)) != NULL) { -- if (skb_dst(skb)) -+ if (skb_dst(skb)) { -+ DTRACE_IP(drop__out, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, skb->sk, -+ void_ip_t * : ipinfo_t *, ipv6_hdr(skb), -+ struct net_device * : ifinfo_t *, skb->dev, -+ struct iphdr * : ipv4info_t *, NULL, -+ struct ipv6hdr * : ipv6info_t *, -+ ipv6_hdr(skb), -+ const char * : string, "flushing pending frames"); - IP6_INC_STATS(sock_net(sk), ip6_dst_idev(skb_dst(skb)), - IPSTATS_MIB_OUTDISCARDS); -+ } - kfree_skb(skb); - } - -diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c -index 8cd2782a31e4c38e227064cdb60eaccf45352192..e90cb6e0781d367146da70c59ed12bc757819792 100644 ---- a/net/ipv6/mcast.c -+++ b/net/ipv6/mcast.c -@@ -60,6 +60,8 @@ - - #include <net/ip6_checksum.h> - -+#include <linux/sdt.h> -+ - /* Ensure that we have struct in6_addr aligned on 32bit word. */ - static int __mld2_query_bugs[] __attribute__((__unused__)) = { - BUILD_BUG_ON_ZERO(offsetof(struct mld2_query, mld2q_srcs) % 4), -@@ -1644,6 +1646,7 @@ static void mld_sendpack(struct sk_buff *skb) - int payload_len, mldlen; - struct inet6_dev *idev; - struct net *net = dev_net(skb->dev); -+ const char *dropreason; - int err; - struct flowi6 fl6; - struct dst_entry *dst; -@@ -1673,26 +1676,45 @@ static void mld_sendpack(struct sk_buff *skb) - dst = NULL; - } - skb_dst_set(skb, dst); -- if (err) -- goto err_out; -+ if (err) { -+ kfree_skb(skb); -+ skb = NULL; -+ dropreason = "out of memory"; -+ goto out; -+ } -+ -+ DTRACE_IP(send, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, skb->sk, -+ void_ip_t * : ipinfo_t *, ipv6_hdr(skb), -+ struct net_device * : ifinfo_t *, skb->dev, -+ struct iphdr * : ipv4info_t *, NULL, -+ struct ipv6hdr * : ipv6info_t *, ipv6_hdr(skb)); - - err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, - net, net->ipv6.igmp_sk, skb, NULL, skb->dev, - dst_output); -+ dropreason = "multicast send error"; - out: - if (!err) { - ICMP6MSGOUT_INC_STATS(net, idev, ICMPV6_MLD2_REPORT); - ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS); - } else { -+ /* skb may have been freed */ -+ DTRACE_IP(drop__out, -+ struct sk_buff * : pktinfo_t *, NULL, -+ struct sock * : csinfo_t *, NULL, -+ void_ip_t * : ipinfo_t *, NULL, -+ struct net_device * : ifinfo_t *, idev->dev, -+ struct iphdr * : ipv4info_t *, NULL, -+ struct ipv6hdr * : ipv6info_t *, NULL, -+ const char * : string, dropreason); -+ - IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTDISCARDS); - } - - rcu_read_unlock(); - return; -- --err_out: -- kfree_skb(skb); -- goto out; - } - - static int grec_size(struct ifmcaddr6 *pmc, int type, int gdel, int sdel) -@@ -1979,7 +2001,7 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) - { - struct net *net = dev_net(dev); - struct sock *sk = net->ipv6.igmp_sk; -- struct inet6_dev *idev; -+ struct inet6_dev *idev = NULL; - struct sk_buff *skb; - struct mld_msg *hdr; - const struct in6_addr *snd_addr, *saddr; -@@ -1990,6 +2012,7 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) - u8 ra[8] = { IPPROTO_ICMPV6, 0, - IPV6_TLV_ROUTERALERT, 2, 0, 0, - IPV6_TLV_PADN, 0 }; -+ const char *dropreason; - struct flowi6 fl6; - struct dst_entry *dst; - -@@ -2011,10 +2034,8 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) - - if (!skb) { - rcu_read_lock(); -- IP6_INC_STATS(net, __in6_dev_get(dev), -- IPSTATS_MIB_OUTDISCARDS); -- rcu_read_unlock(); -- return; -+ dropreason = "out of memory"; -+ goto out; - } - skb->priority = TC_PRIO_CONTROL; - skb_reserve(skb, hlen); -@@ -2049,26 +2070,43 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) - dst = icmp6_dst_alloc(skb->dev, &fl6); - if (IS_ERR(dst)) { - err = PTR_ERR(dst); -- goto err_out; -+ kfree_skb(skb); -+ skb = NULL; -+ dropreason = "out of memory"; -+ goto out; - } - - skb_dst_set(skb, dst); -+ DTRACE_IP(send, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, skb->sk, -+ void_ip_t * : ipinfo_t *, ipv6_hdr(skb), -+ struct net_device * : ifinfo_t *, skb->dev, -+ struct iphdr * : ipv4info_t *, NULL, -+ struct ipv6hdr * : ipv6info_t *, ipv6_hdr(skb)); - err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, - net, sk, skb, NULL, skb->dev, - dst_output); -+ dropreason = "multicast send error"; - out: - if (!err) { - ICMP6MSGOUT_INC_STATS(net, idev, type); - ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS); -- } else -+ } else { -+ /* skb may have been freed */ -+ DTRACE_IP(drop__out, -+ struct sk_buff * : pktinfo_t *, NULL, -+ struct sock * : csinfo_t *, sk, -+ void_ip_t * : ipinfo_t *, NULL, -+ struct net_device * : ifinfo_t *, idev->dev, -+ struct iphdr * : ipv4info_t *, NULL, -+ struct ipv6hdr * : ipv6info_t *, NULL, -+ const char * : string, dropreason); - IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTDISCARDS); -+ } - - rcu_read_unlock(); - return; -- --err_out: -- kfree_skb(skb); -- goto out; - } - - static void mld_send_initial_cr(struct inet6_dev *idev) -diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c -index 76717478f1733fb753c067efaa5dd210320e0261..35ae4eaffd89ebc7fa85c1142d75b2f3c175254b 100644 ---- a/net/ipv6/ndisc.c -+++ b/net/ipv6/ndisc.c -@@ -68,6 +68,7 @@ - - #include <linux/netfilter.h> - #include <linux/netfilter_ipv6.h> -+#include <linux/sdt.h> - - static u32 ndisc_hash(const void *pkey, - const struct net_device *dev, -@@ -505,6 +506,14 @@ static void ndisc_send_skb(struct sk_buff *skb, - idev = __in6_dev_get(dst->dev); - IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len); - -+ DTRACE_IP(send, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, skb->sk, -+ void_ip_t * : ipinfo_t *, ipv6_hdr(skb), -+ struct net_device * : ifinfo_t *, skb->dev, -+ struct iphdr * : ipv4info_t *, NULL, -+ struct ipv6hdr * : ipv6info_t *, ipv6_hdr(skb)); -+ - err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, - net, sk, skb, NULL, dst->dev, - dst_output); -diff --git a/net/ipv6/output_core.c b/net/ipv6/output_core.c -index af36acc1a6448104ca6c71854e84b1a4bab4b3ea..811a88767a5c67d51fd594cdcbbc4b9d51fd00f1 100644 ---- a/net/ipv6/output_core.c -+++ b/net/ipv6/output_core.c -@@ -10,6 +10,7 @@ - #include <net/addrconf.h> - #include <net/secure_seq.h> - #include <linux/netfilter.h> -+#include <linux/sdt.h> - - static u32 __ipv6_select_ident(struct net *net, - const struct in6_addr *dst, -@@ -164,6 +165,14 @@ int __ip6_local_out(struct net *net, struct sock *sk, struct sk_buff *skb) - - skb->protocol = htons(ETH_P_IPV6); - -+ DTRACE_IP(send, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, skb->sk, -+ void_ip_t * : ipinfo_t *, ipv6_hdr(skb), -+ struct net_device * : ifinfo_t *, skb->dev, -+ struct iphdr * : ipv4info_t *, NULL, -+ struct ipv6hdr * : ipv6info_t *, ipv6_hdr(skb)); -+ - return nf_hook(NFPROTO_IPV6, NF_INET_LOCAL_OUT, - net, sk, skb, NULL, skb_dst(skb)->dev, - dst_output); -diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c -index 6e4ab80a3b94420a85769edf45bbf69e2ba74e39..f88c9441ec51b817db2159c40057f3a2bbcf0268 100644 ---- a/net/ipv6/raw.c -+++ b/net/ipv6/raw.c -@@ -58,6 +58,7 @@ - #include <linux/proc_fs.h> - #include <linux/seq_file.h> - #include <linux/export.h> -+#include <linux/sdt.h> - - #define ICMPV6_HDRLEN 4 /* ICMPv6 header, RFC 4443 Section 2.1 */ - -@@ -622,26 +623,34 @@ static int rawv6_send_hdrinc(struct sock *sk, struct msghdr *msg, int length, - struct ipv6_pinfo *np = inet6_sk(sk); - struct net *net = sock_net(sk); - struct ipv6hdr *iph; -- struct sk_buff *skb; -+ struct sk_buff *skb = NULL; - int err; - struct rt6_info *rt = (struct rt6_info *)*dstp; - int hlen = LL_RESERVED_SPACE(rt->dst.dev); - int tlen = rt->dst.dev->needed_tailroom; -+ const char *dropreason; - - if (length > rt->dst.dev->mtu) { - ipv6_local_error(sk, EMSGSIZE, fl6, rt->dst.dev->mtu); -- return -EMSGSIZE; -+ dropreason = "packet too big"; -+ err = -EMSGSIZE; -+ goto error_check; -+ } -+ if (length < sizeof(struct ipv6hdr)) { -+ dropreason = "packet too short"; -+ err = -EINVAL; -+ goto error_check; - } -- if (length < sizeof(struct ipv6hdr)) -- return -EINVAL; - if (flags&MSG_PROBE) - goto out; - - skb = sock_alloc_send_skb(sk, - length + hlen + tlen + 15, - flags & MSG_DONTWAIT, &err); -- if (!skb) -+ if (!skb) { -+ dropreason = "out of memory"; - goto error; -+ } - skb_reserve(skb, hlen); - - skb->protocol = htons(ETH_P_IPV6); -@@ -665,7 +674,8 @@ static int rawv6_send_hdrinc(struct sock *sk, struct msghdr *msg, int length, - if (err) { - err = -EFAULT; - kfree_skb(skb); -- goto error; -+ dropreason = "could not copy msg"; -+ goto error_check; - } - - skb_dst_set(skb, &rt->dst); -@@ -684,6 +694,13 @@ static int rawv6_send_hdrinc(struct sock *sk, struct msghdr *msg, int length, - */ - rcu_read_lock(); - IP6_UPD_PO_STATS(net, rt->rt6i_idev, IPSTATS_MIB_OUT, skb->len); -+ DTRACE_IP(send, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, skb->sk, -+ void_ip_t * : ipinfo_t *, ipv6_hdr(skb), -+ struct net_device * : ifinfo_t *, skb->dev, -+ struct iphdr * : ipv4info_t *, NULL, -+ struct ipv6hdr * : ipv6info_t *, ipv6_hdr(skb)); - err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, net, sk, skb, - NULL, rt->dst.dev, dst_output); - if (err > 0) -@@ -691,6 +708,7 @@ static int rawv6_send_hdrinc(struct sock *sk, struct msghdr *msg, int length, - if (err) { - IP6_INC_STATS(net, rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS); - rcu_read_unlock(); -+ dropreason = "raw send error"; - goto error_check; - } - rcu_read_unlock(); -@@ -700,6 +718,14 @@ static int rawv6_send_hdrinc(struct sock *sk, struct msghdr *msg, int length, - error: - IP6_INC_STATS(net, rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS); - error_check: -+ DTRACE_IP(drop__out, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, skb ? skb->sk : NULL, -+ void_ip_t * : ipinfo_t *, skb ? ipv6_hdr(skb) : NULL, -+ struct net_device * : ifinfo_t *, skb ? skb->dev : NULL, -+ struct iphdr * : ipv4info_t *, NULL, -+ struct ipv6hdr * : ipv6info_t *, skb ? ipv6_hdr(skb) : NULL, -+ const char * : string, dropreason); - if (err == -ENOBUFS && !np->recverr) - err = 0; - return err; -diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c -index 991dc36f95ff02b15a49dd2f77be8d2f0d94861a..acc63c45565109952355d2e2949ed971904c575d 100644 ---- a/net/ipv6/tcp_ipv6.c -+++ b/net/ipv6/tcp_ipv6.c -@@ -65,6 +65,7 @@ - - #include <crypto/hash.h> - #include <linux/scatterlist.h> -+#include <linux/sdt.h> - - #include <trace/events/tcp.h> - -@@ -496,6 +497,20 @@ static int tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, - return 0; - } - -+/* Since we want to trace send events in TCP prior to pushing the segment to -+ * IP - where the IP header is added - we need to construct an argument -+ * containing relevant IP info so that TCP probe consumers can utilize it. -+ */ -+static inline void dtrace_tcp_build_ipv6hdr(struct in6_addr *saddr, -+ struct in6_addr *daddr, -+ struct ipv6hdr *ip6h) -+{ -+ ip6h->version = 6; -+ ip6h->payload_len = 0; -+ ip6h->nexthdr = IPPROTO_TCP; -+ ip6h->saddr = *saddr; -+ ip6h->daddr = *daddr; -+} - - static int tcp_v6_send_synack(const struct sock *sk, struct dst_entry *dst, - struct flowi *fl, -@@ -540,6 +555,32 @@ static int tcp_v6_send_synack(const struct sock *sk, struct dst_entry *dst, - opt = ireq->ipv6_opt; - if (!opt) - opt = rcu_dereference(np->opt); -+ -+ if (DTRACE_TCP_ENABLED(send)) { -+ struct ipv6hdr ip6h; -+ -+ dtrace_tcp_build_ipv6hdr(&ireq->ir_v6_loc_addr, -+ &ireq->ir_v6_rmt_addr, &ip6h); -+ -+ /* Do not supply tcp sk - addresses/ports are not -+ * committed yet - instead translators will fill them -+ * in from IP/TCP data. -+ */ -+ DTRACE_TCP_NOCHECK(send, -+ struct sk_buff * : pktinfo_t *, -+ NULL, -+ struct sock * : csinfo_t *, sk, -+ __dtrace_tcp_void_ip_t * : -+ ipinfo_t *, &ip6h, -+ struct tcp_sock * : tcpsinfo_t *, -+ NULL, -+ struct tcphdr * : tcpinfo_t *, -+ tcp_hdr(skb), -+ int : tcplsinfo_t *, TCP_LISTEN, -+ int, TCP_LISTEN, -+ int, DTRACE_NET_PROBE_OUTBOUND); -+ } -+ - err = ip6_xmit(sk, skb, fl6, sk->sk_mark, opt, - tclass, sk->sk_priority); - rcu_read_unlock(); -@@ -969,6 +1010,49 @@ static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32 - dst = ip6_dst_lookup_flow(sock_net(ctl_sk), ctl_sk, &fl6, NULL); - if (!IS_ERR(dst)) { - skb_dst_set(buff, dst); -+ -+ if (DTRACE_TCP_ENABLED(send) || -+ DTRACE_TCP_ENABLED(accept__refused)) { -+ struct ipv6hdr ip6h; -+ -+ dtrace_tcp_build_ipv6hdr(&fl6.saddr, &fl6.daddr, -+ &ip6h); -+ -+ /* Do not supply tcp sk - addresses/ports are not -+ * committed yet - instead translators will fill them -+ * in from IP/TCP data. -+ */ -+ DTRACE_TCP_NOCHECK(send, -+ struct sk_buff * : pktinfo_t *, -+ NULL, -+ struct sock * : csinfo_t *, NULL, -+ __dtrace_tcp_void_ip_t * : -+ ipinfo_t *, &ip6h, -+ struct tcp_sock * : tcpsinfo_t *, -+ NULL, -+ struct tcphdr * : tcpinfo_t *, t1, -+ int : tcplsinfo_t *, TCP_CLOSE, -+ int, TCP_CLOSE, -+ int, DTRACE_NET_PROBE_OUTBOUND); -+ if (rst && th->syn && th->ack == 0) -+ DTRACE_TCP_NOCHECK(accept__refused, -+ struct sk_buff * : -+ pktinfo_t *, NULL, -+ struct sock * : csinfo_t *, -+ NULL, -+ __dtrace_tcp_void_ip_t * : -+ ipinfo_t *, &ip6h, -+ struct tcp_sock * : -+ tcpsinfo_t *, NULL, -+ struct tcphdr * : -+ tcpinfo_t *, t1, -+ int : tcplsinfo_t *, -+ TCP_CLOSE, -+ int, TCP_CLOSE, -+ int, -+ DTRACE_NET_PROBE_OUTBOUND); -+ } -+ - ip6_xmit(ctl_sk, buff, &fl6, fl6.flowi6_mark, NULL, - tclass & ~INET_ECN_MASK, priority); - TCP_INC_STATS(net, TCP_MIB_OUTSEGS); -@@ -1583,7 +1667,7 @@ INDIRECT_CALLABLE_SCOPE int tcp_v6_rcv(struct sk_buff *skb) - const struct tcphdr *th; - const struct ipv6hdr *hdr; - bool refcounted; -- struct sock *sk; -+ struct sock *sk = NULL; - int ret; - struct net *net = dev_net(skb->dev); - -@@ -1618,6 +1702,15 @@ INDIRECT_CALLABLE_SCOPE int tcp_v6_rcv(struct sk_buff *skb) - if (!sk) - goto no_tcp_socket; - -+ DTRACE_TCP(receive, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, sk, -+ __dtrace_tcp_void_ip_t * : ipinfo_t *, hdr, -+ struct tcp_sock * : tcpsinfo_t *, tcp_sk(sk), -+ struct tcphdr * : tcpinfo_t *, th, -+ int : tcplsinfo_t *, sk ? sk->sk_state : TCP_CLOSE, -+ int, sk ? sk->sk_state : TCP_CLOSE, -+ int, DTRACE_NET_PROBE_INBOUND); - process: - if (sk->sk_state == TCP_TIME_WAIT) - goto do_time_wait; -@@ -1737,6 +1830,18 @@ INDIRECT_CALLABLE_SCOPE int tcp_v6_rcv(struct sk_buff *skb) - } - - discard_it: -+ if (DTRACE_TCP_ENABLED(receive) && skb->pkt_type == PACKET_HOST) -+ DTRACE_TCP_NOCHECK(receive, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, sk, -+ __dtrace_tcp_void_ip_t * : ipinfo_t *, -+ ipv6_hdr(skb), -+ struct tcp_sock * : tcpsinfo_t *, tcp_sk(sk), -+ struct tcphdr * : tcpinfo_t *, tcp_hdr(skb), -+ int : tcplsinfo_t *, -+ sk ? sk->sk_state : TCP_CLOSE, -+ int, sk ? sk->sk_state : TCP_CLOSE, -+ int, DTRACE_NET_PROBE_INBOUND); - kfree_skb(skb); - return 0; - -diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c -index 29d9691359b9c49ccb56a11f79e3658b1a76700d..996afe0fb0571ba7afe4d0da0bfcd8cfa592f2a4 100644 ---- a/net/ipv6/udp.c -+++ b/net/ipv6/udp.c -@@ -51,6 +51,7 @@ - - #include <linux/proc_fs.h> - #include <linux/seq_file.h> -+#include <linux/sdt.h> - #include <trace/events/skb.h> - #include "udp_impl.h" - -@@ -386,8 +387,15 @@ int udpv6_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, - kfree_skb(skb); - return err; - } -- if (!peeking) -+ if (!peeking) { - SNMP_INC_STATS(mib, UDP_MIB_INDATAGRAMS); -+ DTRACE_UDP(receive, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, sk, -+ void_ip_t * : ipinfo_t *, ip_hdr(skb), -+ struct udp_sock * : udpsinfo_t *, udp_sk(sk), -+ struct udphdr * : udpinfo_t *, udp_hdr(skb)); -+ } - - sock_recv_ts_and_drops(msg, sk, skb); - -@@ -685,6 +693,15 @@ static int udpv6_queue_rcv_one_skb(struct sock *sk, struct sk_buff *skb) - - ret = encap_rcv(sk, skb); - if (ret <= 0) { -+ DTRACE_UDP(receive, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, sk, -+ void_ip_t * : ipinfo_t *, -+ ip_hdr(skb), -+ struct udp_sock * : udpsinfo_t *, -+ udp_sk(sk), -+ struct udphdr * : udpinfo_t *, -+ udp_hdr(skb)); - __UDP_INC_STATS(sock_net(sk), - UDP_MIB_INDATAGRAMS, - is_udplite); -@@ -1238,6 +1255,13 @@ static int udp_v6_send_skb(struct sk_buff *skb, struct flowi6 *fl6, - err = 0; - } - } else { -+ DTRACE_UDP(send, -+ struct sk_buff * : pktinfo_t *, skb, -+ struct sock * : csinfo_t *, sk, -+ void_ip_t * : ipinfo_t *, ip_hdr(skb), -+ struct udp_sock * : udpsinfo_t *, udp_sk(sk), -+ struct udphdr * : udpinfo_t *, uh); -+ - UDP6_INC_STATS(sock_net(sk), - UDP_MIB_OUTDATAGRAMS, is_udplite); - } --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/dtrace-patches/0018-dtrace-add-sample-script-for-building-DTrace-on-Fedo.patch b/sys-kernel/cairn-sources/files/5.10.14/dtrace-patches/0018-dtrace-add-sample-script-for-building-DTrace-on-Fedo.patch deleted file mode 100644 index 27829eae90fd..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/dtrace-patches/0018-dtrace-add-sample-script-for-building-DTrace-on-Fedo.patch +++ /dev/null @@ -1,241 +0,0 @@ -From 6e49525673d614475c5e9b7b164bd48bad93b4a3 Mon Sep 17 00:00:00 2001 -From: Eugene Loh <eugene.loh@oracle.com> -Date: Mon, 12 Aug 2019 20:51:06 -0700 -Subject: [PATCH 18/19] dtrace: add sample script for building DTrace on Fedora - -Signed-off-by: Eugene Loh <eugene.loh@oracle.com> ---- - samples/dtrace/DTrace-on-Fedora.sh | 221 +++++++++++++++++++++++++++++ - 1 file changed, 221 insertions(+) - create mode 100755 samples/dtrace/DTrace-on-Fedora.sh - -diff --git a/samples/dtrace/DTrace-on-Fedora.sh b/samples/dtrace/DTrace-on-Fedora.sh -new file mode 100755 -index 0000000000000000000000000000000000000000..3857027381a54e17a12245e5e511ca3c096ee6d8 ---- /dev/null -+++ b/samples/dtrace/DTrace-on-Fedora.sh -@@ -0,0 +1,221 @@ -+#!/bin/sh -+ -+# Oracle Linux DTrace. -+# Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. -+# Licensed under the Universal Permissive License v 1.0 as shown at -+# http://oss.oracle.com/licenses/upl. -+# -+ -+# Oracle has been working in recent years on porting DTrace, the -+# dynamic tracing tool, to Linux. DTrace offers easy-to-use, powerful, -+# safe, and unintrusive tracing. Oracle's initial focus was the Oracle -+# Unbreakable Enterprise Kernel (UEK), but DTrace runs on upstream Linux -+# kernels and other distributions' Linux kernels as well. Note that at -+# the moment, Oracle is in the process of upstreaming DTrace-related work -+# and reimplementing DTrace itself on top of existing kernel infrastructure -+# such as eBPF. -+ -+# This script illustrates how to build DTrace on Fedora on x86. -+# It is intended as a tutorial rather than a robust, turn-key utility. -+# Read and understand the steps as you execute them. The steps are -+# similar to what one does to build DTrace on other Linux distributions. -+ -+# Useful references on building a custom Fedora kernel include: -+# https://fedoraproject.org/wiki/Building_a_custom_kernel -+# https://fedoraproject.org/wiki/Building_a_custom_kernel#Building_Vanilla_upstream_kernel -+# Roughly speaking, you should have about 20 Gbyte of disk space -+# available and expect to wait a few hours for the build to complete. -+ -+# The overall process is: -+# 1. download and build the CTF library for DTrace to use -+# 2. download Fedora kernel source code -+# 3. prepare DTrace patches to apply -+# 4. prepare the kernel source code -+# a. Linux base code -+# b. apply Linux patches (if any) -+# c. apply Fedora patches -+# d. apply DTrace patches -+# e. prepare makefile and config -+# 5. build the kernel -+# 6. reboot -+# 7. download and build the DTrace userspace utility -+ -+ -+# pick one -+# DTrace patches change relatively infrequently. -+# So DTrace_branch might not have to match your Fedora kernel version exactly. -+#fedora_release=f29; DTrace_branch=5.2.7 ; num_DTrace_patches=19 -+ fedora_release=f30; DTrace_branch=5.2.7 ; num_DTrace_patches=19 -+ -+# Step 1: download and build the CTF library for DTrace to use -+ -+sudo dnf install -y git -+git clone https://github.com/oracle/libdtrace-ctf.git -+cd libdtrace-ctf -+sudo dnf builddep -y libdtrace-ctf.spec # install dependencies -+make -+sudo make install -+cd .. -+ -+# Step 2: download Fedora kernel source code -+ -+sudo dnf install -y fedora-packager -+fedpkg co -a kernel # anonymous clone of Fedora patches -+cd kernel -+git checkout origin/$fedora_release -+fedpkg sources # download tarballs of kernel sources -+sudo dnf builddep -y kernel.spec # install dependencies -+cd .. -+ -+# Step 3: prepare DTrace patches to apply -+ -+# download DTrace kernel code -+git clone https://github.com/oracle/dtrace-linux-kernel.git -+cd dtrace-linux-kernel/ -+git checkout origin/$DTrace_branch -+ -+# The DTrace patches will be the most recent commits. -+# Make sure you use all of them but nothing before that. -+# Make sure the top patches are DTrace -+# and the next one after them is the Linux baseline you want. -+# E.g., the top commits here are DTrace, and the last one is Linux upstream: -+# [...] -+# 66f76fef08e3 dtrace: modular components and x86 support -+# 25f11bb97fb9 dtrace: core and x86 -+# 3c5af76fa5fb waitfd: new syscall implementing waitpid() over fds -+# e95e4350d02b kallsyms: introduce new /proc/kallmodsyms including builtin modules too -+# 86e43efc644c ctf: generate CTF information for the kernel -+# a3b22b9f11d9 (tag: v5.0-rc7) Linux 5.0-rc7 -+git log -n $(($num_DTrace_patches + 1)) --oneline -+ -+# generate the DTrace patches -+git format-patch -$num_DTrace_patches -+ -+cd .. -+ -+# Step 4: prepare the kernel source code -+ -+# Step 4a: Linux base code -+ -+if [ -e kernel/linux-*.xz ]; then -+ /usr/bin/xz -dc kernel/linux-*.tar.xz | /usr/bin/tar -xof - -+else -+ tar xzf kernel/linux-*.tar.gz -+fi -+ -+# make a git repo so patches can be applied -+cd linux-* -+git init -+git config user.email "kernel-team@fedoraproject.org" -+git config user.name "Fedora Kernel Team" -+git config gc.auto 0 -+git add . -+git commit -a -q -m "baseline" -+ -+# Step 4b: apply Linux patches (if any) -+ -+if [ -e ../kernel/patch-*.xz ]; then -+ xzcat ../kernel/patch-*.xz | patch -p1 -F1 -s -+ git commit -a -m "Stable update" -+fi -+ -+# Step 4c: apply Fedora patches -+ -+for x in `awk '/^Patch/ {print $2}' ../kernel/kernel.spec`; do -+ git am ../kernel/$x -+done -+ -+# Step 4d: apply DTrace patches -+ -+for x in ../dtrace-linux-kernel/00*.patch; do -+ git am $x -+ if [ $? -ne 0 ]; then -+ echo DTrace patch did not apply cleanly -+ exit 1 -+ fi -+done -+ -+# Step 4e: prepare makefile and config -+ -+# modify the version tag in the Makefile -+sed -i.old \ -+ 's/^EXTRAVERSION =.*$/EXTRAVERSION = -200.DTrace_'$fedora_release'.x86_64/' \ -+ Makefile -+ -+# use the Fedora config file -+cp ../kernel/kernel-x86_64.config .config -+ -+# modify the config file for DTrace -+sed -i \ -+ -e 's/# CONFIG_UNWINDER_FRAME_POINTER is not set/CONFIG_UNWINDER_FRAME_POINTER=y/' \ -+ -e 's/CONFIG_UNWINDER_ORC=y/# CONFIG_UNWINDER_ORC is not set/' .config -+echo "CONFIG_DTRACE=y" >> .config -+echo "CONFIG_DT_CORE=m" >> .config -+echo "CONFIG_DT_FASTTRAP=m" >> .config -+echo "CONFIG_DT_PROFILE=m" >> .config -+echo "CONFIG_DT_SDT=m" >> .config -+echo "CONFIG_DT_SDT_PERF=y" >> .config -+echo "CONFIG_DT_FBT=m" >> .config -+echo "CONFIG_DT_SYSTRACE=m" >> .config -+echo "CONFIG_DT_DT_TEST=m" >> .config -+echo "CONFIG_DT_DT_PERF=m" >> .config -+echo "CONFIG_DT_DEBUG=y" >> .config -+echo "# CONFIG_DT_DEBUG_MUTEX is not set" >> .config -+ -+# Step 5: build the kernel -+ -+# (might take hours) -+make olddefconfig -+make -j4 -+make -j4 ctf -+ -+# install -+sudo make modules_install -+sudo make install -+sudo make INSTALL_HDR_PATH=/usr headers_install -+cd .. -+ -+# Step 6: reboot -+ -+sudo reboot -+ -+# Step 7: download and build the DTrace userspace utility -+ -+git clone https://github.com/oracle/dtrace-utils.git -+cd dtrace-utils -+ -+# The DTrace packages are missing from Fedora repos, -+# and we just built that software ourselves. -+# So eliminate those packages from the .spec file -+# before calling dnf builddep. -+sed -i.old \ -+ -e 's/-devel libdtrace-ctf-devel >= [0-9\.]*/-devel/' \ -+ -e '/^BuildRequires: dtrace-kernel-headers = [0-9\.]*$/d' dtrace-utils.spec -+sudo dnf builddep -y dtrace-utils.spec -+ -+make -+sudo make install -+cd .. -+ -+exit 0 -+ -+# Now, we can use DTrace on Fedora! (Notice that it is installed at /usr/sbin/dtrace. -+# Some other utility is at /usr/bin/dtrace.) You must be logged in as -+# root to use DTrace. The first thing to do is to list the available probes: -+# -+# # /usr/sbin/dtrace -l -+# ID PROVIDER MODULE FUNCTION NAME -+# 1 dtrace BEGIN -+# 2 dtrace END -+# 3 dtrace ERROR -+# 5 fbt isofs isofs_hashi entry -+# 6 fbt isofs isofs_hashi return -+# 7 fbt isofs isofs_statfs entry -+# 8 fbt isofs isofs_statfs return -+# 9 fbt isofs isofs_iget5_test entry -+# 10 fbt isofs isofs_iget5_test return -+# [...thousands of lines omitted...] -+# -+# Next, check out the Oracle DTrace Guide for simple examples and more information. -+# https://docs.oracle.com/cd/E52668_01/E38608/html/index.html -+ --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/dtrace-patches/0019-locking-publicize-mutex_owner-and-mutex_owned-again.patch b/sys-kernel/cairn-sources/files/5.10.14/dtrace-patches/0019-locking-publicize-mutex_owner-and-mutex_owned-again.patch deleted file mode 100644 index 31b05305cc7b..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/dtrace-patches/0019-locking-publicize-mutex_owner-and-mutex_owned-again.patch +++ /dev/null @@ -1,86 +0,0 @@ -From cbc0fec32fc028d2e75a00f7a0609bc1960b02ee Mon Sep 17 00:00:00 2001 -From: Nick Alcock <nick.alcock@oracle.com> -Date: Mon, 9 Dec 2019 16:51:44 +0000 -Subject: [PATCH 19/19] locking: publicize mutex_owner and mutex_owned again - -DTrace uses both of them. - -Signed-off-by: Nick Alcock <nick.alcock@oracle.com> ---- - dtrace/dtrace_dif.c | 2 +- - include/linux/mutex.h | 16 +++++----------- - kernel/locking/mutex.c | 19 +++++++++++++++++++ - 3 files changed, 25 insertions(+), 12 deletions(-) - -diff --git a/dtrace/dtrace_dif.c b/dtrace/dtrace_dif.c -index ae7f01b4ed9b76ea957dbfe080e1ac8fda995329..798302d322a369f92312a7b22ae41bf3e2d585e2 100644 ---- a/dtrace/dtrace_dif.c -+++ b/dtrace/dtrace_dif.c -@@ -2439,7 +2439,7 @@ static void dtrace_dif_subr(uint_t subr, uint_t rd, uint64_t *regs, - break; - - #ifdef CONFIG_SMP -- regs[rd] = (uintptr_t)__mutex_owner(&mtx); -+ regs[rd] = (uintptr_t)mutex_owner(&mtx); - #else - regs[rd] = 0; - #endif -diff --git a/include/linux/mutex.h b/include/linux/mutex.h -index bb18028db361585e6ed56b1b90853c006282e727..a1f15a42ea1601468e51a2ba04f4e2b2b4a509b2 100644 ---- a/include/linux/mutex.h -+++ b/include/linux/mutex.h -@@ -228,16 +228,10 @@ enum mutex_trylock_recursive_enum { - extern /* __deprecated */ __must_check enum mutex_trylock_recursive_enum - mutex_trylock_recursive(struct mutex *lock); - --#if defined(CONFIG_DEBUG_MUTEXES) || defined(CONFIG_SMP) --static inline int mutex_owned(struct mutex *lock) --{ -- return mutex_is_locked(lock) && __mutex_owner(lock) == current; --} --#else --static inline int mutex_owned(struct mutex *lock) --{ -- return mutex_is_locked(lock); --} --#endif -+extern int -+mutex_owned(struct mutex *lock); -+ -+extern struct task_struct * -+mutex_owner(struct mutex *lock); - - #endif /* __LINUX_MUTEX_H */ -diff --git a/kernel/locking/mutex.c b/kernel/locking/mutex.c -index e784dd89d924c4867de23c0eb60e65b2a47cad52..b856d7ffc51c7f1ace22768d2b2dc1e16335f619 100644 ---- a/kernel/locking/mutex.c -+++ b/kernel/locking/mutex.c -@@ -97,6 +97,25 @@ mutex_trylock_recursive(struct mutex *lock) - } - EXPORT_SYMBOL(mutex_trylock_recursive); - -+struct task_struct *mutex_owner(struct mutex *lock) -+{ -+ return __mutex_owner (lock); -+} -+EXPORT_SYMBOL(mutex_owner); -+ -+#if defined(CONFIG_DEBUG_MUTEXES) || defined(CONFIG_SMP) -+int mutex_owned(struct mutex *lock) -+{ -+ return mutex_is_locked(lock) && __mutex_owner(lock) == current; -+} -+#else -+int mutex_owned(struct mutex *lock) -+{ -+ return mutex_is_locked(lock); -+} -+#endif -+EXPORT_SYMBOL(mutex_owned); -+ - static inline unsigned long __owner_flags(unsigned long owner) - { - return owner & MUTEX_FLAGS; --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/gentoo-patches/0000_README b/sys-kernel/cairn-sources/files/5.10.14/gentoo-patches/0000_README deleted file mode 100644 index 897c945db2d7..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/gentoo-patches/0000_README +++ /dev/null @@ -1,132 +0,0 @@ -README --------------------------------------------------------------------------- -This patchset is to be the series of patches for gentoo-sources. -It is designed for cross-compatibility, fixes and stability, with performance -and additional features/driver support being a second. - -Unless otherwise stated and marked as such, this kernel should be suitable for -all environments. - - -Patchset Numbering Scheme --------------------------------------------------------------------------- - -FIXES -1000-1400 linux-stable -1400-1500 linux-stable queue -1500-1700 security -1700-1800 architecture-related -1800-1900 mm/scheduling/misc -1900-2000 filesystems -2000-2100 networking core -2100-2200 storage core -2200-2300 power management (ACPI, APM) -2300-2400 bus (USB, IEEE1394, PCI, PCMCIA, ...) -2400-2500 network drivers -2500-2600 storage drivers -2600-2700 input -2700-2900 media (graphics, sound, tv) -2900-3000 other -3000-4000 reserved - -FEATURES -4000-4100 network -4100-4200 storage -4200-4300 graphics -4300-4400 filesystem -4400-4500 security enhancement -4500-4600 other - -EXPERIMENTAL -5000-5100 experimental patches (BFQ, ...) - -Individual Patch Descriptions: --------------------------------------------------------------------------- - -Patch: 1000_linux-5.10.1.patch -From: http://www.kernel.org -Desc: Linux 5.10.1 - -Patch: 1001_linux-5.10.2.patch -From: http://www.kernel.org -Desc: Linux 5.10.2 - -Patch: 1002_linux-5.10.3.patch -From: http://www.kernel.org -Desc: Linux 5.10.3 - -Patch: 1003_linux-5.10.4.patch -From: http://www.kernel.org -Desc: Linux 5.10.4 - -Patch: 1004_linux-5.10.5.patch -From: http://www.kernel.org -Desc: Linux 5.10.5 - -Patch: 1005_linux-5.10.6.patch -From: http://www.kernel.org -Desc: Linux 5.10.6 - -Patch: 1006_linux-5.10.7.patch -From: http://www.kernel.org -Desc: Linux 5.10.7 - -Patch: 1007_linux-5.10.8.patch -From: http://www.kernel.org -Desc: Linux 5.10.8 - -Patch: 1008_linux-5.10.9.patch -From: http://www.kernel.org -Desc: Linux 5.10.9 - -Patch: 1009_linux-5.10.10.patch -From: http://www.kernel.org -Desc: Linux 5.10.10 - -Patch: 1010_linux-5.10.11.patch -From: http://www.kernel.org -Desc: Linux 5.10.11 - -Patch: 1011_linux-5.10.12.patch -From: http://www.kernel.org -Desc: Linux 5.10.12 - -Patch: 1012_linux-5.10.13.patch -From: http://www.kernel.org -Desc: Linux 5.10.13 - -Patch: 1013_linux-5.10.14.patch -From: http://www.kernel.org -Desc: Linux 5.10.14 - -Patch: 1500_XATTR_USER_PREFIX.patch -From: https://bugs.gentoo.org/show_bug.cgi?id=470644 -Desc: Support for namespace user.pax.* on tmpfs. - -Patch: 1510_fs-enable-link-security-restrictions-by-default.patch -From: http://sources.debian.net/src/linux/3.16.7-ckt4-3/debian/patches/debian/fs-enable-link-security-restrictions-by-default.patch/ -Desc: Enable link security restrictions by default. - -Patch: 2000_BT-Check-key-sizes-only-if-Secure-Simple-Pairing-enabled.patch -From: https://lore.kernel.org/linux-bluetooth/20190522070540.48895-1-marcel@holtmann.org/raw -Desc: Bluetooth: Check key sizes only when Secure Simple Pairing is enabled. See bug #686758 - -Patch: 2900_tmp513-Fix-build-issue-by-selecting-CONFIG_REG.patch -From: https://bugs.gentoo.org/710790 -Desc: tmp513 requies REGMAP_I2C to build. Select it by default in Kconfig. See bug #710790. Thanks to Phil Stracchino - -Patch: 2920_sign-file-patch-for-libressl.patch -From: https://bugs.gentoo.org/717166 -Desc: sign-file: full functionality with modern LibreSSL - -Patch: 4567_distro-Gentoo-Kconfig.patch -From: Tom Wijsman <TomWij@gentoo.org> -Desc: Add Gentoo Linux support config settings and defaults. - -Patch: 5000_shifts-ubuntu-20.04.patch -From: https://git.launchpad.net/~ubuntu-kernel/ubuntu/+source/linux/+git/focal -Desc: UID/GID shifting overlay filesystem for containers - -Patch: 5013_enable-cpu-optimizations-for-gcc10.patch -From: https://github.com/graysky2/kernel_gcc_patch/ -Desc: Kernel patch enables gcc = v10.1+ optimizations for additional CPUs. diff --git a/sys-kernel/cairn-sources/files/5.10.14/gentoo-patches/1500_XATTR_USER_PREFIX.patch b/sys-kernel/cairn-sources/files/5.10.14/gentoo-patches/1500_XATTR_USER_PREFIX.patch deleted file mode 100644 index 245dcc29fa56..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/gentoo-patches/1500_XATTR_USER_PREFIX.patch +++ /dev/null @@ -1,67 +0,0 @@ -From: Anthony G. Basile <blueness@gentoo.org> - -This patch adds support for a restricted user-controlled namespace on -tmpfs filesystem used to house PaX flags. The namespace must be of the -form user.pax.* and its value cannot exceed a size of 8 bytes. - -This is needed even on all Gentoo systems so that XATTR_PAX flags -are preserved for users who might build packages using portage on -a tmpfs system with a non-hardened kernel and then switch to a -hardened kernel with XATTR_PAX enabled. - -The namespace is added to any user with Extended Attribute support -enabled for tmpfs. Users who do not enable xattrs will not have -the XATTR_PAX flags preserved. - -diff --git a/include/uapi/linux/xattr.h b/include/uapi/linux/xattr.h -index 1590c49..5eab462 100644 ---- a/include/uapi/linux/xattr.h -+++ b/include/uapi/linux/xattr.h -@@ -73,5 +73,9 @@ - #define XATTR_POSIX_ACL_DEFAULT "posix_acl_default" - #define XATTR_NAME_POSIX_ACL_DEFAULT XATTR_SYSTEM_PREFIX XATTR_POSIX_ACL_DEFAULT - -+/* User namespace */ -+#define XATTR_PAX_PREFIX XATTR_USER_PREFIX "pax." -+#define XATTR_PAX_FLAGS_SUFFIX "flags" -+#define XATTR_NAME_PAX_FLAGS XATTR_PAX_PREFIX XATTR_PAX_FLAGS_SUFFIX - - #endif /* _UAPI_LINUX_XATTR_H */ ---- a/mm/shmem.c 2020-05-04 15:30:27.042035334 -0400 -+++ b/mm/shmem.c 2020-05-04 15:34:57.013881725 -0400 -@@ -3238,6 +3238,14 @@ static int shmem_xattr_handler_set(const - struct shmem_inode_info *info = SHMEM_I(inode); - - name = xattr_full_name(handler, name); -+ -+ if (!strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)) { -+ if (strcmp(name, XATTR_NAME_PAX_FLAGS)) -+ return -EOPNOTSUPP; -+ if (size > 8) -+ return -EINVAL; -+ } -+ - return simple_xattr_set(&info->xattrs, name, value, size, flags, NULL); - } - -@@ -3253,6 +3261,12 @@ static const struct xattr_handler shmem_ - .set = shmem_xattr_handler_set, - }; - -+static const struct xattr_handler shmem_user_xattr_handler = { -+ .prefix = XATTR_USER_PREFIX, -+ .get = shmem_xattr_handler_get, -+ .set = shmem_xattr_handler_set, -+}; -+ - static const struct xattr_handler *shmem_xattr_handlers[] = { - #ifdef CONFIG_TMPFS_POSIX_ACL - &posix_acl_access_xattr_handler, -@@ -3260,6 +3274,7 @@ static const struct xattr_handler *shmem - #endif - &shmem_security_xattr_handler, - &shmem_trusted_xattr_handler, -+ &shmem_user_xattr_handler, - NULL - }; - diff --git a/sys-kernel/cairn-sources/files/5.10.14/gentoo-patches/1510_fs-enable-link-security-restrictions-by-default.patch b/sys-kernel/cairn-sources/files/5.10.14/gentoo-patches/1510_fs-enable-link-security-restrictions-by-default.patch deleted file mode 100644 index f0ed144fb17a..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/gentoo-patches/1510_fs-enable-link-security-restrictions-by-default.patch +++ /dev/null @@ -1,20 +0,0 @@ -From: Ben Hutchings <ben@decadent.org.uk> -Subject: fs: Enable link security restrictions by default -Date: Fri, 02 Nov 2012 05:32:06 +0000 -Bug-Debian: https://bugs.debian.org/609455 -Forwarded: not-needed -This reverts commit 561ec64ae67ef25cac8d72bb9c4bfc955edfd415 -('VFS: don't do protected {sym,hard}links by default'). ---- a/fs/namei.c 2018-09-28 07:56:07.770005006 -0400 -+++ b/fs/namei.c 2018-09-28 07:56:43.370349204 -0400 -@@ -885,8 +885,8 @@ static inline void put_link(struct namei - path_put(&last->link); - } - --int sysctl_protected_symlinks __read_mostly = 0; --int sysctl_protected_hardlinks __read_mostly = 0; -+int sysctl_protected_symlinks __read_mostly = 1; -+int sysctl_protected_hardlinks __read_mostly = 1; - int sysctl_protected_fifos __read_mostly; - int sysctl_protected_regular __read_mostly; - diff --git a/sys-kernel/cairn-sources/files/5.10.14/gentoo-patches/2000_BT-Check-key-sizes-only-if-Secure-Simple-Pairing-enabled.patch b/sys-kernel/cairn-sources/files/5.10.14/gentoo-patches/2000_BT-Check-key-sizes-only-if-Secure-Simple-Pairing-enabled.patch deleted file mode 100644 index 394ad48fc20c..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/gentoo-patches/2000_BT-Check-key-sizes-only-if-Secure-Simple-Pairing-enabled.patch +++ /dev/null @@ -1,37 +0,0 @@ -The encryption is only mandatory to be enforced when both sides are using -Secure Simple Pairing and this means the key size check makes only sense -in that case. - -On legacy Bluetooth 2.0 and earlier devices like mice the encryption was -optional and thus causing an issue if the key size check is not bound to -using Secure Simple Pairing. - -Fixes: d5bb334a8e17 ("Bluetooth: Align minimum encryption key size for LE and BR/EDR connections") -Signed-off-by: Marcel Holtmann <marcel@holtmann.org> -Cc: stable@vger.kernel.org ---- - net/bluetooth/hci_conn.c | 9 +++++++-- - 1 file changed, 7 insertions(+), 2 deletions(-) - -diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c -index 3cf0764d5793..7516cdde3373 100644 ---- a/net/bluetooth/hci_conn.c -+++ b/net/bluetooth/hci_conn.c -@@ -1272,8 +1272,13 @@ int hci_conn_check_link_mode(struct hci_conn *conn) - return 0; - } - -- if (hci_conn_ssp_enabled(conn) && -- !test_bit(HCI_CONN_ENCRYPT, &conn->flags)) -+ /* If Secure Simple Pairing is not enabled, then legacy connection -+ * setup is used and no encryption or key sizes can be enforced. -+ */ -+ if (!hci_conn_ssp_enabled(conn)) -+ return 1; -+ -+ if (!test_bit(HCI_CONN_ENCRYPT, &conn->flags)) - return 0; - - /* The minimum encryption key size needs to be enforced by the --- -2.20.1 diff --git a/sys-kernel/cairn-sources/files/5.10.14/gentoo-patches/2900_tmp513-Fix-build-issue-by-selecting-CONFIG_REG.patch b/sys-kernel/cairn-sources/files/5.10.14/gentoo-patches/2900_tmp513-Fix-build-issue-by-selecting-CONFIG_REG.patch deleted file mode 100644 index 433568579cab..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/gentoo-patches/2900_tmp513-Fix-build-issue-by-selecting-CONFIG_REG.patch +++ /dev/null @@ -1,30 +0,0 @@ -From dc328d75a6f37f4ff11a81ae16b1ec88c3197640 Mon Sep 17 00:00:00 2001 -From: Mike Pagano <mpagano@gentoo.org> -Date: Mon, 23 Mar 2020 08:20:06 -0400 -Subject: [PATCH 1/1] This driver requires REGMAP_I2C to build. Select it by - default in Kconfig. Reported at gentoo bugzilla: - https://bugs.gentoo.org/710790 -Cc: mpagano@gentoo.org - -Reported-by: Phil Stracchino <phils@caerllewys.net> - -Signed-off-by: Mike Pagano <mpagano@gentoo.org> ---- - drivers/hwmon/Kconfig | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig -index 47ac20aee06f..530b4f29ba85 100644 ---- a/drivers/hwmon/Kconfig -+++ b/drivers/hwmon/Kconfig -@@ -1769,6 +1769,7 @@ config SENSORS_TMP421 - config SENSORS_TMP513 - tristate "Texas Instruments TMP513 and compatibles" - depends on I2C -+ select REGMAP_I2C - help - If you say yes here you get support for Texas Instruments TMP512, - and TMP513 temperature and power supply sensor chips. --- -2.24.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/gentoo-patches/2920_sign-file-patch-for-libressl.patch b/sys-kernel/cairn-sources/files/5.10.14/gentoo-patches/2920_sign-file-patch-for-libressl.patch deleted file mode 100644 index e6ec017d46c8..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/gentoo-patches/2920_sign-file-patch-for-libressl.patch +++ /dev/null @@ -1,16 +0,0 @@ ---- a/scripts/sign-file.c 2020-05-20 18:47:21.282820662 -0400 -+++ b/scripts/sign-file.c 2020-05-20 18:48:37.991081899 -0400 -@@ -41,9 +41,10 @@ - * signing with anything other than SHA1 - so we're stuck with that if such is - * the case. - */ --#if defined(LIBRESSL_VERSION_NUMBER) || \ -- OPENSSL_VERSION_NUMBER < 0x10000000L || \ -- defined(OPENSSL_NO_CMS) -+#if defined(OPENSSL_NO_CMS) || \ -+ ( defined(LIBRESSL_VERSION_NUMBER) \ -+ && (LIBRESSL_VERSION_NUMBER < 0x3010000fL) ) || \ -+ OPENSSL_VERSION_NUMBER < 0x10000000L - #define USE_PKCS7 - #endif - #ifndef USE_PKCS7 diff --git a/sys-kernel/cairn-sources/files/5.10.14/gentoo-patches/5000_shiftfs-ubuntu-20.04.patch b/sys-kernel/cairn-sources/files/5.10.14/gentoo-patches/5000_shiftfs-ubuntu-20.04.patch deleted file mode 100644 index 665fc660b0de..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/gentoo-patches/5000_shiftfs-ubuntu-20.04.patch +++ /dev/null @@ -1,2203 +0,0 @@ ---- /dev/null 2021-01-08 13:33:13.190303432 -0500 -+++ b/fs/shiftfs.c 2021-01-08 19:02:40.000000000 -0500 -@@ -0,0 +1,2157 @@ -+#include <linux/btrfs.h> -+#include <linux/capability.h> -+#include <linux/cred.h> -+#include <linux/mount.h> -+#include <linux/fdtable.h> -+#include <linux/file.h> -+#include <linux/fs.h> -+#include <linux/namei.h> -+#include <linux/module.h> -+#include <linux/kernel.h> -+#include <linux/magic.h> -+#include <linux/parser.h> -+#include <linux/security.h> -+#include <linux/seq_file.h> -+#include <linux/statfs.h> -+#include <linux/slab.h> -+#include <linux/user_namespace.h> -+#include <linux/uidgid.h> -+#include <linux/xattr.h> -+#include <linux/posix_acl.h> -+#include <linux/posix_acl_xattr.h> -+#include <linux/uio.h> -+#include <linux/fiemap.h> -+ -+struct shiftfs_super_info { -+ struct vfsmount *mnt; -+ struct user_namespace *userns; -+ /* creds of process who created the super block */ -+ const struct cred *creator_cred; -+ bool mark; -+ unsigned int passthrough; -+ unsigned int passthrough_mark; -+}; -+ -+static void shiftfs_fill_inode(struct inode *inode, unsigned long ino, -+ umode_t mode, dev_t dev, struct dentry *dentry); -+ -+#define SHIFTFS_PASSTHROUGH_NONE 0 -+#define SHIFTFS_PASSTHROUGH_STAT 1 -+#define SHIFTFS_PASSTHROUGH_IOCTL 2 -+#define SHIFTFS_PASSTHROUGH_ALL \ -+ (SHIFTFS_PASSTHROUGH_STAT | SHIFTFS_PASSTHROUGH_IOCTL) -+ -+static inline bool shiftfs_passthrough_ioctls(struct shiftfs_super_info *info) -+{ -+ if (!(info->passthrough & SHIFTFS_PASSTHROUGH_IOCTL)) -+ return false; -+ -+ return true; -+} -+ -+static inline bool shiftfs_passthrough_statfs(struct shiftfs_super_info *info) -+{ -+ if (!(info->passthrough & SHIFTFS_PASSTHROUGH_STAT)) -+ return false; -+ -+ return true; -+} -+ -+enum { -+ OPT_MARK, -+ OPT_PASSTHROUGH, -+ OPT_LAST, -+}; -+ -+/* global filesystem options */ -+static const match_table_t tokens = { -+ { OPT_MARK, "mark" }, -+ { OPT_PASSTHROUGH, "passthrough=%u" }, -+ { OPT_LAST, NULL } -+}; -+ -+static const struct cred *shiftfs_override_creds(const struct super_block *sb) -+{ -+ struct shiftfs_super_info *sbinfo = sb->s_fs_info; -+ -+ return override_creds(sbinfo->creator_cred); -+} -+ -+static inline void shiftfs_revert_object_creds(const struct cred *oldcred, -+ struct cred *newcred) -+{ -+ revert_creds(oldcred); -+ put_cred(newcred); -+} -+ -+static kuid_t shift_kuid(struct user_namespace *from, struct user_namespace *to, -+ kuid_t kuid) -+{ -+ uid_t uid = from_kuid(from, kuid); -+ return make_kuid(to, uid); -+} -+ -+static kgid_t shift_kgid(struct user_namespace *from, struct user_namespace *to, -+ kgid_t kgid) -+{ -+ gid_t gid = from_kgid(from, kgid); -+ return make_kgid(to, gid); -+} -+ -+static int shiftfs_override_object_creds(const struct super_block *sb, -+ const struct cred **oldcred, -+ struct cred **newcred, -+ struct dentry *dentry, umode_t mode, -+ bool hardlink) -+{ -+ struct shiftfs_super_info *sbinfo = sb->s_fs_info; -+ kuid_t fsuid = current_fsuid(); -+ kgid_t fsgid = current_fsgid(); -+ -+ *oldcred = shiftfs_override_creds(sb); -+ -+ *newcred = prepare_creds(); -+ if (!*newcred) { -+ revert_creds(*oldcred); -+ return -ENOMEM; -+ } -+ -+ (*newcred)->fsuid = shift_kuid(sb->s_user_ns, sbinfo->userns, fsuid); -+ (*newcred)->fsgid = shift_kgid(sb->s_user_ns, sbinfo->userns, fsgid); -+ -+ if (!hardlink) { -+ int err = security_dentry_create_files_as(dentry, mode, -+ &dentry->d_name, -+ *oldcred, *newcred); -+ if (err) { -+ shiftfs_revert_object_creds(*oldcred, *newcred); -+ return err; -+ } -+ } -+ -+ put_cred(override_creds(*newcred)); -+ return 0; -+} -+ -+static void shiftfs_copyattr(struct inode *from, struct inode *to) -+{ -+ struct user_namespace *from_ns = from->i_sb->s_user_ns; -+ struct user_namespace *to_ns = to->i_sb->s_user_ns; -+ -+ to->i_uid = shift_kuid(from_ns, to_ns, from->i_uid); -+ to->i_gid = shift_kgid(from_ns, to_ns, from->i_gid); -+ to->i_mode = from->i_mode; -+ to->i_atime = from->i_atime; -+ to->i_mtime = from->i_mtime; -+ to->i_ctime = from->i_ctime; -+ i_size_write(to, i_size_read(from)); -+} -+ -+static void shiftfs_copyflags(struct inode *from, struct inode *to) -+{ -+ unsigned int mask = S_SYNC | S_IMMUTABLE | S_APPEND | S_NOATIME; -+ -+ inode_set_flags(to, from->i_flags & mask, mask); -+} -+ -+static void shiftfs_file_accessed(struct file *file) -+{ -+ struct inode *upperi, *loweri; -+ -+ if (file->f_flags & O_NOATIME) -+ return; -+ -+ upperi = file_inode(file); -+ loweri = upperi->i_private; -+ -+ if (!loweri) -+ return; -+ -+ upperi->i_mtime = loweri->i_mtime; -+ upperi->i_ctime = loweri->i_ctime; -+ -+ touch_atime(&file->f_path); -+} -+ -+static int shiftfs_parse_mount_options(struct shiftfs_super_info *sbinfo, -+ char *options) -+{ -+ char *p; -+ substring_t args[MAX_OPT_ARGS]; -+ -+ sbinfo->mark = false; -+ sbinfo->passthrough = 0; -+ -+ while ((p = strsep(&options, ",")) != NULL) { -+ int err, intarg, token; -+ -+ if (!*p) -+ continue; -+ -+ token = match_token(p, tokens, args); -+ switch (token) { -+ case OPT_MARK: -+ sbinfo->mark = true; -+ break; -+ case OPT_PASSTHROUGH: -+ err = match_int(&args[0], &intarg); -+ if (err) -+ return err; -+ -+ if (intarg & ~SHIFTFS_PASSTHROUGH_ALL) -+ return -EINVAL; -+ -+ sbinfo->passthrough = intarg; -+ break; -+ default: -+ return -EINVAL; -+ } -+ } -+ -+ return 0; -+} -+ -+static void shiftfs_d_release(struct dentry *dentry) -+{ -+ struct dentry *lowerd = dentry->d_fsdata; -+ -+ if (lowerd) -+ dput(lowerd); -+} -+ -+static struct dentry *shiftfs_d_real(struct dentry *dentry, -+ const struct inode *inode) -+{ -+ struct dentry *lowerd = dentry->d_fsdata; -+ -+ if (inode && d_inode(dentry) == inode) -+ return dentry; -+ -+ lowerd = d_real(lowerd, inode); -+ if (lowerd && (!inode || inode == d_inode(lowerd))) -+ return lowerd; -+ -+ WARN(1, "shiftfs_d_real(%pd4, %s:%lu): real dentry not found\n", dentry, -+ inode ? inode->i_sb->s_id : "NULL", inode ? inode->i_ino : 0); -+ return dentry; -+} -+ -+static int shiftfs_d_weak_revalidate(struct dentry *dentry, unsigned int flags) -+{ -+ int err = 1; -+ struct dentry *lowerd = dentry->d_fsdata; -+ -+ if (d_is_negative(lowerd) != d_is_negative(dentry)) -+ return 0; -+ -+ if ((lowerd->d_flags & DCACHE_OP_WEAK_REVALIDATE)) -+ err = lowerd->d_op->d_weak_revalidate(lowerd, flags); -+ -+ if (d_really_is_positive(dentry)) { -+ struct inode *inode = d_inode(dentry); -+ struct inode *loweri = d_inode(lowerd); -+ -+ shiftfs_copyattr(loweri, inode); -+ } -+ -+ return err; -+} -+ -+static int shiftfs_d_revalidate(struct dentry *dentry, unsigned int flags) -+{ -+ int err = 1; -+ struct dentry *lowerd = dentry->d_fsdata; -+ -+ if (d_unhashed(lowerd) || -+ ((d_is_negative(lowerd) != d_is_negative(dentry)))) -+ return 0; -+ -+ if (flags & LOOKUP_RCU) -+ return -ECHILD; -+ -+ if ((lowerd->d_flags & DCACHE_OP_REVALIDATE)) -+ err = lowerd->d_op->d_revalidate(lowerd, flags); -+ -+ if (d_really_is_positive(dentry)) { -+ struct inode *inode = d_inode(dentry); -+ struct inode *loweri = d_inode(lowerd); -+ -+ shiftfs_copyattr(loweri, inode); -+ } -+ -+ return err; -+} -+ -+static const struct dentry_operations shiftfs_dentry_ops = { -+ .d_release = shiftfs_d_release, -+ .d_real = shiftfs_d_real, -+ .d_revalidate = shiftfs_d_revalidate, -+ .d_weak_revalidate = shiftfs_d_weak_revalidate, -+}; -+ -+static const char *shiftfs_get_link(struct dentry *dentry, struct inode *inode, -+ struct delayed_call *done) -+{ -+ const char *p; -+ const struct cred *oldcred; -+ struct dentry *lowerd; -+ -+ /* RCU lookup not supported */ -+ if (!dentry) -+ return ERR_PTR(-ECHILD); -+ -+ lowerd = dentry->d_fsdata; -+ oldcred = shiftfs_override_creds(dentry->d_sb); -+ p = vfs_get_link(lowerd, done); -+ revert_creds(oldcred); -+ -+ return p; -+} -+ -+static int shiftfs_setxattr(struct dentry *dentry, struct inode *inode, -+ const char *name, const void *value, -+ size_t size, int flags) -+{ -+ struct dentry *lowerd = dentry->d_fsdata; -+ int err; -+ const struct cred *oldcred; -+ -+ oldcred = shiftfs_override_creds(dentry->d_sb); -+ err = vfs_setxattr(lowerd, name, value, size, flags); -+ revert_creds(oldcred); -+ -+ shiftfs_copyattr(lowerd->d_inode, inode); -+ -+ return err; -+} -+ -+static int shiftfs_xattr_get(const struct xattr_handler *handler, -+ struct dentry *dentry, struct inode *inode, -+ const char *name, void *value, size_t size) -+{ -+ struct dentry *lowerd = dentry->d_fsdata; -+ int err; -+ const struct cred *oldcred; -+ -+ oldcred = shiftfs_override_creds(dentry->d_sb); -+ err = vfs_getxattr(lowerd, name, value, size); -+ revert_creds(oldcred); -+ -+ return err; -+} -+ -+static ssize_t shiftfs_listxattr(struct dentry *dentry, char *list, -+ size_t size) -+{ -+ struct dentry *lowerd = dentry->d_fsdata; -+ int err; -+ const struct cred *oldcred; -+ -+ oldcred = shiftfs_override_creds(dentry->d_sb); -+ err = vfs_listxattr(lowerd, list, size); -+ revert_creds(oldcred); -+ -+ return err; -+} -+ -+static int shiftfs_removexattr(struct dentry *dentry, const char *name) -+{ -+ struct dentry *lowerd = dentry->d_fsdata; -+ int err; -+ const struct cred *oldcred; -+ -+ oldcred = shiftfs_override_creds(dentry->d_sb); -+ err = vfs_removexattr(lowerd, name); -+ revert_creds(oldcred); -+ -+ /* update c/mtime */ -+ shiftfs_copyattr(lowerd->d_inode, d_inode(dentry)); -+ -+ return err; -+} -+ -+static int shiftfs_xattr_set(const struct xattr_handler *handler, -+ struct dentry *dentry, struct inode *inode, -+ const char *name, const void *value, size_t size, -+ int flags) -+{ -+ if (!value) -+ return shiftfs_removexattr(dentry, name); -+ return shiftfs_setxattr(dentry, inode, name, value, size, flags); -+} -+ -+static int shiftfs_inode_test(struct inode *inode, void *data) -+{ -+ return inode->i_private == data; -+} -+ -+static int shiftfs_inode_set(struct inode *inode, void *data) -+{ -+ inode->i_private = data; -+ return 0; -+} -+ -+static int shiftfs_create_object(struct inode *diri, struct dentry *dentry, -+ umode_t mode, const char *symlink, -+ struct dentry *hardlink, bool excl) -+{ -+ int err; -+ const struct cred *oldcred; -+ struct cred *newcred; -+ void *loweri_iop_ptr = NULL; -+ umode_t modei = mode; -+ struct super_block *dir_sb = diri->i_sb; -+ struct dentry *lowerd_new = dentry->d_fsdata; -+ struct inode *inode = NULL, *loweri_dir = diri->i_private; -+ const struct inode_operations *loweri_dir_iop = loweri_dir->i_op; -+ struct dentry *lowerd_link = NULL; -+ -+ if (hardlink) { -+ loweri_iop_ptr = loweri_dir_iop->link; -+ } else { -+ switch (mode & S_IFMT) { -+ case S_IFDIR: -+ loweri_iop_ptr = loweri_dir_iop->mkdir; -+ break; -+ case S_IFREG: -+ loweri_iop_ptr = loweri_dir_iop->create; -+ break; -+ case S_IFLNK: -+ loweri_iop_ptr = loweri_dir_iop->symlink; -+ break; -+ case S_IFSOCK: -+ /* fall through */ -+ case S_IFIFO: -+ loweri_iop_ptr = loweri_dir_iop->mknod; -+ break; -+ } -+ } -+ if (!loweri_iop_ptr) { -+ err = -EINVAL; -+ goto out_iput; -+ } -+ -+ inode_lock_nested(loweri_dir, I_MUTEX_PARENT); -+ -+ if (!hardlink) { -+ inode = new_inode(dir_sb); -+ if (!inode) { -+ err = -ENOMEM; -+ goto out_iput; -+ } -+ -+ /* -+ * new_inode() will have added the new inode to the super -+ * block's list of inodes. Further below we will call -+ * inode_insert5() Which would perform the same operation again -+ * thereby corrupting the list. To avoid this raise I_CREATING -+ * in i_state which will cause inode_insert5() to skip this -+ * step. I_CREATING will be cleared by d_instantiate_new() -+ * below. -+ */ -+ spin_lock(&inode->i_lock); -+ inode->i_state |= I_CREATING; -+ spin_unlock(&inode->i_lock); -+ -+ inode_init_owner(inode, diri, mode); -+ modei = inode->i_mode; -+ } -+ -+ err = shiftfs_override_object_creds(dentry->d_sb, &oldcred, &newcred, -+ dentry, modei, hardlink != NULL); -+ if (err) -+ goto out_iput; -+ -+ if (hardlink) { -+ lowerd_link = hardlink->d_fsdata; -+ err = vfs_link(lowerd_link, loweri_dir, lowerd_new, NULL); -+ } else { -+ switch (modei & S_IFMT) { -+ case S_IFDIR: -+ err = vfs_mkdir(loweri_dir, lowerd_new, modei); -+ break; -+ case S_IFREG: -+ err = vfs_create(loweri_dir, lowerd_new, modei, excl); -+ break; -+ case S_IFLNK: -+ err = vfs_symlink(loweri_dir, lowerd_new, symlink); -+ break; -+ case S_IFSOCK: -+ /* fall through */ -+ case S_IFIFO: -+ err = vfs_mknod(loweri_dir, lowerd_new, modei, 0); -+ break; -+ default: -+ err = -EINVAL; -+ break; -+ } -+ } -+ -+ shiftfs_revert_object_creds(oldcred, newcred); -+ -+ if (!err && WARN_ON(!lowerd_new->d_inode)) -+ err = -EIO; -+ if (err) -+ goto out_iput; -+ -+ if (hardlink) { -+ inode = d_inode(hardlink); -+ ihold(inode); -+ -+ /* copy up times from lower inode */ -+ shiftfs_copyattr(d_inode(lowerd_link), inode); -+ set_nlink(d_inode(hardlink), d_inode(lowerd_link)->i_nlink); -+ d_instantiate(dentry, inode); -+ } else { -+ struct inode *inode_tmp; -+ struct inode *loweri_new = d_inode(lowerd_new); -+ -+ inode_tmp = inode_insert5(inode, (unsigned long)loweri_new, -+ shiftfs_inode_test, shiftfs_inode_set, -+ loweri_new); -+ if (unlikely(inode_tmp != inode)) { -+ pr_err_ratelimited("shiftfs: newly created inode found in cache\n"); -+ iput(inode_tmp); -+ err = -EINVAL; -+ goto out_iput; -+ } -+ -+ ihold(loweri_new); -+ shiftfs_fill_inode(inode, loweri_new->i_ino, loweri_new->i_mode, -+ 0, lowerd_new); -+ d_instantiate_new(dentry, inode); -+ } -+ -+ shiftfs_copyattr(loweri_dir, diri); -+ if (loweri_iop_ptr == loweri_dir_iop->mkdir) -+ set_nlink(diri, loweri_dir->i_nlink); -+ -+ inode = NULL; -+ -+out_iput: -+ iput(inode); -+ inode_unlock(loweri_dir); -+ -+ return err; -+} -+ -+static int shiftfs_create(struct inode *dir, struct dentry *dentry, -+ umode_t mode, bool excl) -+{ -+ mode |= S_IFREG; -+ -+ return shiftfs_create_object(dir, dentry, mode, NULL, NULL, excl); -+} -+ -+static int shiftfs_mkdir(struct inode *dir, struct dentry *dentry, -+ umode_t mode) -+{ -+ mode |= S_IFDIR; -+ -+ return shiftfs_create_object(dir, dentry, mode, NULL, NULL, false); -+} -+ -+static int shiftfs_link(struct dentry *hardlink, struct inode *dir, -+ struct dentry *dentry) -+{ -+ return shiftfs_create_object(dir, dentry, 0, NULL, hardlink, false); -+} -+ -+static int shiftfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, -+ dev_t rdev) -+{ -+ if (!S_ISFIFO(mode) && !S_ISSOCK(mode)) -+ return -EPERM; -+ -+ return shiftfs_create_object(dir, dentry, mode, NULL, NULL, false); -+} -+ -+static int shiftfs_symlink(struct inode *dir, struct dentry *dentry, -+ const char *symlink) -+{ -+ return shiftfs_create_object(dir, dentry, S_IFLNK, symlink, NULL, false); -+} -+ -+static int shiftfs_rm(struct inode *dir, struct dentry *dentry, bool rmdir) -+{ -+ struct dentry *lowerd = dentry->d_fsdata; -+ struct inode *loweri = dir->i_private; -+ struct inode *inode = d_inode(dentry); -+ int err; -+ const struct cred *oldcred; -+ -+ dget(lowerd); -+ oldcred = shiftfs_override_creds(dentry->d_sb); -+ inode_lock_nested(loweri, I_MUTEX_PARENT); -+ if (rmdir) -+ err = vfs_rmdir(loweri, lowerd); -+ else -+ err = vfs_unlink(loweri, lowerd, NULL); -+ revert_creds(oldcred); -+ -+ if (!err) { -+ d_drop(dentry); -+ -+ if (rmdir) -+ clear_nlink(inode); -+ else -+ drop_nlink(inode); -+ } -+ inode_unlock(loweri); -+ -+ shiftfs_copyattr(loweri, dir); -+ dput(lowerd); -+ -+ return err; -+} -+ -+static int shiftfs_unlink(struct inode *dir, struct dentry *dentry) -+{ -+ return shiftfs_rm(dir, dentry, false); -+} -+ -+static int shiftfs_rmdir(struct inode *dir, struct dentry *dentry) -+{ -+ return shiftfs_rm(dir, dentry, true); -+} -+ -+static int shiftfs_rename(struct inode *olddir, struct dentry *old, -+ struct inode *newdir, struct dentry *new, -+ unsigned int flags) -+{ -+ struct dentry *lowerd_dir_old = old->d_parent->d_fsdata, -+ *lowerd_dir_new = new->d_parent->d_fsdata, -+ *lowerd_old = old->d_fsdata, *lowerd_new = new->d_fsdata, -+ *trapd; -+ struct inode *loweri_dir_old = lowerd_dir_old->d_inode, -+ *loweri_dir_new = lowerd_dir_new->d_inode; -+ int err = -EINVAL; -+ const struct cred *oldcred; -+ -+ trapd = lock_rename(lowerd_dir_new, lowerd_dir_old); -+ -+ if (trapd == lowerd_old || trapd == lowerd_new) -+ goto out_unlock; -+ -+ oldcred = shiftfs_override_creds(old->d_sb); -+ err = vfs_rename(loweri_dir_old, lowerd_old, loweri_dir_new, lowerd_new, -+ NULL, flags); -+ revert_creds(oldcred); -+ -+ shiftfs_copyattr(loweri_dir_old, olddir); -+ shiftfs_copyattr(loweri_dir_new, newdir); -+ -+out_unlock: -+ unlock_rename(lowerd_dir_new, lowerd_dir_old); -+ -+ return err; -+} -+ -+static struct dentry *shiftfs_lookup(struct inode *dir, struct dentry *dentry, -+ unsigned int flags) -+{ -+ struct dentry *new; -+ struct inode *newi; -+ const struct cred *oldcred; -+ struct dentry *lowerd = dentry->d_parent->d_fsdata; -+ struct inode *inode = NULL, *loweri = lowerd->d_inode; -+ -+ inode_lock(loweri); -+ oldcred = shiftfs_override_creds(dentry->d_sb); -+ new = lookup_one_len(dentry->d_name.name, lowerd, dentry->d_name.len); -+ revert_creds(oldcred); -+ inode_unlock(loweri); -+ -+ if (IS_ERR(new)) -+ return new; -+ -+ dentry->d_fsdata = new; -+ -+ newi = new->d_inode; -+ if (!newi) -+ goto out; -+ -+ inode = iget5_locked(dentry->d_sb, (unsigned long)newi, -+ shiftfs_inode_test, shiftfs_inode_set, newi); -+ if (!inode) { -+ dput(new); -+ return ERR_PTR(-ENOMEM); -+ } -+ if (inode->i_state & I_NEW) { -+ /* -+ * inode->i_private set by shiftfs_inode_set(), but we still -+ * need to take a reference -+ */ -+ ihold(newi); -+ shiftfs_fill_inode(inode, newi->i_ino, newi->i_mode, 0, new); -+ unlock_new_inode(inode); -+ } -+ -+out: -+ return d_splice_alias(inode, dentry); -+} -+ -+static int shiftfs_permission(struct inode *inode, int mask) -+{ -+ int err; -+ const struct cred *oldcred; -+ struct inode *loweri = inode->i_private; -+ -+ if (!loweri) { -+ WARN_ON(!(mask & MAY_NOT_BLOCK)); -+ return -ECHILD; -+ } -+ -+ err = generic_permission(inode, mask); -+ if (err) -+ return err; -+ -+ oldcred = shiftfs_override_creds(inode->i_sb); -+ err = inode_permission(loweri, mask); -+ revert_creds(oldcred); -+ -+ return err; -+} -+ -+static int shiftfs_fiemap(struct inode *inode, -+ struct fiemap_extent_info *fieinfo, u64 start, -+ u64 len) -+{ -+ int err; -+ const struct cred *oldcred; -+ struct inode *loweri = inode->i_private; -+ -+ if (!loweri->i_op->fiemap) -+ return -EOPNOTSUPP; -+ -+ oldcred = shiftfs_override_creds(inode->i_sb); -+ if (fieinfo->fi_flags & FIEMAP_FLAG_SYNC) -+ filemap_write_and_wait(loweri->i_mapping); -+ err = loweri->i_op->fiemap(loweri, fieinfo, start, len); -+ revert_creds(oldcred); -+ -+ return err; -+} -+ -+static int shiftfs_tmpfile(struct inode *dir, struct dentry *dentry, -+ umode_t mode) -+{ -+ int err; -+ const struct cred *oldcred; -+ struct dentry *lowerd = dentry->d_fsdata; -+ struct inode *loweri = dir->i_private; -+ -+ if (!loweri->i_op->tmpfile) -+ return -EOPNOTSUPP; -+ -+ oldcred = shiftfs_override_creds(dir->i_sb); -+ err = loweri->i_op->tmpfile(loweri, lowerd, mode); -+ revert_creds(oldcred); -+ -+ return err; -+} -+ -+static int shiftfs_setattr(struct dentry *dentry, struct iattr *attr) -+{ -+ struct dentry *lowerd = dentry->d_fsdata; -+ struct inode *loweri = lowerd->d_inode; -+ struct iattr newattr; -+ const struct cred *oldcred; -+ struct super_block *sb = dentry->d_sb; -+ struct shiftfs_super_info *sbinfo = sb->s_fs_info; -+ int err; -+ -+ err = setattr_prepare(dentry, attr); -+ if (err) -+ return err; -+ -+ newattr = *attr; -+ newattr.ia_uid = shift_kuid(sb->s_user_ns, sbinfo->userns, attr->ia_uid); -+ newattr.ia_gid = shift_kgid(sb->s_user_ns, sbinfo->userns, attr->ia_gid); -+ -+ /* -+ * mode change is for clearing setuid/setgid bits. Allow lower fs -+ * to interpret this in its own way. -+ */ -+ if (newattr.ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID)) -+ newattr.ia_valid &= ~ATTR_MODE; -+ -+ inode_lock(loweri); -+ oldcred = shiftfs_override_creds(dentry->d_sb); -+ err = notify_change(lowerd, &newattr, NULL); -+ revert_creds(oldcred); -+ inode_unlock(loweri); -+ -+ shiftfs_copyattr(loweri, d_inode(dentry)); -+ -+ return err; -+} -+ -+static int shiftfs_getattr(const struct path *path, struct kstat *stat, -+ u32 request_mask, unsigned int query_flags) -+{ -+ struct inode *inode = path->dentry->d_inode; -+ struct dentry *lowerd = path->dentry->d_fsdata; -+ struct inode *loweri = lowerd->d_inode; -+ struct shiftfs_super_info *info = path->dentry->d_sb->s_fs_info; -+ struct path newpath = { .mnt = info->mnt, .dentry = lowerd }; -+ struct user_namespace *from_ns = loweri->i_sb->s_user_ns; -+ struct user_namespace *to_ns = inode->i_sb->s_user_ns; -+ const struct cred *oldcred; -+ int err; -+ -+ oldcred = shiftfs_override_creds(inode->i_sb); -+ err = vfs_getattr(&newpath, stat, request_mask, query_flags); -+ revert_creds(oldcred); -+ -+ if (err) -+ return err; -+ -+ /* transform the underlying id */ -+ stat->uid = shift_kuid(from_ns, to_ns, stat->uid); -+ stat->gid = shift_kgid(from_ns, to_ns, stat->gid); -+ return 0; -+} -+ -+#ifdef CONFIG_SHIFT_FS_POSIX_ACL -+ -+static int -+shift_acl_ids(struct user_namespace *from, struct user_namespace *to, -+ struct posix_acl *acl) -+{ -+ int i; -+ -+ for (i = 0; i < acl->a_count; i++) { -+ struct posix_acl_entry *e = &acl->a_entries[i]; -+ switch(e->e_tag) { -+ case ACL_USER: -+ e->e_uid = shift_kuid(from, to, e->e_uid); -+ if (!uid_valid(e->e_uid)) -+ return -EOVERFLOW; -+ break; -+ case ACL_GROUP: -+ e->e_gid = shift_kgid(from, to, e->e_gid); -+ if (!gid_valid(e->e_gid)) -+ return -EOVERFLOW; -+ break; -+ } -+ } -+ return 0; -+} -+ -+static void -+shift_acl_xattr_ids(struct user_namespace *from, struct user_namespace *to, -+ void *value, size_t size) -+{ -+ struct posix_acl_xattr_header *header = value; -+ struct posix_acl_xattr_entry *entry = (void *)(header + 1), *end; -+ int count; -+ kuid_t kuid; -+ kgid_t kgid; -+ -+ if (!value) -+ return; -+ if (size < sizeof(struct posix_acl_xattr_header)) -+ return; -+ if (header->a_version != cpu_to_le32(POSIX_ACL_XATTR_VERSION)) -+ return; -+ -+ count = posix_acl_xattr_count(size); -+ if (count < 0) -+ return; -+ if (count == 0) -+ return; -+ -+ for (end = entry + count; entry != end; entry++) { -+ switch(le16_to_cpu(entry->e_tag)) { -+ case ACL_USER: -+ kuid = make_kuid(&init_user_ns, le32_to_cpu(entry->e_id)); -+ kuid = shift_kuid(from, to, kuid); -+ entry->e_id = cpu_to_le32(from_kuid(&init_user_ns, kuid)); -+ break; -+ case ACL_GROUP: -+ kgid = make_kgid(&init_user_ns, le32_to_cpu(entry->e_id)); -+ kgid = shift_kgid(from, to, kgid); -+ entry->e_id = cpu_to_le32(from_kgid(&init_user_ns, kgid)); -+ break; -+ default: -+ break; -+ } -+ } -+} -+ -+static struct posix_acl *shiftfs_get_acl(struct inode *inode, int type) -+{ -+ struct inode *loweri = inode->i_private; -+ const struct cred *oldcred; -+ struct posix_acl *lower_acl, *acl = NULL; -+ struct user_namespace *from_ns = loweri->i_sb->s_user_ns; -+ struct user_namespace *to_ns = inode->i_sb->s_user_ns; -+ int size; -+ int err; -+ -+ if (!IS_POSIXACL(loweri)) -+ return NULL; -+ -+ oldcred = shiftfs_override_creds(inode->i_sb); -+ lower_acl = get_acl(loweri, type); -+ revert_creds(oldcred); -+ -+ if (lower_acl && !IS_ERR(lower_acl)) { -+ /* XXX: export posix_acl_clone? */ -+ size = sizeof(struct posix_acl) + -+ lower_acl->a_count * sizeof(struct posix_acl_entry); -+ acl = kmemdup(lower_acl, size, GFP_KERNEL); -+ posix_acl_release(lower_acl); -+ -+ if (!acl) -+ return ERR_PTR(-ENOMEM); -+ -+ refcount_set(&acl->a_refcount, 1); -+ -+ err = shift_acl_ids(from_ns, to_ns, acl); -+ if (err) { -+ kfree(acl); -+ return ERR_PTR(err); -+ } -+ } -+ -+ return acl; -+} -+ -+static int -+shiftfs_posix_acl_xattr_get(const struct xattr_handler *handler, -+ struct dentry *dentry, struct inode *inode, -+ const char *name, void *buffer, size_t size) -+{ -+ struct inode *loweri = inode->i_private; -+ int ret; -+ -+ ret = shiftfs_xattr_get(NULL, dentry, inode, handler->name, -+ buffer, size); -+ if (ret < 0) -+ return ret; -+ -+ inode_lock(loweri); -+ shift_acl_xattr_ids(loweri->i_sb->s_user_ns, inode->i_sb->s_user_ns, -+ buffer, size); -+ inode_unlock(loweri); -+ return ret; -+} -+ -+static int -+shiftfs_posix_acl_xattr_set(const struct xattr_handler *handler, -+ struct dentry *dentry, struct inode *inode, -+ const char *name, const void *value, -+ size_t size, int flags) -+{ -+ struct inode *loweri = inode->i_private; -+ int err; -+ -+ if (!IS_POSIXACL(loweri) || !loweri->i_op->set_acl) -+ return -EOPNOTSUPP; -+ if (handler->flags == ACL_TYPE_DEFAULT && !S_ISDIR(inode->i_mode)) -+ return value ? -EACCES : 0; -+ if (!inode_owner_or_capable(inode)) -+ return -EPERM; -+ -+ if (value) { -+ shift_acl_xattr_ids(inode->i_sb->s_user_ns, -+ loweri->i_sb->s_user_ns, -+ (void *)value, size); -+ err = shiftfs_setxattr(dentry, inode, handler->name, value, -+ size, flags); -+ } else { -+ err = shiftfs_removexattr(dentry, handler->name); -+ } -+ -+ if (!err) -+ shiftfs_copyattr(loweri, inode); -+ -+ return err; -+} -+ -+static const struct xattr_handler -+shiftfs_posix_acl_access_xattr_handler = { -+ .name = XATTR_NAME_POSIX_ACL_ACCESS, -+ .flags = ACL_TYPE_ACCESS, -+ .get = shiftfs_posix_acl_xattr_get, -+ .set = shiftfs_posix_acl_xattr_set, -+}; -+ -+static const struct xattr_handler -+shiftfs_posix_acl_default_xattr_handler = { -+ .name = XATTR_NAME_POSIX_ACL_DEFAULT, -+ .flags = ACL_TYPE_DEFAULT, -+ .get = shiftfs_posix_acl_xattr_get, -+ .set = shiftfs_posix_acl_xattr_set, -+}; -+ -+#else /* !CONFIG_SHIFT_FS_POSIX_ACL */ -+ -+#define shiftfs_get_acl NULL -+ -+#endif /* CONFIG_SHIFT_FS_POSIX_ACL */ -+ -+static const struct inode_operations shiftfs_dir_inode_operations = { -+ .lookup = shiftfs_lookup, -+ .mkdir = shiftfs_mkdir, -+ .symlink = shiftfs_symlink, -+ .unlink = shiftfs_unlink, -+ .rmdir = shiftfs_rmdir, -+ .rename = shiftfs_rename, -+ .link = shiftfs_link, -+ .setattr = shiftfs_setattr, -+ .create = shiftfs_create, -+ .mknod = shiftfs_mknod, -+ .permission = shiftfs_permission, -+ .getattr = shiftfs_getattr, -+ .listxattr = shiftfs_listxattr, -+ .get_acl = shiftfs_get_acl, -+}; -+ -+static const struct inode_operations shiftfs_file_inode_operations = { -+ .fiemap = shiftfs_fiemap, -+ .getattr = shiftfs_getattr, -+ .get_acl = shiftfs_get_acl, -+ .listxattr = shiftfs_listxattr, -+ .permission = shiftfs_permission, -+ .setattr = shiftfs_setattr, -+ .tmpfile = shiftfs_tmpfile, -+}; -+ -+static const struct inode_operations shiftfs_special_inode_operations = { -+ .getattr = shiftfs_getattr, -+ .get_acl = shiftfs_get_acl, -+ .listxattr = shiftfs_listxattr, -+ .permission = shiftfs_permission, -+ .setattr = shiftfs_setattr, -+}; -+ -+static const struct inode_operations shiftfs_symlink_inode_operations = { -+ .getattr = shiftfs_getattr, -+ .get_link = shiftfs_get_link, -+ .listxattr = shiftfs_listxattr, -+ .setattr = shiftfs_setattr, -+}; -+ -+static struct file *shiftfs_open_realfile(const struct file *file, -+ struct inode *realinode) -+{ -+ struct file *realfile; -+ const struct cred *old_cred; -+ struct inode *inode = file_inode(file); -+ struct dentry *lowerd = file->f_path.dentry->d_fsdata; -+ struct shiftfs_super_info *info = inode->i_sb->s_fs_info; -+ struct path realpath = { .mnt = info->mnt, .dentry = lowerd }; -+ -+ old_cred = shiftfs_override_creds(inode->i_sb); -+ realfile = open_with_fake_path(&realpath, file->f_flags, realinode, -+ info->creator_cred); -+ revert_creds(old_cred); -+ -+ return realfile; -+} -+ -+#define SHIFTFS_SETFL_MASK (O_APPEND | O_NONBLOCK | O_NDELAY | O_DIRECT) -+ -+static int shiftfs_change_flags(struct file *file, unsigned int flags) -+{ -+ struct inode *inode = file_inode(file); -+ int err; -+ -+ /* if some flag changed that cannot be changed then something's amiss */ -+ if (WARN_ON((file->f_flags ^ flags) & ~SHIFTFS_SETFL_MASK)) -+ return -EIO; -+ -+ flags &= SHIFTFS_SETFL_MASK; -+ -+ if (((flags ^ file->f_flags) & O_APPEND) && IS_APPEND(inode)) -+ return -EPERM; -+ -+ if (flags & O_DIRECT) { -+ if (!file->f_mapping->a_ops || -+ !file->f_mapping->a_ops->direct_IO) -+ return -EINVAL; -+ } -+ -+ if (file->f_op->check_flags) { -+ err = file->f_op->check_flags(flags); -+ if (err) -+ return err; -+ } -+ -+ spin_lock(&file->f_lock); -+ file->f_flags = (file->f_flags & ~SHIFTFS_SETFL_MASK) | flags; -+ spin_unlock(&file->f_lock); -+ -+ return 0; -+} -+ -+static int shiftfs_open(struct inode *inode, struct file *file) -+{ -+ struct file *realfile; -+ -+ realfile = shiftfs_open_realfile(file, inode->i_private); -+ if (IS_ERR(realfile)) -+ return PTR_ERR(realfile); -+ -+ file->private_data = realfile; -+ /* For O_DIRECT dentry_open() checks f_mapping->a_ops->direct_IO. */ -+ file->f_mapping = realfile->f_mapping; -+ -+ return 0; -+} -+ -+static int shiftfs_dir_open(struct inode *inode, struct file *file) -+{ -+ struct file *realfile; -+ const struct cred *oldcred; -+ struct dentry *lowerd = file->f_path.dentry->d_fsdata; -+ struct shiftfs_super_info *info = inode->i_sb->s_fs_info; -+ struct path realpath = { .mnt = info->mnt, .dentry = lowerd }; -+ -+ oldcred = shiftfs_override_creds(file->f_path.dentry->d_sb); -+ realfile = dentry_open(&realpath, file->f_flags | O_NOATIME, -+ info->creator_cred); -+ revert_creds(oldcred); -+ if (IS_ERR(realfile)) -+ return PTR_ERR(realfile); -+ -+ file->private_data = realfile; -+ -+ return 0; -+} -+ -+static int shiftfs_release(struct inode *inode, struct file *file) -+{ -+ struct file *realfile = file->private_data; -+ -+ if (realfile) -+ fput(realfile); -+ -+ return 0; -+} -+ -+static int shiftfs_dir_release(struct inode *inode, struct file *file) -+{ -+ return shiftfs_release(inode, file); -+} -+ -+static loff_t shiftfs_dir_llseek(struct file *file, loff_t offset, int whence) -+{ -+ struct file *realfile = file->private_data; -+ -+ return vfs_llseek(realfile, offset, whence); -+} -+ -+static loff_t shiftfs_file_llseek(struct file *file, loff_t offset, int whence) -+{ -+ struct inode *realinode = file_inode(file)->i_private; -+ -+ return generic_file_llseek_size(file, offset, whence, -+ realinode->i_sb->s_maxbytes, -+ i_size_read(realinode)); -+} -+ -+/* XXX: Need to figure out what to to about atime updates, maybe other -+ * timestamps too ... ref. ovl_file_accessed() */ -+ -+static rwf_t shiftfs_iocb_to_rwf(struct kiocb *iocb) -+{ -+ int ifl = iocb->ki_flags; -+ rwf_t flags = 0; -+ -+ if (ifl & IOCB_NOWAIT) -+ flags |= RWF_NOWAIT; -+ if (ifl & IOCB_HIPRI) -+ flags |= RWF_HIPRI; -+ if (ifl & IOCB_DSYNC) -+ flags |= RWF_DSYNC; -+ if (ifl & IOCB_SYNC) -+ flags |= RWF_SYNC; -+ -+ return flags; -+} -+ -+static int shiftfs_real_fdget(const struct file *file, struct fd *lowerfd) -+{ -+ struct file *realfile; -+ -+ if (file->f_op->open != shiftfs_open && -+ file->f_op->open != shiftfs_dir_open) -+ return -EINVAL; -+ -+ realfile = file->private_data; -+ lowerfd->flags = 0; -+ lowerfd->file = realfile; -+ -+ /* Did the flags change since open? */ -+ if (unlikely(file->f_flags & ~lowerfd->file->f_flags)) -+ return shiftfs_change_flags(lowerfd->file, file->f_flags); -+ -+ return 0; -+} -+ -+static ssize_t shiftfs_read_iter(struct kiocb *iocb, struct iov_iter *iter) -+{ -+ struct file *file = iocb->ki_filp; -+ struct fd lowerfd; -+ const struct cred *oldcred; -+ ssize_t ret; -+ -+ if (!iov_iter_count(iter)) -+ return 0; -+ -+ ret = shiftfs_real_fdget(file, &lowerfd); -+ if (ret) -+ return ret; -+ -+ oldcred = shiftfs_override_creds(file->f_path.dentry->d_sb); -+ ret = vfs_iter_read(lowerfd.file, iter, &iocb->ki_pos, -+ shiftfs_iocb_to_rwf(iocb)); -+ revert_creds(oldcred); -+ -+ shiftfs_file_accessed(file); -+ -+ fdput(lowerfd); -+ return ret; -+} -+ -+static ssize_t shiftfs_write_iter(struct kiocb *iocb, struct iov_iter *iter) -+{ -+ struct file *file = iocb->ki_filp; -+ struct inode *inode = file_inode(file); -+ struct fd lowerfd; -+ const struct cred *oldcred; -+ ssize_t ret; -+ -+ if (!iov_iter_count(iter)) -+ return 0; -+ -+ inode_lock(inode); -+ /* Update mode */ -+ shiftfs_copyattr(inode->i_private, inode); -+ ret = file_remove_privs(file); -+ if (ret) -+ goto out_unlock; -+ -+ ret = shiftfs_real_fdget(file, &lowerfd); -+ if (ret) -+ goto out_unlock; -+ -+ oldcred = shiftfs_override_creds(file->f_path.dentry->d_sb); -+ file_start_write(lowerfd.file); -+ ret = vfs_iter_write(lowerfd.file, iter, &iocb->ki_pos, -+ shiftfs_iocb_to_rwf(iocb)); -+ file_end_write(lowerfd.file); -+ revert_creds(oldcred); -+ -+ /* Update size */ -+ shiftfs_copyattr(inode->i_private, inode); -+ -+ fdput(lowerfd); -+ -+out_unlock: -+ inode_unlock(inode); -+ return ret; -+} -+ -+static int shiftfs_fsync(struct file *file, loff_t start, loff_t end, -+ int datasync) -+{ -+ struct fd lowerfd; -+ const struct cred *oldcred; -+ int ret; -+ -+ ret = shiftfs_real_fdget(file, &lowerfd); -+ if (ret) -+ return ret; -+ -+ oldcred = shiftfs_override_creds(file->f_path.dentry->d_sb); -+ ret = vfs_fsync_range(lowerfd.file, start, end, datasync); -+ revert_creds(oldcred); -+ -+ fdput(lowerfd); -+ return ret; -+} -+ -+static int shiftfs_mmap(struct file *file, struct vm_area_struct *vma) -+{ -+ struct file *realfile = file->private_data; -+ const struct cred *oldcred; -+ int ret; -+ -+ if (!realfile->f_op->mmap) -+ return -ENODEV; -+ -+ if (WARN_ON(file != vma->vm_file)) -+ return -EIO; -+ -+ oldcred = shiftfs_override_creds(file->f_path.dentry->d_sb); -+ vma->vm_file = get_file(realfile); -+ ret = call_mmap(vma->vm_file, vma); -+ revert_creds(oldcred); -+ -+ shiftfs_file_accessed(file); -+ -+ if (ret) { -+ /* -+ * Drop refcount from new vm_file value and restore original -+ * vm_file value -+ */ -+ vma->vm_file = file; -+ fput(realfile); -+ } else { -+ /* Drop refcount from previous vm_file value */ -+ fput(file); -+ } -+ -+ return ret; -+} -+ -+static long shiftfs_fallocate(struct file *file, int mode, loff_t offset, -+ loff_t len) -+{ -+ struct inode *inode = file_inode(file); -+ struct inode *loweri = inode->i_private; -+ struct fd lowerfd; -+ const struct cred *oldcred; -+ int ret; -+ -+ ret = shiftfs_real_fdget(file, &lowerfd); -+ if (ret) -+ return ret; -+ -+ oldcred = shiftfs_override_creds(file->f_path.dentry->d_sb); -+ ret = vfs_fallocate(lowerfd.file, mode, offset, len); -+ revert_creds(oldcred); -+ -+ /* Update size */ -+ shiftfs_copyattr(loweri, inode); -+ -+ fdput(lowerfd); -+ return ret; -+} -+ -+static int shiftfs_fadvise(struct file *file, loff_t offset, loff_t len, -+ int advice) -+{ -+ struct fd lowerfd; -+ const struct cred *oldcred; -+ int ret; -+ -+ ret = shiftfs_real_fdget(file, &lowerfd); -+ if (ret) -+ return ret; -+ -+ oldcred = shiftfs_override_creds(file->f_path.dentry->d_sb); -+ ret = vfs_fadvise(lowerfd.file, offset, len, advice); -+ revert_creds(oldcred); -+ -+ fdput(lowerfd); -+ return ret; -+} -+ -+static int shiftfs_override_ioctl_creds(int cmd, const struct super_block *sb, -+ const struct cred **oldcred, -+ struct cred **newcred) -+{ -+ struct shiftfs_super_info *sbinfo = sb->s_fs_info; -+ kuid_t fsuid = current_fsuid(); -+ kgid_t fsgid = current_fsgid(); -+ -+ *oldcred = shiftfs_override_creds(sb); -+ -+ *newcred = prepare_creds(); -+ if (!*newcred) { -+ revert_creds(*oldcred); -+ return -ENOMEM; -+ } -+ -+ (*newcred)->fsuid = shift_kuid(sb->s_user_ns, sbinfo->userns, fsuid); -+ (*newcred)->fsgid = shift_kgid(sb->s_user_ns, sbinfo->userns, fsgid); -+ -+ /* clear all caps to prevent bypassing capable() checks */ -+ cap_clear((*newcred)->cap_bset); -+ cap_clear((*newcred)->cap_effective); -+ cap_clear((*newcred)->cap_inheritable); -+ cap_clear((*newcred)->cap_permitted); -+ -+ if (cmd == BTRFS_IOC_SNAP_DESTROY) { -+ kuid_t kuid_root = make_kuid(sb->s_user_ns, 0); -+ /* -+ * Allow the root user in the container to remove subvolumes -+ * from other users. -+ */ -+ if (uid_valid(kuid_root) && uid_eq(fsuid, kuid_root)) -+ cap_raise((*newcred)->cap_effective, CAP_DAC_OVERRIDE); -+ } -+ -+ put_cred(override_creds(*newcred)); -+ return 0; -+} -+ -+static inline void shiftfs_revert_ioctl_creds(const struct cred *oldcred, -+ struct cred *newcred) -+{ -+ return shiftfs_revert_object_creds(oldcred, newcred); -+} -+ -+static inline bool is_btrfs_snap_ioctl(int cmd) -+{ -+ if ((cmd == BTRFS_IOC_SNAP_CREATE) || (cmd == BTRFS_IOC_SNAP_CREATE_V2)) -+ return true; -+ -+ return false; -+} -+ -+static int shiftfs_btrfs_ioctl_fd_restore(int cmd, int fd, void __user *arg, -+ struct btrfs_ioctl_vol_args *v1, -+ struct btrfs_ioctl_vol_args_v2 *v2) -+{ -+ int ret; -+ -+ if (!is_btrfs_snap_ioctl(cmd)) -+ return 0; -+ -+ if (cmd == BTRFS_IOC_SNAP_CREATE) -+ ret = copy_to_user(arg, v1, sizeof(*v1)); -+ else -+ ret = copy_to_user(arg, v2, sizeof(*v2)); -+ -+ __close_fd(current->files, fd); -+ kfree(v1); -+ kfree(v2); -+ -+ return ret; -+} -+ -+static int shiftfs_btrfs_ioctl_fd_replace(int cmd, void __user *arg, -+ struct btrfs_ioctl_vol_args **b1, -+ struct btrfs_ioctl_vol_args_v2 **b2, -+ int *newfd) -+{ -+ int oldfd, ret; -+ struct fd src; -+ struct fd lfd = {}; -+ struct btrfs_ioctl_vol_args *v1 = NULL; -+ struct btrfs_ioctl_vol_args_v2 *v2 = NULL; -+ -+ if (!is_btrfs_snap_ioctl(cmd)) -+ return 0; -+ -+ if (cmd == BTRFS_IOC_SNAP_CREATE) { -+ v1 = memdup_user(arg, sizeof(*v1)); -+ if (IS_ERR(v1)) -+ return PTR_ERR(v1); -+ oldfd = v1->fd; -+ *b1 = v1; -+ } else { -+ v2 = memdup_user(arg, sizeof(*v2)); -+ if (IS_ERR(v2)) -+ return PTR_ERR(v2); -+ oldfd = v2->fd; -+ *b2 = v2; -+ } -+ -+ src = fdget(oldfd); -+ if (!src.file) -+ return -EINVAL; -+ -+ ret = shiftfs_real_fdget(src.file, &lfd); -+ if (ret) { -+ fdput(src); -+ return ret; -+ } -+ -+ /* -+ * shiftfs_real_fdget() does not take a reference to lfd.file, so -+ * take a reference here to offset the one which will be put by -+ * __close_fd(), and make sure that reference is put on fdput(lfd). -+ */ -+ get_file(lfd.file); -+ lfd.flags |= FDPUT_FPUT; -+ fdput(src); -+ -+ *newfd = get_unused_fd_flags(lfd.file->f_flags); -+ if (*newfd < 0) { -+ fdput(lfd); -+ return *newfd; -+ } -+ -+ fd_install(*newfd, lfd.file); -+ -+ if (cmd == BTRFS_IOC_SNAP_CREATE) { -+ v1->fd = *newfd; -+ ret = copy_to_user(arg, v1, sizeof(*v1)); -+ v1->fd = oldfd; -+ } else { -+ v2->fd = *newfd; -+ ret = copy_to_user(arg, v2, sizeof(*v2)); -+ v2->fd = oldfd; -+ } -+ -+ if (ret) -+ shiftfs_btrfs_ioctl_fd_restore(cmd, *newfd, arg, v1, v2); -+ -+ return ret; -+} -+ -+static long shiftfs_real_ioctl(struct file *file, unsigned int cmd, -+ unsigned long arg) -+{ -+ struct fd lowerfd; -+ struct cred *newcred; -+ const struct cred *oldcred; -+ int newfd = -EBADF; -+ long err = 0, ret = 0; -+ void __user *argp = (void __user *)arg; -+ struct super_block *sb = file->f_path.dentry->d_sb; -+ struct btrfs_ioctl_vol_args *btrfs_v1 = NULL; -+ struct btrfs_ioctl_vol_args_v2 *btrfs_v2 = NULL; -+ -+ ret = shiftfs_btrfs_ioctl_fd_replace(cmd, argp, &btrfs_v1, &btrfs_v2, -+ &newfd); -+ if (ret < 0) -+ return ret; -+ -+ ret = shiftfs_real_fdget(file, &lowerfd); -+ if (ret) -+ goto out_restore; -+ -+ ret = shiftfs_override_ioctl_creds(cmd, sb, &oldcred, &newcred); -+ if (ret) -+ goto out_fdput; -+ -+ ret = vfs_ioctl(lowerfd.file, cmd, arg); -+ -+ shiftfs_revert_ioctl_creds(oldcred, newcred); -+ -+ shiftfs_copyattr(file_inode(lowerfd.file), file_inode(file)); -+ shiftfs_copyflags(file_inode(lowerfd.file), file_inode(file)); -+ -+out_fdput: -+ fdput(lowerfd); -+ -+out_restore: -+ err = shiftfs_btrfs_ioctl_fd_restore(cmd, newfd, argp, -+ btrfs_v1, btrfs_v2); -+ if (!ret) -+ ret = err; -+ -+ return ret; -+} -+ -+static bool in_ioctl_whitelist(int flag, unsigned long arg) -+{ -+ void __user *argp = (void __user *)arg; -+ u64 flags = 0; -+ -+ switch (flag) { -+ case BTRFS_IOC_FS_INFO: -+ return true; -+ case BTRFS_IOC_SNAP_CREATE: -+ return true; -+ case BTRFS_IOC_SNAP_CREATE_V2: -+ return true; -+ case BTRFS_IOC_SUBVOL_CREATE: -+ return true; -+ case BTRFS_IOC_SUBVOL_CREATE_V2: -+ return true; -+ case BTRFS_IOC_SUBVOL_GETFLAGS: -+ return true; -+ case BTRFS_IOC_SUBVOL_SETFLAGS: -+ if (copy_from_user(&flags, argp, sizeof(flags))) -+ return false; -+ -+ if (flags & ~BTRFS_SUBVOL_RDONLY) -+ return false; -+ -+ return true; -+ case BTRFS_IOC_SNAP_DESTROY: -+ return true; -+ } -+ -+ return false; -+} -+ -+static long shiftfs_ioctl(struct file *file, unsigned int cmd, -+ unsigned long arg) -+{ -+ switch (cmd) { -+ case FS_IOC_GETVERSION: -+ /* fall through */ -+ case FS_IOC_GETFLAGS: -+ /* fall through */ -+ case FS_IOC_SETFLAGS: -+ break; -+ default: -+ if (!in_ioctl_whitelist(cmd, arg) || -+ !shiftfs_passthrough_ioctls(file->f_path.dentry->d_sb->s_fs_info)) -+ return -ENOTTY; -+ } -+ -+ return shiftfs_real_ioctl(file, cmd, arg); -+} -+ -+static long shiftfs_compat_ioctl(struct file *file, unsigned int cmd, -+ unsigned long arg) -+{ -+ switch (cmd) { -+ case FS_IOC32_GETVERSION: -+ /* fall through */ -+ case FS_IOC32_GETFLAGS: -+ /* fall through */ -+ case FS_IOC32_SETFLAGS: -+ break; -+ default: -+ if (!in_ioctl_whitelist(cmd, arg) || -+ !shiftfs_passthrough_ioctls(file->f_path.dentry->d_sb->s_fs_info)) -+ return -ENOIOCTLCMD; -+ } -+ -+ return shiftfs_real_ioctl(file, cmd, arg); -+} -+ -+enum shiftfs_copyop { -+ SHIFTFS_COPY, -+ SHIFTFS_CLONE, -+ SHIFTFS_DEDUPE, -+}; -+ -+static ssize_t shiftfs_copyfile(struct file *file_in, loff_t pos_in, -+ struct file *file_out, loff_t pos_out, u64 len, -+ unsigned int flags, enum shiftfs_copyop op) -+{ -+ ssize_t ret; -+ struct fd real_in, real_out; -+ const struct cred *oldcred; -+ struct inode *inode_out = file_inode(file_out); -+ struct inode *loweri = inode_out->i_private; -+ -+ ret = shiftfs_real_fdget(file_out, &real_out); -+ if (ret) -+ return ret; -+ -+ ret = shiftfs_real_fdget(file_in, &real_in); -+ if (ret) { -+ fdput(real_out); -+ return ret; -+ } -+ -+ oldcred = shiftfs_override_creds(inode_out->i_sb); -+ switch (op) { -+ case SHIFTFS_COPY: -+ ret = vfs_copy_file_range(real_in.file, pos_in, real_out.file, -+ pos_out, len, flags); -+ break; -+ -+ case SHIFTFS_CLONE: -+ ret = vfs_clone_file_range(real_in.file, pos_in, real_out.file, -+ pos_out, len, flags); -+ break; -+ -+ case SHIFTFS_DEDUPE: -+ ret = vfs_dedupe_file_range_one(real_in.file, pos_in, -+ real_out.file, pos_out, len, -+ flags); -+ break; -+ } -+ revert_creds(oldcred); -+ -+ /* Update size */ -+ shiftfs_copyattr(loweri, inode_out); -+ -+ fdput(real_in); -+ fdput(real_out); -+ -+ return ret; -+} -+ -+static ssize_t shiftfs_copy_file_range(struct file *file_in, loff_t pos_in, -+ struct file *file_out, loff_t pos_out, -+ size_t len, unsigned int flags) -+{ -+ return shiftfs_copyfile(file_in, pos_in, file_out, pos_out, len, flags, -+ SHIFTFS_COPY); -+} -+ -+static loff_t shiftfs_remap_file_range(struct file *file_in, loff_t pos_in, -+ struct file *file_out, loff_t pos_out, -+ loff_t len, unsigned int remap_flags) -+{ -+ enum shiftfs_copyop op; -+ -+ if (remap_flags & ~(REMAP_FILE_DEDUP | REMAP_FILE_ADVISORY)) -+ return -EINVAL; -+ -+ if (remap_flags & REMAP_FILE_DEDUP) -+ op = SHIFTFS_DEDUPE; -+ else -+ op = SHIFTFS_CLONE; -+ -+ return shiftfs_copyfile(file_in, pos_in, file_out, pos_out, len, -+ remap_flags, op); -+} -+ -+static int shiftfs_iterate_shared(struct file *file, struct dir_context *ctx) -+{ -+ const struct cred *oldcred; -+ int err = -ENOTDIR; -+ struct file *realfile = file->private_data; -+ -+ oldcred = shiftfs_override_creds(file->f_path.dentry->d_sb); -+ err = iterate_dir(realfile, ctx); -+ revert_creds(oldcred); -+ -+ return err; -+} -+ -+const struct file_operations shiftfs_file_operations = { -+ .open = shiftfs_open, -+ .release = shiftfs_release, -+ .llseek = shiftfs_file_llseek, -+ .read_iter = shiftfs_read_iter, -+ .write_iter = shiftfs_write_iter, -+ .fsync = shiftfs_fsync, -+ .mmap = shiftfs_mmap, -+ .fallocate = shiftfs_fallocate, -+ .fadvise = shiftfs_fadvise, -+ .unlocked_ioctl = shiftfs_ioctl, -+ .compat_ioctl = shiftfs_compat_ioctl, -+ .copy_file_range = shiftfs_copy_file_range, -+ .remap_file_range = shiftfs_remap_file_range, -+}; -+ -+const struct file_operations shiftfs_dir_operations = { -+ .open = shiftfs_dir_open, -+ .release = shiftfs_dir_release, -+ .compat_ioctl = shiftfs_compat_ioctl, -+ .fsync = shiftfs_fsync, -+ .iterate_shared = shiftfs_iterate_shared, -+ .llseek = shiftfs_dir_llseek, -+ .read = generic_read_dir, -+ .unlocked_ioctl = shiftfs_ioctl, -+}; -+ -+static const struct address_space_operations shiftfs_aops = { -+ /* For O_DIRECT dentry_open() checks f_mapping->a_ops->direct_IO */ -+ .direct_IO = noop_direct_IO, -+}; -+ -+static void shiftfs_fill_inode(struct inode *inode, unsigned long ino, -+ umode_t mode, dev_t dev, struct dentry *dentry) -+{ -+ struct inode *loweri; -+ -+ inode->i_ino = ino; -+ inode->i_flags |= S_NOCMTIME; -+ -+ mode &= S_IFMT; -+ inode->i_mode = mode; -+ switch (mode & S_IFMT) { -+ case S_IFDIR: -+ inode->i_op = &shiftfs_dir_inode_operations; -+ inode->i_fop = &shiftfs_dir_operations; -+ break; -+ case S_IFLNK: -+ inode->i_op = &shiftfs_symlink_inode_operations; -+ break; -+ case S_IFREG: -+ inode->i_op = &shiftfs_file_inode_operations; -+ inode->i_fop = &shiftfs_file_operations; -+ inode->i_mapping->a_ops = &shiftfs_aops; -+ break; -+ default: -+ inode->i_op = &shiftfs_special_inode_operations; -+ init_special_inode(inode, mode, dev); -+ break; -+ } -+ -+ if (!dentry) -+ return; -+ -+ loweri = dentry->d_inode; -+ if (!loweri->i_op->get_link) -+ inode->i_opflags |= IOP_NOFOLLOW; -+ -+ shiftfs_copyattr(loweri, inode); -+ shiftfs_copyflags(loweri, inode); -+ set_nlink(inode, loweri->i_nlink); -+} -+ -+static int shiftfs_show_options(struct seq_file *m, struct dentry *dentry) -+{ -+ struct super_block *sb = dentry->d_sb; -+ struct shiftfs_super_info *sbinfo = sb->s_fs_info; -+ -+ if (sbinfo->mark) -+ seq_show_option(m, "mark", NULL); -+ -+ if (sbinfo->passthrough) -+ seq_printf(m, ",passthrough=%u", sbinfo->passthrough); -+ -+ return 0; -+} -+ -+static int shiftfs_statfs(struct dentry *dentry, struct kstatfs *buf) -+{ -+ struct super_block *sb = dentry->d_sb; -+ struct shiftfs_super_info *sbinfo = sb->s_fs_info; -+ struct dentry *root = sb->s_root; -+ struct dentry *realroot = root->d_fsdata; -+ struct path realpath = { .mnt = sbinfo->mnt, .dentry = realroot }; -+ int err; -+ -+ err = vfs_statfs(&realpath, buf); -+ if (err) -+ return err; -+ -+ if (!shiftfs_passthrough_statfs(sbinfo)) -+ buf->f_type = sb->s_magic; -+ -+ return 0; -+} -+ -+static void shiftfs_evict_inode(struct inode *inode) -+{ -+ struct inode *loweri = inode->i_private; -+ -+ clear_inode(inode); -+ -+ if (loweri) -+ iput(loweri); -+} -+ -+static void shiftfs_put_super(struct super_block *sb) -+{ -+ struct shiftfs_super_info *sbinfo = sb->s_fs_info; -+ -+ if (sbinfo) { -+ mntput(sbinfo->mnt); -+ put_cred(sbinfo->creator_cred); -+ kfree(sbinfo); -+ } -+} -+ -+static const struct xattr_handler shiftfs_xattr_handler = { -+ .prefix = "", -+ .get = shiftfs_xattr_get, -+ .set = shiftfs_xattr_set, -+}; -+ -+const struct xattr_handler *shiftfs_xattr_handlers[] = { -+#ifdef CONFIG_SHIFT_FS_POSIX_ACL -+ &shiftfs_posix_acl_access_xattr_handler, -+ &shiftfs_posix_acl_default_xattr_handler, -+#endif -+ &shiftfs_xattr_handler, -+ NULL -+}; -+ -+static inline bool passthrough_is_subset(int old_flags, int new_flags) -+{ -+ if ((new_flags & old_flags) != new_flags) -+ return false; -+ -+ return true; -+} -+ -+static int shiftfs_super_check_flags(unsigned long old_flags, -+ unsigned long new_flags) -+{ -+ if ((old_flags & SB_RDONLY) && !(new_flags & SB_RDONLY)) -+ return -EPERM; -+ -+ if ((old_flags & SB_NOSUID) && !(new_flags & SB_NOSUID)) -+ return -EPERM; -+ -+ if ((old_flags & SB_NODEV) && !(new_flags & SB_NODEV)) -+ return -EPERM; -+ -+ if ((old_flags & SB_NOEXEC) && !(new_flags & SB_NOEXEC)) -+ return -EPERM; -+ -+ if ((old_flags & SB_NOATIME) && !(new_flags & SB_NOATIME)) -+ return -EPERM; -+ -+ if ((old_flags & SB_NODIRATIME) && !(new_flags & SB_NODIRATIME)) -+ return -EPERM; -+ -+ if (!(old_flags & SB_POSIXACL) && (new_flags & SB_POSIXACL)) -+ return -EPERM; -+ -+ return 0; -+} -+ -+static int shiftfs_remount(struct super_block *sb, int *flags, char *data) -+{ -+ int err; -+ struct shiftfs_super_info new = {}; -+ struct shiftfs_super_info *info = sb->s_fs_info; -+ -+ err = shiftfs_parse_mount_options(&new, data); -+ if (err) -+ return err; -+ -+ err = shiftfs_super_check_flags(sb->s_flags, *flags); -+ if (err) -+ return err; -+ -+ /* Mark mount option cannot be changed. */ -+ if (info->mark || (info->mark != new.mark)) -+ return -EPERM; -+ -+ if (info->passthrough != new.passthrough) { -+ /* Don't allow exceeding passthrough options of mark mount. */ -+ if (!passthrough_is_subset(info->passthrough_mark, -+ info->passthrough)) -+ return -EPERM; -+ -+ info->passthrough = new.passthrough; -+ } -+ -+ return 0; -+} -+ -+static const struct super_operations shiftfs_super_ops = { -+ .put_super = shiftfs_put_super, -+ .show_options = shiftfs_show_options, -+ .statfs = shiftfs_statfs, -+ .remount_fs = shiftfs_remount, -+ .evict_inode = shiftfs_evict_inode, -+}; -+ -+struct shiftfs_data { -+ void *data; -+ const char *path; -+}; -+ -+static void shiftfs_super_force_flags(struct super_block *sb, -+ unsigned long lower_flags) -+{ -+ sb->s_flags |= lower_flags & (SB_RDONLY | SB_NOSUID | SB_NODEV | -+ SB_NOEXEC | SB_NOATIME | SB_NODIRATIME); -+ -+ if (!(lower_flags & SB_POSIXACL)) -+ sb->s_flags &= ~SB_POSIXACL; -+} -+ -+static int shiftfs_fill_super(struct super_block *sb, void *raw_data, -+ int silent) -+{ -+ int err; -+ struct path path = {}; -+ struct shiftfs_super_info *sbinfo_mp; -+ char *name = NULL; -+ struct inode *inode = NULL; -+ struct dentry *dentry = NULL; -+ struct shiftfs_data *data = raw_data; -+ struct shiftfs_super_info *sbinfo = NULL; -+ -+ if (!data->path) -+ return -EINVAL; -+ -+ sb->s_fs_info = kzalloc(sizeof(*sbinfo), GFP_KERNEL); -+ if (!sb->s_fs_info) -+ return -ENOMEM; -+ sbinfo = sb->s_fs_info; -+ -+ err = shiftfs_parse_mount_options(sbinfo, data->data); -+ if (err) -+ return err; -+ -+ /* to mount a mark, must be userns admin */ -+ if (!sbinfo->mark && !ns_capable(current_user_ns(), CAP_SYS_ADMIN)) -+ return -EPERM; -+ -+ name = kstrdup(data->path, GFP_KERNEL); -+ if (!name) -+ return -ENOMEM; -+ -+ err = kern_path(name, LOOKUP_FOLLOW, &path); -+ if (err) -+ goto out_free_name; -+ -+ if (!S_ISDIR(path.dentry->d_inode->i_mode)) { -+ err = -ENOTDIR; -+ goto out_put_path; -+ } -+ -+ sb->s_flags |= SB_POSIXACL; -+ -+ if (sbinfo->mark) { -+ struct cred *cred_tmp; -+ struct super_block *lower_sb = path.mnt->mnt_sb; -+ -+ /* to mark a mount point, must root wrt lower s_user_ns */ -+ if (!ns_capable(lower_sb->s_user_ns, CAP_SYS_ADMIN)) { -+ err = -EPERM; -+ goto out_put_path; -+ } -+ -+ /* -+ * this part is visible unshifted, so make sure no -+ * executables that could be used to give suid -+ * privileges -+ */ -+ sb->s_iflags = SB_I_NOEXEC; -+ -+ shiftfs_super_force_flags(sb, lower_sb->s_flags); -+ -+ /* -+ * Handle nesting of shiftfs mounts by referring this mark -+ * mount back to the original mark mount. This is more -+ * efficient and alleviates concerns about stack depth. -+ */ -+ if (lower_sb->s_magic == SHIFTFS_MAGIC) { -+ sbinfo_mp = lower_sb->s_fs_info; -+ -+ /* Doesn't make sense to mark a mark mount */ -+ if (sbinfo_mp->mark) { -+ err = -EINVAL; -+ goto out_put_path; -+ } -+ -+ if (!passthrough_is_subset(sbinfo_mp->passthrough, -+ sbinfo->passthrough)) { -+ err = -EPERM; -+ goto out_put_path; -+ } -+ -+ sbinfo->mnt = mntget(sbinfo_mp->mnt); -+ dentry = dget(path.dentry->d_fsdata); -+ /* -+ * Copy up the passthrough mount options from the -+ * parent mark mountpoint. -+ */ -+ sbinfo->passthrough_mark = sbinfo_mp->passthrough_mark; -+ sbinfo->creator_cred = get_cred(sbinfo_mp->creator_cred); -+ } else { -+ sbinfo->mnt = mntget(path.mnt); -+ dentry = dget(path.dentry); -+ /* -+ * For a new mark passthrough_mark and passthrough -+ * are identical. -+ */ -+ sbinfo->passthrough_mark = sbinfo->passthrough; -+ -+ cred_tmp = prepare_creds(); -+ if (!cred_tmp) { -+ err = -ENOMEM; -+ goto out_put_path; -+ } -+ /* Don't override disk quota limits or use reserved space. */ -+ cap_lower(cred_tmp->cap_effective, CAP_SYS_RESOURCE); -+ sbinfo->creator_cred = cred_tmp; -+ } -+ } else { -+ /* -+ * This leg executes if we're admin capable in the namespace, -+ * so be very careful. -+ */ -+ err = -EPERM; -+ if (path.dentry->d_sb->s_magic != SHIFTFS_MAGIC) -+ goto out_put_path; -+ -+ sbinfo_mp = path.dentry->d_sb->s_fs_info; -+ if (!sbinfo_mp->mark) -+ goto out_put_path; -+ -+ if (!passthrough_is_subset(sbinfo_mp->passthrough, -+ sbinfo->passthrough)) -+ goto out_put_path; -+ -+ sbinfo->mnt = mntget(sbinfo_mp->mnt); -+ sbinfo->creator_cred = get_cred(sbinfo_mp->creator_cred); -+ dentry = dget(path.dentry->d_fsdata); -+ /* -+ * Copy up passthrough settings from mark mountpoint so we can -+ * verify when the overlay wants to remount with different -+ * passthrough settings. -+ */ -+ sbinfo->passthrough_mark = sbinfo_mp->passthrough; -+ shiftfs_super_force_flags(sb, path.mnt->mnt_sb->s_flags); -+ } -+ -+ sb->s_stack_depth = dentry->d_sb->s_stack_depth + 1; -+ if (sb->s_stack_depth > FILESYSTEM_MAX_STACK_DEPTH) { -+ printk(KERN_ERR "shiftfs: maximum stacking depth exceeded\n"); -+ err = -EINVAL; -+ goto out_put_path; -+ } -+ -+ inode = new_inode(sb); -+ if (!inode) { -+ err = -ENOMEM; -+ goto out_put_path; -+ } -+ shiftfs_fill_inode(inode, dentry->d_inode->i_ino, S_IFDIR, 0, dentry); -+ -+ ihold(dentry->d_inode); -+ inode->i_private = dentry->d_inode; -+ -+ sb->s_magic = SHIFTFS_MAGIC; -+ sb->s_maxbytes = MAX_LFS_FILESIZE; -+ sb->s_op = &shiftfs_super_ops; -+ sb->s_xattr = shiftfs_xattr_handlers; -+ sb->s_d_op = &shiftfs_dentry_ops; -+ sb->s_root = d_make_root(inode); -+ if (!sb->s_root) { -+ err = -ENOMEM; -+ goto out_put_path; -+ } -+ -+ sb->s_root->d_fsdata = dentry; -+ sbinfo->userns = get_user_ns(dentry->d_sb->s_user_ns); -+ shiftfs_copyattr(dentry->d_inode, sb->s_root->d_inode); -+ -+ dentry = NULL; -+ err = 0; -+ -+out_put_path: -+ path_put(&path); -+ -+out_free_name: -+ kfree(name); -+ -+ dput(dentry); -+ -+ return err; -+} -+ -+static struct dentry *shiftfs_mount(struct file_system_type *fs_type, -+ int flags, const char *dev_name, void *data) -+{ -+ struct shiftfs_data d = { data, dev_name }; -+ -+ return mount_nodev(fs_type, flags, &d, shiftfs_fill_super); -+} -+ -+static struct file_system_type shiftfs_type = { -+ .owner = THIS_MODULE, -+ .name = "shiftfs", -+ .mount = shiftfs_mount, -+ .kill_sb = kill_anon_super, -+ .fs_flags = FS_USERNS_MOUNT, -+}; -+ -+static int __init shiftfs_init(void) -+{ -+ return register_filesystem(&shiftfs_type); -+} -+ -+static void __exit shiftfs_exit(void) -+{ -+ unregister_filesystem(&shiftfs_type); -+} -+ -+MODULE_ALIAS_FS("shiftfs"); -+MODULE_AUTHOR("James Bottomley"); -+MODULE_AUTHOR("Seth Forshee <seth.forshee@canonical.com>"); -+MODULE_AUTHOR("Christian Brauner <christian.brauner@ubuntu.com>"); -+MODULE_DESCRIPTION("id shifting filesystem"); -+MODULE_LICENSE("GPL v2"); -+module_init(shiftfs_init) -+module_exit(shiftfs_exit) ---- a/include/uapi/linux/magic.h 2021-01-06 19:08:45.234777659 -0500 -+++ b/include/uapi/linux/magic.h 2021-01-06 19:09:53.900375394 -0500 -@@ -96,4 +96,6 @@ - #define DEVMEM_MAGIC 0x454d444d /* "DMEM" */ - #define Z3FOLD_MAGIC 0x33 - -+#define SHIFTFS_MAGIC 0x6a656a62 -+ - #endif /* __LINUX_MAGIC_H__ */ ---- a/fs/Makefile 2021-01-08 18:08:28.187064015 -0500 -+++ b/fs/Makefile 2021-01-08 18:09:00.788217579 -0500 -@@ -136,3 +136,4 @@ obj-$(CONFIG_EFIVAR_FS) += efivarfs/ - obj-$(CONFIG_EROFS_FS) += erofs/ - obj-$(CONFIG_VBOXSF_FS) += vboxsf/ - obj-$(CONFIG_ZONEFS_FS) += zonefs/ -+obj-$(CONFIG_SHIFT_FS) += shiftfs.o ---- a/fs/Kconfig 2021-01-06 19:14:17.709697891 -0500 -+++ b/fs/Kconfig 2021-01-06 19:15:23.413281282 -0500 -@@ -122,6 +122,24 @@ source "fs/autofs/Kconfig" - source "fs/fuse/Kconfig" - source "fs/overlayfs/Kconfig" - -+config SHIFT_FS -+ tristate "UID/GID shifting overlay filesystem for containers" -+ help -+ This filesystem can overlay any mounted filesystem and shift -+ the uid/gid the files appear at. The idea is that -+ unprivileged containers can use this to mount root volumes -+ using this technique. -+ -+config SHIFT_FS_POSIX_ACL -+ bool "shiftfs POSIX Access Control Lists" -+ depends on SHIFT_FS -+ select FS_POSIX_ACL -+ help -+ POSIX Access Control Lists (ACLs) support permissions for users and -+ groups beyond the owner/group/world scheme. -+ -+ If you don't know what Access Control Lists are, say N. -+ - menu "Caches" - - source "fs/fscache/Kconfig" diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0001-make-DEFAULT_MMAP_MIN_ADDR-match-LSM_MMAP_MIN_ADDR.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0001-make-DEFAULT_MMAP_MIN_ADDR-match-LSM_MMAP_MIN_ADDR.patch deleted file mode 100644 index f8f2122cb3cd..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0001-make-DEFAULT_MMAP_MIN_ADDR-match-LSM_MMAP_MIN_ADDR.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 30c2f2c6db2cf258ae0dd7fb30884f55bac154f1 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Sat, 27 May 2017 07:22:12 -0400 -Subject: [PATCH 001/113] make DEFAULT_MMAP_MIN_ADDR match LSM_MMAP_MIN_ADDR - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - mm/Kconfig | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/mm/Kconfig b/mm/Kconfig -index 390165ffbb0f..3b24c9e3535e 100644 ---- a/mm/Kconfig -+++ b/mm/Kconfig -@@ -321,7 +321,8 @@ config KSM - config DEFAULT_MMAP_MIN_ADDR - int "Low address space to protect from user allocation" - depends on MMU -- default 4096 -+ default 32768 if ARM || (ARM64 && COMPAT) -+ default 65536 - help - This is the portion of low virtual memory which should be protected - from userspace allocation. Keeping a user from writing to low pages --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0002-enable-HARDENED_USERCOPY-by-default.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0002-enable-HARDENED_USERCOPY-by-default.patch deleted file mode 100644 index 9f78840ae492..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0002-enable-HARDENED_USERCOPY-by-default.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 437cb2ad97254b24e60ba133808b7cae0fe6b298 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Mon, 29 May 2017 06:17:41 -0400 -Subject: [PATCH 002/113] enable HARDENED_USERCOPY by default - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - security/Kconfig | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/security/Kconfig b/security/Kconfig -index 7561f6f99f1d..9446ddf40974 100644 ---- a/security/Kconfig -+++ b/security/Kconfig -@@ -154,6 +154,7 @@ config HARDENED_USERCOPY - bool "Harden memory copies between kernel and userspace" - depends on HAVE_HARDENED_USERCOPY_ALLOCATOR - imply STRICT_DEVMEM -+ default y - help - This option checks for obviously wrong memory regions when - copying memory to/from the kernel (via copy_to_user() and --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0003-disable-HARDENED_USERCOPY_FALLBACK-by-default.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0003-disable-HARDENED_USERCOPY_FALLBACK-by-default.patch deleted file mode 100644 index 024742c47f89..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0003-disable-HARDENED_USERCOPY_FALLBACK-by-default.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 0857d86274507a026ccd8910d307b2e4874b14ac Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Thu, 26 Apr 2018 02:01:26 -0400 -Subject: [PATCH 003/113] disable HARDENED_USERCOPY_FALLBACK by default - ---- - security/Kconfig | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/security/Kconfig b/security/Kconfig -index 9446ddf40974..5c388f7fe09d 100644 ---- a/security/Kconfig -+++ b/security/Kconfig -@@ -167,7 +167,6 @@ config HARDENED_USERCOPY - config HARDENED_USERCOPY_FALLBACK - bool "Allow usercopy whitelist violations to fallback to object size" - depends on HARDENED_USERCOPY -- default y - help - This is a temporary option that allows missing usercopy whitelists - to be discovered via a WARN() to the kernel log, instead of --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0004-enable-SECURITY_DMESG_RESTRICT-by-default.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0004-enable-SECURITY_DMESG_RESTRICT-by-default.patch deleted file mode 100644 index 12711244396e..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0004-enable-SECURITY_DMESG_RESTRICT-by-default.patch +++ /dev/null @@ -1,26 +0,0 @@ -From a9943395a6697f68e4f77f622f0325fb3b447d67 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Wed, 3 May 2017 12:05:15 -0400 -Subject: [PATCH 004/113] enable SECURITY_DMESG_RESTRICT by default - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - security/Kconfig | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/security/Kconfig b/security/Kconfig -index 5c388f7fe09d..428ad7622370 100644 ---- a/security/Kconfig -+++ b/security/Kconfig -@@ -9,7 +9,7 @@ source "security/keys/Kconfig" - - config SECURITY_DMESG_RESTRICT - bool "Restrict unprivileged access to the kernel syslog" -- default n -+ default y - help - This enforces restrictions on unprivileged users reading the kernel - syslog via dmesg(8). --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0005-set-kptr_restrict-2-by-default.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0005-set-kptr_restrict-2-by-default.patch deleted file mode 100644 index b7ec66b45535..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0005-set-kptr_restrict-2-by-default.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 0455b0e44f264e2151355933b2207155573d8ca9 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Wed, 3 May 2017 12:06:14 -0400 -Subject: [PATCH 005/113] set kptr_restrict=2 by default - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - lib/vsprintf.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/lib/vsprintf.c b/lib/vsprintf.c -index 14c9a6af1b23..2501f75bd74d 100644 ---- a/lib/vsprintf.c -+++ b/lib/vsprintf.c -@@ -821,7 +821,7 @@ static char *ptr_to_id(char *buf, char *end, const void *ptr, - return pointer_string(buf, end, (const void *)hashval, spec); - } - --int kptr_restrict __read_mostly; -+int kptr_restrict __read_mostly = 2; - - static noinline_for_stack - char *restricted_pointer(char *buf, char *end, const void *ptr, --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0006-enable-DEBUG_LIST-by-default.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0006-enable-DEBUG_LIST-by-default.patch deleted file mode 100644 index 09889dd0d500..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0006-enable-DEBUG_LIST-by-default.patch +++ /dev/null @@ -1,25 +0,0 @@ -From e2559a54cae54f9df791118b3134fa9ec5a0fc41 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Wed, 3 May 2017 12:10:57 -0400 -Subject: [PATCH 006/113] enable DEBUG_LIST by default - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - lib/Kconfig.debug | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug -index c789b39ed527..89c9d6aebf77 100644 ---- a/lib/Kconfig.debug -+++ b/lib/Kconfig.debug -@@ -1471,6 +1471,7 @@ menu "Debug kernel data structures" - config DEBUG_LIST - bool "Debug linked list manipulation" - depends on DEBUG_KERNEL || BUG_ON_DATA_CORRUPTION -+ default y - help - Enable this to turn on extended checks in the linked-list - walking routines. --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0007-enable-BUG_ON_DATA_CORRUPTION-by-default.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0007-enable-BUG_ON_DATA_CORRUPTION-by-default.patch deleted file mode 100644 index 63c45608206d..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0007-enable-BUG_ON_DATA_CORRUPTION-by-default.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 3699b64980b7d8779c2b72fe906e89a9e3411211 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Mon, 29 May 2017 12:21:21 -0400 -Subject: [PATCH 007/113] enable BUG_ON_DATA_CORRUPTION by default - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - lib/Kconfig.debug | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug -index 89c9d6aebf77..11068e77d146 100644 ---- a/lib/Kconfig.debug -+++ b/lib/Kconfig.debug -@@ -1511,6 +1511,7 @@ config DEBUG_NOTIFIERS - config BUG_ON_DATA_CORRUPTION - bool "Trigger a BUG when data corruption is detected" - select DEBUG_LIST -+ default y - help - Select this option if the kernel should BUG when it encounters - data corruption in kernel memory structures when they get checked --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0008-enable-ARM64_SW_TTBR0_PAN-by-default.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0008-enable-ARM64_SW_TTBR0_PAN-by-default.patch deleted file mode 100644 index 8d956207b61f..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0008-enable-ARM64_SW_TTBR0_PAN-by-default.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 1f7bedc814d9bec78d93858a91a1c41c72fb5d9b Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Sun, 25 Feb 2018 01:39:32 -0500 -Subject: [PATCH 008/113] enable ARM64_SW_TTBR0_PAN by default - ---- - arch/arm64/Kconfig | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig -index a6b5b7ef40ae..a145245ec5e7 100644 ---- a/arch/arm64/Kconfig -+++ b/arch/arm64/Kconfig -@@ -1199,6 +1199,7 @@ config RODATA_FULL_DEFAULT_ENABLED - - config ARM64_SW_TTBR0_PAN - bool "Emulate Privileged Access Never using TTBR0_EL1 switching" -+ default y - help - Enabling this option prevents the kernel from accessing - user-space memory directly by pointing TTBR0_EL1 to a reserved --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0009-arm64-enable-RANDOMIZE_BASE-by-default.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0009-arm64-enable-RANDOMIZE_BASE-by-default.patch deleted file mode 100644 index 6d04cc08d09e..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0009-arm64-enable-RANDOMIZE_BASE-by-default.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 0a215fddffc20c8f2aa776111937c4d690fe14f8 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Sun, 25 Feb 2018 01:33:48 -0500 -Subject: [PATCH 009/113] arm64: enable RANDOMIZE_BASE by default - ---- - arch/arm64/Kconfig | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig -index a145245ec5e7..21088a6532d8 100644 ---- a/arch/arm64/Kconfig -+++ b/arch/arm64/Kconfig -@@ -1790,6 +1790,7 @@ config RANDOMIZE_BASE - bool "Randomize the address of the kernel image" - select ARM64_MODULE_PLTS if MODULES - select RELOCATABLE -+ default y - help - Randomizes the virtual address at which the kernel image is - loaded, as a security feature that deters exploit attempts --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0010-enable-SLAB_FREELIST_RANDOM-by-default.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0010-enable-SLAB_FREELIST_RANDOM-by-default.patch deleted file mode 100644 index 53cdf0f3ba22..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0010-enable-SLAB_FREELIST_RANDOM-by-default.patch +++ /dev/null @@ -1,25 +0,0 @@ -From ccd7ee1cce3fc4f9fa54520f3adbbf47a4fcad27 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Wed, 3 May 2017 19:43:38 -0400 -Subject: [PATCH 010/113] enable SLAB_FREELIST_RANDOM by default - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - init/Kconfig | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/init/Kconfig b/init/Kconfig -index 0872a5a2e759..dcbcb4243316 100644 ---- a/init/Kconfig -+++ b/init/Kconfig -@@ -1929,6 +1929,7 @@ config SLAB_MERGE_DEFAULT - config SLAB_FREELIST_RANDOM - bool "Randomize slab freelist" - depends on SLAB || SLUB -+ default y - help - Randomizes the freelist order used on creating new pages. This - security feature reduces the predictability of the kernel slab --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0011-enable-SLAB_FREELIST_HARDENED-by-default.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0011-enable-SLAB_FREELIST_HARDENED-by-default.patch deleted file mode 100644 index 2664e4fe0cac..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0011-enable-SLAB_FREELIST_HARDENED-by-default.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 3bdf61f4fd15f83c6c68ec80a1075cc97fcc27a7 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Sun, 20 Aug 2017 15:39:25 -0400 -Subject: [PATCH 011/113] enable SLAB_FREELIST_HARDENED by default - ---- - init/Kconfig | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/init/Kconfig b/init/Kconfig -index dcbcb4243316..667d1c6c021b 100644 ---- a/init/Kconfig -+++ b/init/Kconfig -@@ -1938,6 +1938,7 @@ config SLAB_FREELIST_RANDOM - config SLAB_FREELIST_HARDENED - bool "Harden slab freelist metadata" - depends on SLAB || SLUB -+ default y - help - Many kernel heap attacks try to target slab cache metadata and - other infrastructure. This options makes minor performance --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0012-disable-SLAB_MERGE_DEFAULT-by-default.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0012-disable-SLAB_MERGE_DEFAULT-by-default.patch deleted file mode 100644 index a318069e51d3..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0012-disable-SLAB_MERGE_DEFAULT-by-default.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 0b6f9a21063ad87550e8ad3c585bfc2af8ac1d49 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Sat, 8 Jul 2017 02:38:54 -0400 -Subject: [PATCH 012/113] disable SLAB_MERGE_DEFAULT by default - ---- - init/Kconfig | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/init/Kconfig b/init/Kconfig -index 667d1c6c021b..859ab5ae66ff 100644 ---- a/init/Kconfig -+++ b/init/Kconfig -@@ -1914,7 +1914,6 @@ endchoice - - config SLAB_MERGE_DEFAULT - bool "Allow slab caches to be merged" -- default y - help - For reduced kernel memory fragmentation, slab caches can be - merged when they share the same size and other characteristics. --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0013-enable-FORTIFY_SOURCE-by-default.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0013-enable-FORTIFY_SOURCE-by-default.patch deleted file mode 100644 index 9637a356b0c6..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0013-enable-FORTIFY_SOURCE-by-default.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 877645788ff6bb326cb8f90aedf431fac367c92f Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Mon, 8 May 2017 12:51:54 -0400 -Subject: [PATCH 013/113] enable FORTIFY_SOURCE by default - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - security/Kconfig | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/security/Kconfig b/security/Kconfig -index 428ad7622370..3a2c68c7b50f 100644 ---- a/security/Kconfig -+++ b/security/Kconfig -@@ -191,6 +191,7 @@ config HARDENED_USERCOPY_PAGESPAN - config FORTIFY_SOURCE - bool "Harden common str/mem functions against buffer overflows" - depends on ARCH_HAS_FORTIFY_SOURCE -+ default y - help - Detect overflows of buffers in common string and memory functions - where the compiler can determine and validate the buffer sizes. --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0014-enable-PANIC_ON_OOPS-by-default.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0014-enable-PANIC_ON_OOPS-by-default.patch deleted file mode 100644 index 752187981ff1..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0014-enable-PANIC_ON_OOPS-by-default.patch +++ /dev/null @@ -1,34 +0,0 @@ -From f56cae64efe0e211d99aea8175098433e1fa2ee9 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Wed, 3 May 2017 12:09:17 -0400 -Subject: [PATCH 014/113] enable PANIC_ON_OOPS by default - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - lib/Kconfig.debug | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug -index 11068e77d146..45b169177fb9 100644 ---- a/lib/Kconfig.debug -+++ b/lib/Kconfig.debug -@@ -894,6 +894,7 @@ menu "Debug Oops, Lockups and Hangs" - - config PANIC_ON_OOPS - bool "Panic on Oops" -+ default y - help - Say Y here to enable the kernel to panic when it oopses. This - has the same effect as setting oops=panic on the kernel command -@@ -903,7 +904,7 @@ config PANIC_ON_OOPS - anything erroneous after an oops which could result in data - corruption or other issues. - -- Say N if unsure. -+ Say Y if unsure. - - config PANIC_ON_OOPS_VALUE - int --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0015-stop-hiding-SLUB_DEBUG-behind-EXPERT.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0015-stop-hiding-SLUB_DEBUG-behind-EXPERT.patch deleted file mode 100644 index 6e2c2fd764ab..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0015-stop-hiding-SLUB_DEBUG-behind-EXPERT.patch +++ /dev/null @@ -1,26 +0,0 @@ -From aac553a70c3506a97cb33821e5b15fbf5fba3158 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Sun, 14 May 2017 22:39:34 -0400 -Subject: [PATCH 015/113] stop hiding SLUB_DEBUG behind EXPERT - -It can make sense to disable this to reduce attack surface / complexity. ---- - init/Kconfig | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/init/Kconfig b/init/Kconfig -index 859ab5ae66ff..74680a15ceb4 100644 ---- a/init/Kconfig -+++ b/init/Kconfig -@@ -1843,7 +1843,7 @@ config VM_EVENT_COUNTERS - - config SLUB_DEBUG - default y -- bool "Enable SLUB debugging support" if EXPERT -+ bool "Enable SLUB debugging support" - depends on SLUB && SYSFS - help - SLUB has extensive debug support features. Disabling these can --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0016-stop-hiding-X86_16BIT-behind-EXPERT.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0016-stop-hiding-X86_16BIT-behind-EXPERT.patch deleted file mode 100644 index 49895dc51e47..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0016-stop-hiding-X86_16BIT-behind-EXPERT.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 6bec6634466c70d12acaddacd5e1023684dbb3c0 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Thu, 4 May 2017 18:11:31 -0400 -Subject: [PATCH 016/113] stop hiding X86_16BIT behind EXPERT - ---- - arch/x86/Kconfig | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig -index 3a5ecb1039bf..d2d5e0cbf85c 100644 ---- a/arch/x86/Kconfig -+++ b/arch/x86/Kconfig -@@ -1194,7 +1194,7 @@ config VM86 - default X86_LEGACY_VM86 - - config X86_16BIT -- bool "Enable support for 16-bit segments" if EXPERT -+ bool "Enable support for 16-bit segments" - default y - depends on MODIFY_LDT_SYSCALL - help --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0017-disable-X86_16BIT-by-default.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0017-disable-X86_16BIT-by-default.patch deleted file mode 100644 index 47e1a1e829c8..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0017-disable-X86_16BIT-by-default.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 2820aa8f5dc49f6b52dd3913fd873d0256543f20 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Thu, 4 May 2017 18:11:52 -0400 -Subject: [PATCH 017/113] disable X86_16BIT by default - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - arch/x86/Kconfig | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig -index d2d5e0cbf85c..ab6e7e2d3cf0 100644 ---- a/arch/x86/Kconfig -+++ b/arch/x86/Kconfig -@@ -1195,7 +1195,6 @@ config VM86 - - config X86_16BIT - bool "Enable support for 16-bit segments" -- default y - depends on MODIFY_LDT_SYSCALL - help - This option is required by programs like Wine to run 16-bit --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0018-stop-hiding-MODIFY_LDT_SYSCALL-behind-EXPERT.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0018-stop-hiding-MODIFY_LDT_SYSCALL-behind-EXPERT.patch deleted file mode 100644 index a72e45a811cc..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0018-stop-hiding-MODIFY_LDT_SYSCALL-behind-EXPERT.patch +++ /dev/null @@ -1,25 +0,0 @@ -From ca5dce9c47de65f90b9b826e7514a37ce23f9a42 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Thu, 4 May 2017 18:15:52 -0400 -Subject: [PATCH 018/113] stop hiding MODIFY_LDT_SYSCALL behind EXPERT - ---- - arch/x86/Kconfig | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig -index ab6e7e2d3cf0..7b9df510469b 100644 ---- a/arch/x86/Kconfig -+++ b/arch/x86/Kconfig -@@ -2392,7 +2392,7 @@ config CMDLINE_OVERRIDE - be set to 'N' under normal conditions. - - config MODIFY_LDT_SYSCALL -- bool "Enable the LDT (local descriptor table)" if EXPERT -+ bool "Enable the LDT (local descriptor table)" - default y - help - Linux can allow user programs to install a per-process x86 --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0019-disable-MODIFY_LDT_SYSCALL-by-default.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0019-disable-MODIFY_LDT_SYSCALL-by-default.patch deleted file mode 100644 index 178e0a193c3e..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0019-disable-MODIFY_LDT_SYSCALL-by-default.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 9c1be96e8fbf27df4ce830b2e270b231870d38fb Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Thu, 4 May 2017 18:16:16 -0400 -Subject: [PATCH 019/113] disable MODIFY_LDT_SYSCALL by default - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> -Signed-off-by: Levente Polyak <levente@leventepolyak.net> ---- - arch/x86/Kconfig | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig -index 7b9df510469b..63e1e9fc18dd 100644 ---- a/arch/x86/Kconfig -+++ b/arch/x86/Kconfig -@@ -2393,7 +2393,6 @@ config CMDLINE_OVERRIDE - - config MODIFY_LDT_SYSCALL - bool "Enable the LDT (local descriptor table)" -- default y - help - Linux can allow user programs to install a per-process x86 - Local Descriptor Table (LDT) using the modify_ldt(2) system --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0020-set-LEGACY_VSYSCALL_NONE-by-default.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0020-set-LEGACY_VSYSCALL_NONE-by-default.patch deleted file mode 100644 index 732f786b952b..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0020-set-LEGACY_VSYSCALL_NONE-by-default.patch +++ /dev/null @@ -1,25 +0,0 @@ -From df005ca65f037830f2ccc1f85cd03172e4f122cb Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Mon, 29 May 2017 07:08:42 -0400 -Subject: [PATCH 020/113] set LEGACY_VSYSCALL_NONE by default - ---- - arch/x86/Kconfig | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig -index 63e1e9fc18dd..4fd082de7420 100644 ---- a/arch/x86/Kconfig -+++ b/arch/x86/Kconfig -@@ -2296,7 +2296,7 @@ config COMPAT_VDSO - choice - prompt "vsyscall table for legacy applications" - depends on X86_64 -- default LEGACY_VSYSCALL_XONLY -+ default LEGACY_VSYSCALL_NONE - help - Legacy user code that does not know how to find the vDSO expects - to be able to issue three syscalls by calling fixed addresses in --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0021-stop-hiding-AIO-behind-EXPERT.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0021-stop-hiding-AIO-behind-EXPERT.patch deleted file mode 100644 index bb40a91fc527..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0021-stop-hiding-AIO-behind-EXPERT.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 99991cae01d880237386a0947862557fb4bd5eba Mon Sep 17 00:00:00 2001 -From: Bernhard40 <32568352+Bernhard40@users.noreply.github.com> -Date: Fri, 6 Oct 2017 10:21:50 +0000 -Subject: [PATCH 021/113] stop hiding AIO behind EXPERT - ---- - init/Kconfig | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/init/Kconfig b/init/Kconfig -index 74680a15ceb4..8605f3e78e47 100644 ---- a/init/Kconfig -+++ b/init/Kconfig -@@ -1591,7 +1591,7 @@ config SHMEM - which may be appropriate on small systems without swap. - - config AIO -- bool "Enable AIO support" if EXPERT -+ bool "Enable AIO support" - default y - help - This option enables POSIX asynchronous I/O which may by used --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0022-disable-AIO-by-default.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0022-disable-AIO-by-default.patch deleted file mode 100644 index fc9abea42075..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0022-disable-AIO-by-default.patch +++ /dev/null @@ -1,24 +0,0 @@ -From c3899f4ac55a90679c7b1e1175edd30a3dbf077c Mon Sep 17 00:00:00 2001 -From: Bernhard40 <32568352+Bernhard40@users.noreply.github.com> -Date: Fri, 6 Oct 2017 10:24:10 +0000 -Subject: [PATCH 022/113] disable AIO by default - ---- - init/Kconfig | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/init/Kconfig b/init/Kconfig -index 8605f3e78e47..21f0b6926cf3 100644 ---- a/init/Kconfig -+++ b/init/Kconfig -@@ -1592,7 +1592,6 @@ config SHMEM - - config AIO - bool "Enable AIO support" -- default y - help - This option enables POSIX asynchronous I/O which may by used - by some high performance threaded applications. Disabling --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0023-remove-SYSVIPC-from-arm64-x86_64-defconfigs.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0023-remove-SYSVIPC-from-arm64-x86_64-defconfigs.patch deleted file mode 100644 index 928b654e89f3..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0023-remove-SYSVIPC-from-arm64-x86_64-defconfigs.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 693f07d2bccfff30ec58776bfe988a37a36037b6 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Sun, 25 Feb 2018 02:08:49 -0500 -Subject: [PATCH 023/113] remove SYSVIPC from arm64/x86_64 defconfigs - ---- - arch/arm64/configs/defconfig | 1 - - arch/x86/configs/x86_64_defconfig | 1 - - 2 files changed, 2 deletions(-) - -diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig -index 5cfe3cf6f2ac..f25871361bdc 100644 ---- a/arch/arm64/configs/defconfig -+++ b/arch/arm64/configs/defconfig -@@ -1,4 +1,3 @@ --CONFIG_SYSVIPC=y - CONFIG_POSIX_MQUEUE=y - CONFIG_AUDIT=y - CONFIG_NO_HZ_IDLE=y -diff --git a/arch/x86/configs/x86_64_defconfig b/arch/x86/configs/x86_64_defconfig -index 9936528e1939..981ee8c0e330 100644 ---- a/arch/x86/configs/x86_64_defconfig -+++ b/arch/x86/configs/x86_64_defconfig -@@ -1,5 +1,4 @@ - # CONFIG_LOCALVERSION_AUTO is not set --CONFIG_SYSVIPC=y - CONFIG_POSIX_MQUEUE=y - CONFIG_AUDIT=y - CONFIG_NO_HZ=y --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0024-disable-DEVPORT-by-default.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0024-disable-DEVPORT-by-default.patch deleted file mode 100644 index ef7ce5bb4558..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0024-disable-DEVPORT-by-default.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 366eacb7f45ab0cd377af20025eae1ca418c76f5 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Sat, 27 May 2017 07:28:10 -0400 -Subject: [PATCH 024/113] disable DEVPORT by default - ---- - drivers/char/Kconfig | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig -index d229a2d0c017..68178c3a25de 100644 ---- a/drivers/char/Kconfig -+++ b/drivers/char/Kconfig -@@ -391,7 +391,6 @@ config MAX_RAW_DEVS - config DEVPORT - bool "/dev/port character device" - depends on ISA || PCI -- default y - help - Say Y here if you want to support the /dev/port device. The /dev/port - device is similar to /dev/mem, but for I/O ports. --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0025-disable-PROC_VMCORE-by-default.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0025-disable-PROC_VMCORE-by-default.patch deleted file mode 100644 index af9e7d9115ff..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0025-disable-PROC_VMCORE-by-default.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 470f9d68246af103dc79d3f804eccf2114326c52 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Sat, 27 May 2017 07:29:45 -0400 -Subject: [PATCH 025/113] disable PROC_VMCORE by default - ---- - fs/proc/Kconfig | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/fs/proc/Kconfig b/fs/proc/Kconfig -index c930001056f9..6a0a51b3f593 100644 ---- a/fs/proc/Kconfig -+++ b/fs/proc/Kconfig -@@ -41,7 +41,6 @@ config PROC_KCORE - config PROC_VMCORE - bool "/proc/vmcore support" - depends on PROC_FS && CRASH_DUMP -- default y - help - Exports the dump image of crashed kernel in ELF format. - --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0026-disable-NFS_DEBUG-by-default.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0026-disable-NFS_DEBUG-by-default.patch deleted file mode 100644 index 9cb6bc268713..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0026-disable-NFS_DEBUG-by-default.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 64dc800cbfe0c7dde04e471807e80140d1989ef6 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Sun, 28 May 2017 03:03:46 -0400 -Subject: [PATCH 026/113] disable NFS_DEBUG by default - ---- - fs/nfs/Kconfig | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig -index e2a488d403a6..ce54c1c693a8 100644 ---- a/fs/nfs/Kconfig -+++ b/fs/nfs/Kconfig -@@ -195,7 +195,6 @@ config NFS_DEBUG - bool - depends on NFS_FS && SUNRPC_DEBUG - select CRC32 -- default y - - config NFS_DISABLE_UDP_SUPPORT - bool "NFS: Disable NFS UDP protocol support" --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0027-enable-DEBUG_WX-by-default.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0027-enable-DEBUG_WX-by-default.patch deleted file mode 100644 index 417e81fc7833..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0027-enable-DEBUG_WX-by-default.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 839523af4d580520035120f486271943234a7503 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Mon, 29 May 2017 12:11:11 -0400 -Subject: [PATCH 027/113] enable DEBUG_WX by default - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - mm/Kconfig.debug | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/mm/Kconfig.debug b/mm/Kconfig.debug -index 864f129f1937..929d585bd267 100644 ---- a/mm/Kconfig.debug -+++ b/mm/Kconfig.debug -@@ -126,6 +126,7 @@ config DEBUG_WX - depends on ARCH_HAS_DEBUG_WX - depends on MMU - select PTDUMP_CORE -+ default y - help - Generate a warning if any W+X mappings are found at boot. - --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0028-disable-LEGACY_PTYS-by-default.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0028-disable-LEGACY_PTYS-by-default.patch deleted file mode 100644 index 83b44562583e..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0028-disable-LEGACY_PTYS-by-default.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 3b75ae9d5a52b590f4e4538b54605e260ce36569 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Fri, 5 Jan 2018 13:21:16 -0500 -Subject: [PATCH 028/113] disable LEGACY_PTYS by default - ---- - drivers/tty/Kconfig | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/drivers/tty/Kconfig b/drivers/tty/Kconfig -index 93fd984eb2f5..d9086484d2de 100644 ---- a/drivers/tty/Kconfig -+++ b/drivers/tty/Kconfig -@@ -122,7 +122,6 @@ config UNIX98_PTYS - - config LEGACY_PTYS - bool "Legacy (BSD) PTY support" -- default y - help - A pseudo terminal (PTY) is a software device consisting of two - halves: a master and a slave. The slave device behaves identical to --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0029-disable-DEVMEM-by-default.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0029-disable-DEVMEM-by-default.patch deleted file mode 100644 index d5fff73b8eb0..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0029-disable-DEVMEM-by-default.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 9c70639fa73518a3cd963b8c97f067712b3eaac4 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Fri, 5 Jan 2018 12:41:42 -0500 -Subject: [PATCH 029/113] disable DEVMEM by default - ---- - drivers/char/Kconfig | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig -index 68178c3a25de..2fd45f01e7a2 100644 ---- a/drivers/char/Kconfig -+++ b/drivers/char/Kconfig -@@ -327,7 +327,6 @@ config NSC_GPIO - - config DEVMEM - bool "/dev/mem virtual device support" -- default y - help - Say Y here if you want to support the /dev/mem device. - The /dev/mem device is used to access areas of physical --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0030-enable-IO_STRICT_DEVMEM-by-default.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0030-enable-IO_STRICT_DEVMEM-by-default.patch deleted file mode 100644 index f21c4186740c..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0030-enable-IO_STRICT_DEVMEM-by-default.patch +++ /dev/null @@ -1,24 +0,0 @@ -From f713dfa97e016d7210b7eeb735e06bb3f3b2deb4 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Fri, 5 Jan 2018 12:43:49 -0500 -Subject: [PATCH 030/113] enable IO_STRICT_DEVMEM by default - ---- - lib/Kconfig.debug | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug -index 45b169177fb9..a46f21a56125 100644 ---- a/lib/Kconfig.debug -+++ b/lib/Kconfig.debug -@@ -1668,6 +1668,7 @@ config STRICT_DEVMEM - config IO_STRICT_DEVMEM - bool "Filter I/O access to /dev/mem" - depends on STRICT_DEVMEM -+ default y - help - If this option is disabled, you allow userspace (root) access to all - io-memory regardless of whether a driver is actively using that --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0031-disable-COMPAT_BRK-by-default.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0031-disable-COMPAT_BRK-by-default.patch deleted file mode 100644 index f91a762cabef..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0031-disable-COMPAT_BRK-by-default.patch +++ /dev/null @@ -1,24 +0,0 @@ -From a98740f42e35ebe09a9de4cc15ac9aa536e4267d Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Sun, 7 May 2017 18:28:33 -0400 -Subject: [PATCH 031/113] disable COMPAT_BRK by default - ---- - init/Kconfig | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/init/Kconfig b/init/Kconfig -index 21f0b6926cf3..4f5827e10be3 100644 ---- a/init/Kconfig -+++ b/init/Kconfig -@@ -1866,7 +1866,6 @@ config SLUB_MEMCG_SYSFS_ON - - config COMPAT_BRK - bool "Disable heap randomization" -- default y - help - Randomizing heap placement makes heap exploits harder, but it - also breaks ancient binaries (including anything libc5 based). --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0032-use-maximum-supported-mmap-rnd-entropy-by-default.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0032-use-maximum-supported-mmap-rnd-entropy-by-default.patch deleted file mode 100644 index fd00e53e7383..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0032-use-maximum-supported-mmap-rnd-entropy-by-default.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 839e25dfcaf76cfef8915ed945c40a5c4ce5eea2 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Sun, 7 May 2017 16:16:39 -0400 -Subject: [PATCH 032/113] use maximum supported mmap rnd entropy by default - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - arch/Kconfig | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/arch/Kconfig b/arch/Kconfig -index 69fe7133c765..8b5c346d5dd8 100644 ---- a/arch/Kconfig -+++ b/arch/Kconfig -@@ -752,7 +752,7 @@ config ARCH_MMAP_RND_BITS - int "Number of bits to use for ASLR of mmap base address" if EXPERT - range ARCH_MMAP_RND_BITS_MIN ARCH_MMAP_RND_BITS_MAX - default ARCH_MMAP_RND_BITS_DEFAULT if ARCH_MMAP_RND_BITS_DEFAULT -- default ARCH_MMAP_RND_BITS_MIN -+ default ARCH_MMAP_RND_BITS_MAX - depends on HAVE_ARCH_MMAP_RND_BITS - help - This value can be used to select the number of bits to use to -@@ -786,7 +786,7 @@ config ARCH_MMAP_RND_COMPAT_BITS - int "Number of bits to use for ASLR of mmap base address for compatible applications" if EXPERT - range ARCH_MMAP_RND_COMPAT_BITS_MIN ARCH_MMAP_RND_COMPAT_BITS_MAX - default ARCH_MMAP_RND_COMPAT_BITS_DEFAULT if ARCH_MMAP_RND_COMPAT_BITS_DEFAULT -- default ARCH_MMAP_RND_COMPAT_BITS_MIN -+ default ARCH_MMAP_RND_COMPAT_BITS_MAX - depends on HAVE_ARCH_MMAP_RND_COMPAT_BITS - help - This value can be used to select the number of bits to use to --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0033-enable-protected_-symlinks-hardlinks-by-default.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0033-enable-protected_-symlinks-hardlinks-by-default.patch deleted file mode 100644 index f2b9d2b30907..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0033-enable-protected_-symlinks-hardlinks-by-default.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 2ecda519277297017ca2e87e49e78f1edbbdca2a Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Tue, 30 May 2017 10:47:23 -0400 -Subject: [PATCH 033/113] enable protected_{symlinks,hardlinks} by default - ---- - fs/namei.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/fs/namei.c b/fs/namei.c -index d4a6dd772303..59ff3ce21026 100644 ---- a/fs/namei.c -+++ b/fs/namei.c -@@ -932,8 +932,8 @@ static inline void put_link(struct nameidata *nd) - path_put(&last->link); - } - --int sysctl_protected_symlinks __read_mostly = 0; --int sysctl_protected_hardlinks __read_mostly = 0; -+int sysctl_protected_symlinks __read_mostly = 1; -+int sysctl_protected_hardlinks __read_mostly = 1; - int sysctl_protected_fifos __read_mostly; - int sysctl_protected_regular __read_mostly; - --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0034-enable-SECURITY-by-default.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0034-enable-SECURITY-by-default.patch deleted file mode 100644 index 435d798bd297..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0034-enable-SECURITY-by-default.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 0d8729414a95cc7297ac6097a4bcaece22697226 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Sun, 25 Feb 2018 02:13:48 -0500 -Subject: [PATCH 034/113] enable SECURITY by default - ---- - security/Kconfig | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/security/Kconfig b/security/Kconfig -index 3a2c68c7b50f..fa037a250821 100644 ---- a/security/Kconfig -+++ b/security/Kconfig -@@ -23,6 +23,7 @@ config SECURITY - bool "Enable different security models" - depends on SYSFS - depends on MULTIUSER -+ default y - help - This allows you to choose different security modules to be - configured into your kernel. --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0035-enable-SECURITY_YAMA-by-default.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0035-enable-SECURITY_YAMA-by-default.patch deleted file mode 100644 index ff50b48426b1..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0035-enable-SECURITY_YAMA-by-default.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 73c695d1e1bfb621be54428c1affd07e93cd46fa Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Mon, 29 May 2017 06:17:59 -0400 -Subject: [PATCH 035/113] enable SECURITY_YAMA by default - ---- - security/yama/Kconfig | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/security/yama/Kconfig b/security/yama/Kconfig -index a810304123ca..b809050b25d2 100644 ---- a/security/yama/Kconfig -+++ b/security/yama/Kconfig -@@ -2,7 +2,7 @@ - config SECURITY_YAMA - bool "Yama support" - depends on SECURITY -- default n -+ default y - help - This selects Yama, which extends DAC support with additional - system-wide security settings beyond regular Linux discretionary --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0036-enable-SECURITY_NETWORK-by-default.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0036-enable-SECURITY_NETWORK-by-default.patch deleted file mode 100644 index 022ffff944e3..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0036-enable-SECURITY_NETWORK-by-default.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 2974a5ecf4226a6f0e1e3e342631a655a8ddb70e Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Sun, 25 Feb 2018 02:14:02 -0500 -Subject: [PATCH 036/113] enable SECURITY_NETWORK by default - ---- - security/Kconfig | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/security/Kconfig b/security/Kconfig -index fa037a250821..81d0a08736aa 100644 ---- a/security/Kconfig -+++ b/security/Kconfig -@@ -49,6 +49,7 @@ config SECURITYFS - config SECURITY_NETWORK - bool "Socket and Networking Security Hooks" - depends on SECURITY -+ default y - help - This enables the socket and networking security hooks. - If enabled, a security module can use these hooks to --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0037-enable-AUDIT-by-default.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0037-enable-AUDIT-by-default.patch deleted file mode 100644 index 9f76b64138ea..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0037-enable-AUDIT-by-default.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 89109cfb13f3f0afb69c8c1eb709e54b2d193165 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Sun, 25 Feb 2018 02:15:24 -0500 -Subject: [PATCH 037/113] enable AUDIT by default - ---- - init/Kconfig | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/init/Kconfig b/init/Kconfig -index 4f5827e10be3..9b75a4921575 100644 ---- a/init/Kconfig -+++ b/init/Kconfig -@@ -419,6 +419,7 @@ config USELIB - config AUDIT - bool "Auditing support" - depends on NET -+ default y - help - Enable auditing infrastructure that can be used with another - kernel subsystem, such as SELinux (which requires this for --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0038-enable-SECURITY_SELINUX-by-default.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0038-enable-SECURITY_SELINUX-by-default.patch deleted file mode 100644 index d68f6f23e745..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0038-enable-SECURITY_SELINUX-by-default.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 47c4b37b8826887f8473b52a6b06f0374c130358 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Sun, 25 Feb 2018 02:16:49 -0500 -Subject: [PATCH 038/113] enable SECURITY_SELINUX by default - ---- - security/selinux/Kconfig | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/security/selinux/Kconfig b/security/selinux/Kconfig -index 9e921fc72538..76d7ed11513c 100644 ---- a/security/selinux/Kconfig -+++ b/security/selinux/Kconfig -@@ -3,7 +3,7 @@ config SECURITY_SELINUX - bool "NSA SELinux Support" - depends on SECURITY_NETWORK && AUDIT && NET && INET - select NETWORK_SECMARK -- default n -+ default y - help - This selects NSA Security-Enhanced Linux (SELinux). - You will also need a policy configuration and a labeled filesystem. --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0039-enable-SYN_COOKIES-by-default.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0039-enable-SYN_COOKIES-by-default.patch deleted file mode 100644 index 63397ccd6f1a..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0039-enable-SYN_COOKIES-by-default.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 9f8e5278fc3651a3977892421cf73110b6fdddfc Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Sat, 6 Jan 2018 13:41:11 -0500 -Subject: [PATCH 039/113] enable SYN_COOKIES by default - ---- - net/ipv4/Kconfig | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig -index 87983e70f03f..989e005bf698 100644 ---- a/net/ipv4/Kconfig -+++ b/net/ipv4/Kconfig -@@ -267,6 +267,7 @@ config IP_PIMSM_V2 - - config SYN_COOKIES - bool "IP: TCP syncookie support" -+ default y - help - Normal TCP/IP networking is open to an attack known as "SYN - flooding". This denial-of-service attack prevents legitimate remote --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0040-enable-INIT_ON_ALLOC_DEFAULT_ON-by-default.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0040-enable-INIT_ON_ALLOC_DEFAULT_ON-by-default.patch deleted file mode 100644 index 48a2656615d2..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0040-enable-INIT_ON_ALLOC_DEFAULT_ON-by-default.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 82e4cd51bfc9b9374eab357f06daf07fac70c05a Mon Sep 17 00:00:00 2001 -From: Levente Polyak <levente@leventepolyak.net> -Date: Thu, 19 Sep 2019 19:02:23 +0200 -Subject: [PATCH 040/113] enable INIT_ON_ALLOC_DEFAULT_ON by default - ---- - security/Kconfig.hardening | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/security/Kconfig.hardening b/security/Kconfig.hardening -index 269967c4fc1b..1e279f6d7633 100644 ---- a/security/Kconfig.hardening -+++ b/security/Kconfig.hardening -@@ -190,6 +190,7 @@ config STACKLEAK_RUNTIME_DISABLE - - config INIT_ON_ALLOC_DEFAULT_ON - bool "Enable heap memory zeroing on allocation by default" -+ default yes - help - This has the effect of setting "init_on_alloc=1" on the kernel - command line. This can be disabled with "init_on_alloc=0". --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0041-enable-INIT_ON_FREE_DEFAULT_ON-by-default.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0041-enable-INIT_ON_FREE_DEFAULT_ON-by-default.patch deleted file mode 100644 index 2d9de4987928..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0041-enable-INIT_ON_FREE_DEFAULT_ON-by-default.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 4f104133b8eb1694bb390d2326d058cd6088447e Mon Sep 17 00:00:00 2001 -From: Levente Polyak <levente@leventepolyak.net> -Date: Thu, 19 Sep 2019 19:03:01 +0200 -Subject: [PATCH 041/113] enable INIT_ON_FREE_DEFAULT_ON by default - ---- - security/Kconfig.hardening | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/security/Kconfig.hardening b/security/Kconfig.hardening -index 1e279f6d7633..2fa447823405 100644 ---- a/security/Kconfig.hardening -+++ b/security/Kconfig.hardening -@@ -203,6 +203,7 @@ config INIT_ON_ALLOC_DEFAULT_ON - - config INIT_ON_FREE_DEFAULT_ON - bool "Enable heap memory zeroing on free by default" -+ default yes - help - This has the effect of setting "init_on_free=1" on the kernel - command line. This can be disabled with "init_on_free=0". --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0042-kconfig-select-DEBUG_FS_ALLOW_NONE-by-default-if-DEB.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0042-kconfig-select-DEBUG_FS_ALLOW_NONE-by-default-if-DEB.patch deleted file mode 100644 index 9d60e6ac8351..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0042-kconfig-select-DEBUG_FS_ALLOW_NONE-by-default-if-DEB.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 86156651b3157fe340ae16dc525e3e14f0859b06 Mon Sep 17 00:00:00 2001 -From: Levente Polyak <levente@leventepolyak.net> -Date: Sun, 27 Sep 2020 00:43:48 +0200 -Subject: [PATCH 042/113] kconfig: select DEBUG_FS_ALLOW_NONE by default if - DEBUG_FS is enabled - -Signed-off-by: Levente Polyak <levente@leventepolyak.net> ---- - lib/Kconfig.debug | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug -index a46f21a56125..4a1a32a059f4 100644 ---- a/lib/Kconfig.debug -+++ b/lib/Kconfig.debug -@@ -488,7 +488,7 @@ config DEBUG_FS - choice - prompt "Debugfs default access" - depends on DEBUG_FS -- default DEBUG_FS_ALLOW_ALL -+ default DEBUG_FS_ALLOW_NONE - help - This selects the default access restrictions for debugfs. - It can be overridden with kernel command line option --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0043-stop-hiding-SYSFS_SYSCALL-behind-EXPERT.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0043-stop-hiding-SYSFS_SYSCALL-behind-EXPERT.patch deleted file mode 100644 index c17caeb4b96a..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0043-stop-hiding-SYSFS_SYSCALL-behind-EXPERT.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 674970612ddb058c0031c6ba49a2df1538878db5 Mon Sep 17 00:00:00 2001 -From: Levente Polyak <levente@leventepolyak.net> -Date: Tue, 22 Dec 2020 23:35:53 +0100 -Subject: [PATCH 043/113] stop hiding SYSFS_SYSCALL behind EXPERT - ---- - init/Kconfig | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/init/Kconfig b/init/Kconfig -index 9b75a4921575..006d4d41e3af 100644 ---- a/init/Kconfig -+++ b/init/Kconfig -@@ -1434,7 +1434,7 @@ config SGETMASK_SYSCALL - If unsure, leave the default option here. - - config SYSFS_SYSCALL -- bool "Sysfs syscall support" if EXPERT -+ bool "Sysfs syscall support" - default y - help - sys_sysfs is an obsolete system call no longer supported in libc. --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0044-disable-SYSFS_SYSCALL-by-default.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0044-disable-SYSFS_SYSCALL-by-default.patch deleted file mode 100644 index 2b43d650c0d6..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0044-disable-SYSFS_SYSCALL-by-default.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 0fce7abfe363d96288a40ac6e3a920eea334383c Mon Sep 17 00:00:00 2001 -From: Levente Polyak <levente@leventepolyak.net> -Date: Tue, 22 Dec 2020 23:36:54 +0100 -Subject: [PATCH 044/113] disable SYSFS_SYSCALL by default - ---- - init/Kconfig | 3 +-- - 1 file changed, 1 insertion(+), 2 deletions(-) - -diff --git a/init/Kconfig b/init/Kconfig -index 006d4d41e3af..3d6b1b23e2db 100644 ---- a/init/Kconfig -+++ b/init/Kconfig -@@ -1435,13 +1435,12 @@ config SGETMASK_SYSCALL - - config SYSFS_SYSCALL - bool "Sysfs syscall support" -- default y - help - sys_sysfs is an obsolete system call no longer supported in libc. - Note that disabling this option is more secure but might break - compatibility with some systems. - -- If unsure say Y here. -+ If unsure say N here. - - config FHANDLE - bool "open by fhandle syscalls" if EXPERT --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0045-stop-hiding-UID16-behind-EXPERT.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0045-stop-hiding-UID16-behind-EXPERT.patch deleted file mode 100644 index 976ca6bcc895..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0045-stop-hiding-UID16-behind-EXPERT.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 21e9ece3ab19a46b0c68ae28c8a8ecb4f335baf7 Mon Sep 17 00:00:00 2001 -From: Levente Polyak <levente@leventepolyak.net> -Date: Tue, 22 Dec 2020 23:40:09 +0100 -Subject: [PATCH 045/113] stop hiding UID16 behind EXPERT - ---- - init/Kconfig | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/init/Kconfig b/init/Kconfig -index 3d6b1b23e2db..2b6d0492def5 100644 ---- a/init/Kconfig -+++ b/init/Kconfig -@@ -1403,7 +1403,7 @@ menuconfig EXPERT - Only use this if you really know what you are doing. - - config UID16 -- bool "Enable 16-bit UID system calls" if EXPERT -+ bool "Enable 16-bit UID system calls" - depends on HAVE_UID16 && MULTIUSER - default y - help --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0046-disable-UID16-by-default.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0046-disable-UID16-by-default.patch deleted file mode 100644 index e4e59aa23874..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0046-disable-UID16-by-default.patch +++ /dev/null @@ -1,24 +0,0 @@ -From e6c5d24e9ce65b9e86c79851271153e54af2d752 Mon Sep 17 00:00:00 2001 -From: Levente Polyak <levente@leventepolyak.net> -Date: Tue, 22 Dec 2020 23:41:32 +0100 -Subject: [PATCH 046/113] disable UID16 by default - ---- - init/Kconfig | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/init/Kconfig b/init/Kconfig -index 2b6d0492def5..58df4930995f 100644 ---- a/init/Kconfig -+++ b/init/Kconfig -@@ -1405,7 +1405,6 @@ menuconfig EXPERT - config UID16 - bool "Enable 16-bit UID system calls" - depends on HAVE_UID16 && MULTIUSER -- default y - help - This enables the legacy 16-bit UID syscall wrappers. - --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0047-add-__read_only-for-non-init-related-usage.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0047-add-__read_only-for-non-init-related-usage.patch deleted file mode 100644 index 6e2dfaf2c313..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0047-add-__read_only-for-non-init-related-usage.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 18f2367d9fc0726dedebfb290482d22aa59ff059 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Sun, 7 May 2017 00:28:23 -0400 -Subject: [PATCH 047/113] add __read_only for non-init related usage - ---- - include/linux/cache.h | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/include/linux/cache.h b/include/linux/cache.h -index d742c57eaee5..f0222c070458 100644 ---- a/include/linux/cache.h -+++ b/include/linux/cache.h -@@ -37,6 +37,8 @@ - #define __ro_after_init __section(".data..ro_after_init") - #endif - -+#define __read_only __ro_after_init -+ - #ifndef ____cacheline_aligned - #define ____cacheline_aligned __attribute__((__aligned__(SMP_CACHE_BYTES))) - #endif --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0048-make-sysctl-constants-read-only.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0048-make-sysctl-constants-read-only.patch deleted file mode 100644 index a331bc7123db..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0048-make-sysctl-constants-read-only.patch +++ /dev/null @@ -1,108 +0,0 @@ -From da389cc424df461626e323414e71be25640074b9 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Sun, 7 May 2017 00:43:03 -0400 -Subject: [PATCH 048/113] make sysctl constants read-only - -Most of this is extracted from the last publicly available version of -the PaX patches where it's part of KERNEXEC as __read_only. It has been -extended to a few more of these constants. ---- - kernel/sysctl.c | 54 ++++++++++++++++++++++++------------------------- - 1 file changed, 27 insertions(+), 27 deletions(-) - -diff --git a/kernel/sysctl.c b/kernel/sysctl.c -index afad085960b8..b2cd3dbbb17a 100644 ---- a/kernel/sysctl.c -+++ b/kernel/sysctl.c -@@ -108,33 +108,33 @@ - - /* Constants used for minimum and maximum */ - #ifdef CONFIG_LOCKUP_DETECTOR --static int sixty = 60; --#endif -- --static int __maybe_unused neg_one = -1; --static int __maybe_unused two = 2; --static int __maybe_unused four = 4; --static unsigned long zero_ul; --static unsigned long one_ul = 1; --static unsigned long long_max = LONG_MAX; --static int one_hundred = 100; --static int two_hundred = 200; --static int one_thousand = 1000; -+static int sixty __read_only = 60; -+#endif -+ -+static int __maybe_unused neg_one __read_only = -1; -+static int __maybe_unused two __read_only = 2; -+static int __maybe_unused four __read_only = 4; -+static unsigned long zero_ul __read_only; -+static unsigned long one_ul __read_only = 1; -+static unsigned long long_max __read_only = LONG_MAX; -+static int one_hundred __read_only = 100; -+static int two_hundred __read_only = 200; -+static int one_thousand __read_only = 1000; - #ifdef CONFIG_PRINTK --static int ten_thousand = 10000; -+static int ten_thousand __read_only = 10000; - #endif - #ifdef CONFIG_PERF_EVENTS --static int six_hundred_forty_kb = 640 * 1024; -+static int six_hundred_forty_kb __read_only = 640 * 1024; - #endif - - /* this is needed for the proc_doulongvec_minmax of vm_dirty_bytes */ --static unsigned long dirty_bytes_min = 2 * PAGE_SIZE; -+static unsigned long dirty_bytes_min __read_only = 2 * PAGE_SIZE; - - /* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */ --static int maxolduid = 65535; --static int minolduid; -+static int maxolduid __read_only = 65535; -+static int minolduid __read_only; - --static int ngroups_max = NGROUPS_MAX; -+static int ngroups_max __read_only = NGROUPS_MAX; - static const int cap_last_cap = CAP_LAST_CAP; - - /* -@@ -142,7 +142,7 @@ static const int cap_last_cap = CAP_LAST_CAP; - * and hung_task_check_interval_secs - */ - #ifdef CONFIG_DETECT_HUNG_TASK --static unsigned long hung_task_timeout_max = (LONG_MAX/HZ); -+static unsigned long hung_task_timeout_max __read_only = (LONG_MAX/HZ); - #endif - - #ifdef CONFIG_INOTIFY_USER -@@ -185,19 +185,19 @@ int sysctl_legacy_va_layout; - #endif - - #ifdef CONFIG_SCHED_DEBUG --static int min_sched_granularity_ns = 100000; /* 100 usecs */ --static int max_sched_granularity_ns = NSEC_PER_SEC; /* 1 second */ --static int min_wakeup_granularity_ns; /* 0 usecs */ --static int max_wakeup_granularity_ns = NSEC_PER_SEC; /* 1 second */ -+static int min_sched_granularity_ns __read_only = 100000; /* 100 usecs */ -+static int max_sched_granularity_ns __read_only = NSEC_PER_SEC; /* 1 second */ -+static int min_wakeup_granularity_ns __read_only; /* 0 usecs */ -+static int max_wakeup_granularity_ns __read_only = NSEC_PER_SEC; /* 1 second */ - #ifdef CONFIG_SMP --static int min_sched_tunable_scaling = SCHED_TUNABLESCALING_NONE; --static int max_sched_tunable_scaling = SCHED_TUNABLESCALING_END-1; -+static int min_sched_tunable_scaling __read_only = SCHED_TUNABLESCALING_NONE; -+static int max_sched_tunable_scaling __read_only = SCHED_TUNABLESCALING_END-1; - #endif /* CONFIG_SMP */ - #endif /* CONFIG_SCHED_DEBUG */ - - #ifdef CONFIG_COMPACTION --static int min_extfrag_threshold; --static int max_extfrag_threshold = 1000; -+static int min_extfrag_threshold __read_only; -+static int max_extfrag_threshold __read_only = 1000; - #endif - - #endif /* CONFIG_SYSCTL */ --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0049-mark-kernel_set_to_readonly-as-__ro_after_init.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0049-mark-kernel_set_to_readonly-as-__ro_after_init.patch deleted file mode 100644 index 7e10b9b59d45..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0049-mark-kernel_set_to_readonly-as-__ro_after_init.patch +++ /dev/null @@ -1,67 +0,0 @@ -From 5427cc4e11d447f4141f6656d0f320f3c201d621 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Fri, 12 May 2017 03:22:00 -0400 -Subject: [PATCH 049/113] mark kernel_set_to_readonly as __ro_after_init - -This change was extracted from PaX where it's part of KERNEXEC. - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - arch/x86/mm/init_32.c | 5 ++--- - arch/x86/mm/init_64.c | 5 ++--- - 2 files changed, 4 insertions(+), 6 deletions(-) - -diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c -index 7c055259de3a..77192cbc1dd7 100644 ---- a/arch/x86/mm/init_32.c -+++ b/arch/x86/mm/init_32.c -@@ -828,7 +828,7 @@ void arch_remove_memory(int nid, u64 start, u64 size, - } - #endif - --int kernel_set_to_readonly __read_mostly; -+int kernel_set_to_readonly __ro_after_init; - - static void mark_nxdata_nx(void) - { -@@ -852,12 +852,11 @@ void mark_rodata_ro(void) - unsigned long start = PFN_ALIGN(_text); - unsigned long size = (unsigned long)__end_rodata - start; - -+ kernel_set_to_readonly = 1; - set_pages_ro(virt_to_page(start), size >> PAGE_SHIFT); - pr_info("Write protecting kernel text and read-only data: %luk\n", - size >> 10); - -- kernel_set_to_readonly = 1; -- - #ifdef CONFIG_CPA_DEBUG - pr_info("Testing CPA: Reverting %lx-%lx\n", start, start + size); - set_pages_rw(virt_to_page(start), size >> PAGE_SHIFT); -diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c -index b5a3fa4033d3..63a0f8097d0a 100644 ---- a/arch/x86/mm/init_64.c -+++ b/arch/x86/mm/init_64.c -@@ -1322,7 +1322,7 @@ int __init deferred_page_init_max_threads(const struct cpumask *node_cpumask) - } - #endif - --int kernel_set_to_readonly; -+int kernel_set_to_readonly __ro_after_init; - - void mark_rodata_ro(void) - { -@@ -1335,9 +1335,8 @@ void mark_rodata_ro(void) - - printk(KERN_INFO "Write protecting the kernel read-only data: %luk\n", - (end - start) >> 10); -- set_memory_ro(start, (end - start) >> PAGE_SHIFT); -- - kernel_set_to_readonly = 1; -+ set_memory_ro(start, (end - start) >> PAGE_SHIFT); - - /* - * The rodata/data/bss/brk section (but not the kernel text!) --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0050-Revert-mark-kernel_set_to_readonly-as-__ro_after_ini.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0050-Revert-mark-kernel_set_to_readonly-as-__ro_after_ini.patch deleted file mode 100644 index cb8f5198eb72..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0050-Revert-mark-kernel_set_to_readonly-as-__ro_after_ini.patch +++ /dev/null @@ -1,70 +0,0 @@ -From 4c1123c432c6467d6258e52dfa7293e64bc99ef1 Mon Sep 17 00:00:00 2001 -From: Levente Polyak <levente@leventepolyak.net> -Date: Sun, 13 Jan 2019 21:42:45 +0100 -Subject: [PATCH 050/113] Revert "mark kernel_set_to_readonly as - __ro_after_init" - - This commit causes CPA conflicts, cf. - https://github.com/anthraxx/linux-hardened/issues/4. - - Signed-off-by: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr> ---- - arch/x86/mm/init_32.c | 5 +++-- - arch/x86/mm/init_64.c | 5 +++-- - 2 files changed, 6 insertions(+), 4 deletions(-) - -diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c -index 77192cbc1dd7..7c055259de3a 100644 ---- a/arch/x86/mm/init_32.c -+++ b/arch/x86/mm/init_32.c -@@ -828,7 +828,7 @@ void arch_remove_memory(int nid, u64 start, u64 size, - } - #endif - --int kernel_set_to_readonly __ro_after_init; -+int kernel_set_to_readonly __read_mostly; - - static void mark_nxdata_nx(void) - { -@@ -852,11 +852,12 @@ void mark_rodata_ro(void) - unsigned long start = PFN_ALIGN(_text); - unsigned long size = (unsigned long)__end_rodata - start; - -- kernel_set_to_readonly = 1; - set_pages_ro(virt_to_page(start), size >> PAGE_SHIFT); - pr_info("Write protecting kernel text and read-only data: %luk\n", - size >> 10); - -+ kernel_set_to_readonly = 1; -+ - #ifdef CONFIG_CPA_DEBUG - pr_info("Testing CPA: Reverting %lx-%lx\n", start, start + size); - set_pages_rw(virt_to_page(start), size >> PAGE_SHIFT); -diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c -index 63a0f8097d0a..b5a3fa4033d3 100644 ---- a/arch/x86/mm/init_64.c -+++ b/arch/x86/mm/init_64.c -@@ -1322,7 +1322,7 @@ int __init deferred_page_init_max_threads(const struct cpumask *node_cpumask) - } - #endif - --int kernel_set_to_readonly __ro_after_init; -+int kernel_set_to_readonly; - - void mark_rodata_ro(void) - { -@@ -1335,9 +1335,10 @@ void mark_rodata_ro(void) - - printk(KERN_INFO "Write protecting the kernel read-only data: %luk\n", - (end - start) >> 10); -- kernel_set_to_readonly = 1; - set_memory_ro(start, (end - start) >> PAGE_SHIFT); - -+ kernel_set_to_readonly = 1; -+ - /* - * The rodata/data/bss/brk section (but not the kernel text!) - * should also be not-executable. --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0051-mark-slub-runtime-configuration-as-__ro_after_init.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0051-mark-slub-runtime-configuration-as-__ro_after_init.patch deleted file mode 100644 index 8477af69188b..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0051-mark-slub-runtime-configuration-as-__ro_after_init.patch +++ /dev/null @@ -1,57 +0,0 @@ -From c828ce6ad8640cd0fc71c26f4792595a9f1355ed Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Sun, 14 May 2017 19:01:58 -0400 -Subject: [PATCH 051/113] mark slub runtime configuration as __ro_after_init - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - mm/slub.c | 16 ++++++++-------- - 1 file changed, 8 insertions(+), 8 deletions(-) - -diff --git a/mm/slub.c b/mm/slub.c -index 071e41067ea6..e01d54dc46e1 100644 ---- a/mm/slub.c -+++ b/mm/slub.c -@@ -486,13 +486,13 @@ static inline void *restore_red_left(struct kmem_cache *s, void *p) - * Debug settings: - */ - #if defined(CONFIG_SLUB_DEBUG_ON) --static slab_flags_t slub_debug = DEBUG_DEFAULT_FLAGS; -+static slab_flags_t slub_debug __ro_after_init = DEBUG_DEFAULT_FLAGS; - #else --static slab_flags_t slub_debug; -+static slab_flags_t slub_debug __ro_after_init; - #endif - --static char *slub_debug_string; --static int disable_higher_order_debug; -+static char *slub_debug_string __ro_after_init; -+static int disable_higher_order_debug __ro_after_init; - - /* - * slub is about to manipulate internal object metadata. This memory lies -@@ -3363,9 +3363,9 @@ EXPORT_SYMBOL(kmem_cache_alloc_bulk); - * and increases the number of allocations possible without having to - * take the list_lock. - */ --static unsigned int slub_min_order; --static unsigned int slub_max_order = PAGE_ALLOC_COSTLY_ORDER; --static unsigned int slub_min_objects; -+static unsigned int slub_min_order __ro_after_init; -+static unsigned int slub_max_order __ro_after_init = PAGE_ALLOC_COSTLY_ORDER; -+static unsigned int slub_min_objects __ro_after_init; - - /* - * Calculate the order of allocation given an slab object size. -@@ -4883,7 +4883,7 @@ enum slab_stat_type { - #define SO_TOTAL (1 << SL_TOTAL) - - #ifdef CONFIG_MEMCG --static bool memcg_sysfs_enabled = IS_ENABLED(CONFIG_SLUB_MEMCG_SYSFS_ON); -+static bool memcg_sysfs_enabled __ro_after_init = IS_ENABLED(CONFIG_SLUB_MEMCG_SYSFS_ON); - - static int __init setup_slub_memcg_sysfs(char *str) - { --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0052-add-__ro_after_init-to-slab_nomerge-and-slab_state.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0052-add-__ro_after_init-to-slab_nomerge-and-slab_state.patch deleted file mode 100644 index e38988d5c8c5..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0052-add-__ro_after_init-to-slab_nomerge-and-slab_state.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 44af11562c2ddc1bb62c531fa37bf6dc1caa104a Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Wed, 3 May 2017 11:35:35 -0400 -Subject: [PATCH 052/113] add __ro_after_init to slab_nomerge and slab_state - -This was extracted from the PaX patch where it's part of the KERNEXEC -feature as __read_only. - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - mm/slab_common.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/mm/slab_common.c b/mm/slab_common.c -index f9ccd5dc13f3..bff04048559f 100644 ---- a/mm/slab_common.c -+++ b/mm/slab_common.c -@@ -30,7 +30,7 @@ - - #include "slab.h" - --enum slab_state slab_state; -+enum slab_state slab_state __ro_after_init; - LIST_HEAD(slab_caches); - DEFINE_MUTEX(slab_mutex); - struct kmem_cache *kmem_cache; -@@ -61,7 +61,7 @@ static DECLARE_WORK(slab_caches_to_rcu_destroy_work, - /* - * Merge control. If this is set then no merging of slab caches will occur. - */ --static bool slab_nomerge = !IS_ENABLED(CONFIG_SLAB_MERGE_DEFAULT); -+static bool slab_nomerge __ro_after_init = !IS_ENABLED(CONFIG_SLAB_MERGE_DEFAULT); - - static int __init setup_slab_nomerge(char *str) - { --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0053-mark-kmem_cache-as-__ro_after_init.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0053-mark-kmem_cache-as-__ro_after_init.patch deleted file mode 100644 index fb682b743fd7..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0053-mark-kmem_cache-as-__ro_after_init.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 32c99733e4e166930213239e2b0249c1b93645ee Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Sun, 28 May 2017 18:51:30 -0400 -Subject: [PATCH 053/113] mark kmem_cache as __ro_after_init - ---- - mm/slab_common.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/mm/slab_common.c b/mm/slab_common.c -index bff04048559f..2b73c12d8fce 100644 ---- a/mm/slab_common.c -+++ b/mm/slab_common.c -@@ -33,7 +33,7 @@ - enum slab_state slab_state __ro_after_init; - LIST_HEAD(slab_caches); - DEFINE_MUTEX(slab_mutex); --struct kmem_cache *kmem_cache; -+struct kmem_cache *kmem_cache __ro_after_init; - - #ifdef CONFIG_HARDENED_USERCOPY - bool usercopy_fallback __ro_after_init = --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0054-mark-__supported_pte_mask-as-__ro_after_init.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0054-mark-__supported_pte_mask-as-__ro_after_init.patch deleted file mode 100644 index 19c854f99503..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0054-mark-__supported_pte_mask-as-__ro_after_init.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 975692afa5eb106ff97cf87cc2c20827225b1e54 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Fri, 12 May 2017 00:06:16 -0400 -Subject: [PATCH 054/113] mark __supported_pte_mask as __ro_after_init - -These changes were extracted from PaX where it was part of KERNEXEC as -__read_only. - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - arch/x86/mm/init_32.c | 4 ++-- - arch/x86/mm/init_64.c | 4 ++-- - 2 files changed, 4 insertions(+), 4 deletions(-) - -diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c -index 7c055259de3a..291b7b4476a9 100644 ---- a/arch/x86/mm/init_32.c -+++ b/arch/x86/mm/init_32.c -@@ -546,9 +546,9 @@ static void __init pagetable_init(void) - - #define DEFAULT_PTE_MASK ~(_PAGE_NX | _PAGE_GLOBAL) - /* Bits supported by the hardware: */ --pteval_t __supported_pte_mask __read_mostly = DEFAULT_PTE_MASK; -+pteval_t __supported_pte_mask __ro_after_init = DEFAULT_PTE_MASK; - /* Bits allowed in normal kernel mappings: */ --pteval_t __default_kernel_pte_mask __read_mostly = DEFAULT_PTE_MASK; -+pteval_t __default_kernel_pte_mask __ro_after_init = DEFAULT_PTE_MASK; - EXPORT_SYMBOL_GPL(__supported_pte_mask); - /* Used in PAGE_KERNEL_* macros which are reasonably used out-of-tree: */ - EXPORT_SYMBOL(__default_kernel_pte_mask); -diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c -index b5a3fa4033d3..c3d771ffc178 100644 ---- a/arch/x86/mm/init_64.c -+++ b/arch/x86/mm/init_64.c -@@ -97,9 +97,9 @@ DEFINE_ENTRY(pte, pte, init) - */ - - /* Bits supported by the hardware: */ --pteval_t __supported_pte_mask __read_mostly = ~0; -+pteval_t __supported_pte_mask __ro_after_init = ~0; - /* Bits allowed in normal kernel mappings: */ --pteval_t __default_kernel_pte_mask __read_mostly = ~0; -+pteval_t __default_kernel_pte_mask __ro_after_init = ~0; - EXPORT_SYMBOL_GPL(__supported_pte_mask); - /* Used in PAGE_KERNEL_* macros which are reasonably used out-of-tree: */ - EXPORT_SYMBOL(__default_kernel_pte_mask); --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0055-mark-kobj_ns_type_register-as-only-used-for-init.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0055-mark-kobj_ns_type_register-as-only-used-for-init.patch deleted file mode 100644 index 3f011c02c9e5..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0055-mark-kobj_ns_type_register-as-only-used-for-init.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 5e42d85e11c2782634935d3d5157ce73af6b8d8b Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Tue, 4 Jul 2017 01:24:28 -0400 -Subject: [PATCH 055/113] mark kobj_ns_type_register as only used for init - -This allows kobj_ns_ops_tbl to be __ro_after_init. - -Extracted from PaX. ---- - include/linux/kobject_ns.h | 2 +- - lib/kobject.c | 4 ++-- - 2 files changed, 3 insertions(+), 3 deletions(-) - -diff --git a/include/linux/kobject_ns.h b/include/linux/kobject_ns.h -index 2b5b64256cf4..8cdce21dce0f 100644 ---- a/include/linux/kobject_ns.h -+++ b/include/linux/kobject_ns.h -@@ -45,7 +45,7 @@ struct kobj_ns_type_operations { - void (*drop_ns)(void *); - }; - --int kobj_ns_type_register(const struct kobj_ns_type_operations *ops); -+int __init kobj_ns_type_register(const struct kobj_ns_type_operations *ops); - int kobj_ns_type_registered(enum kobj_ns_type type); - const struct kobj_ns_type_operations *kobj_child_ns_ops(struct kobject *parent); - const struct kobj_ns_type_operations *kobj_ns_ops(struct kobject *kobj); -diff --git a/lib/kobject.c b/lib/kobject.c -index ea53b30cf483..5343bbeea5f8 100644 ---- a/lib/kobject.c -+++ b/lib/kobject.c -@@ -1023,9 +1023,9 @@ EXPORT_SYMBOL_GPL(kset_create_and_add); - - - static DEFINE_SPINLOCK(kobj_ns_type_lock); --static const struct kobj_ns_type_operations *kobj_ns_ops_tbl[KOBJ_NS_TYPES]; -+static const struct kobj_ns_type_operations *kobj_ns_ops_tbl[KOBJ_NS_TYPES] __ro_after_init; - --int kobj_ns_type_register(const struct kobj_ns_type_operations *ops) -+int __init kobj_ns_type_register(const struct kobj_ns_type_operations *ops) - { - enum kobj_ns_type type = ops->type; - int error; --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0056-mark-open_softirq-as-only-used-for-init.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0056-mark-open_softirq-as-only-used-for-init.patch deleted file mode 100644 index 48c704ee363b..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0056-mark-open_softirq-as-only-used-for-init.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 7423c05941ce6d13b295148068ab08f5581860af Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Tue, 4 Jul 2017 01:32:30 -0400 -Subject: [PATCH 056/113] mark open_softirq as only used for init - ---- - include/linux/interrupt.h | 2 +- - kernel/softirq.c | 2 +- - 2 files changed, 2 insertions(+), 2 deletions(-) - -diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h -index ee8299eb1f52..f03b78ae5f0a 100644 ---- a/include/linux/interrupt.h -+++ b/include/linux/interrupt.h -@@ -569,7 +569,7 @@ static inline void do_softirq_own_stack(void) - } - #endif - --extern void open_softirq(int nr, void (*action)(struct softirq_action *)); -+extern void __init open_softirq(int nr, void (*action)(struct softirq_action *)); - extern void softirq_init(void); - extern void __raise_softirq_irqoff(unsigned int nr); - -diff --git a/kernel/softirq.c b/kernel/softirq.c -index 09229ad82209..0595a8248c4a 100644 ---- a/kernel/softirq.c -+++ b/kernel/softirq.c -@@ -486,7 +486,7 @@ void __raise_softirq_irqoff(unsigned int nr) - or_softirq_pending(1UL << nr); - } - --void open_softirq(int nr, void (*action)(struct softirq_action *)) -+void __init open_softirq(int nr, void (*action)(struct softirq_action *)) - { - softirq_vec[nr].action = action; - } --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0057-remove-unused-softirq_action-callback-parameter.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0057-remove-unused-softirq_action-callback-parameter.patch deleted file mode 100644 index f036cb331dfc..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0057-remove-unused-softirq_action-callback-parameter.patch +++ /dev/null @@ -1,208 +0,0 @@ -From 8732aabd990d6eb6d2ae2d2618b605925373db1b Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Tue, 4 Jul 2017 01:41:11 -0400 -Subject: [PATCH 057/113] remove unused softirq_action callback parameter - -Extracted from PaX. ---- - block/blk-mq.c | 2 +- - include/linux/interrupt.h | 4 ++-- - kernel/rcu/tiny.c | 2 +- - kernel/rcu/tree.c | 2 +- - kernel/sched/fair.c | 2 +- - kernel/softirq.c | 15 +++++++-------- - kernel/time/hrtimer.c | 2 +- - kernel/time/timer.c | 2 +- - lib/irq_poll.c | 2 +- - net/core/dev.c | 4 ++-- - 10 files changed, 18 insertions(+), 19 deletions(-) - -diff --git a/block/blk-mq.c b/block/blk-mq.c -index 2a1eff60c797..75a0077ea1a9 100644 ---- a/block/blk-mq.c -+++ b/block/blk-mq.c -@@ -569,7 +569,7 @@ EXPORT_SYMBOL(blk_mq_end_request); - * Softirq action handler - move entries to local list and loop over them - * while passing them to the queue registered handler. - */ --static __latent_entropy void blk_done_softirq(struct softirq_action *h) -+static __latent_entropy void blk_done_softirq(void) - { - struct list_head *cpu_list, local_list; - -diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h -index f03b78ae5f0a..4381b79f76cf 100644 ---- a/include/linux/interrupt.h -+++ b/include/linux/interrupt.h -@@ -554,7 +554,7 @@ extern const char * const softirq_to_name[NR_SOFTIRQS]; - - struct softirq_action - { -- void (*action)(struct softirq_action *); -+ void (*action)(void); - }; - - asmlinkage void do_softirq(void); -@@ -569,7 +569,7 @@ static inline void do_softirq_own_stack(void) - } - #endif - --extern void __init open_softirq(int nr, void (*action)(struct softirq_action *)); -+extern void __init open_softirq(int nr, void (*action)(void)); - extern void softirq_init(void); - extern void __raise_softirq_irqoff(unsigned int nr); - -diff --git a/kernel/rcu/tiny.c b/kernel/rcu/tiny.c -index aa897c3f2e92..d8976886fd68 100644 ---- a/kernel/rcu/tiny.c -+++ b/kernel/rcu/tiny.c -@@ -101,7 +101,7 @@ static inline bool rcu_reclaim_tiny(struct rcu_head *head) - } - - /* Invoke the RCU callbacks whose grace period has elapsed. */ --static __latent_entropy void rcu_process_callbacks(struct softirq_action *unused) -+static __latent_entropy void rcu_process_callbacks(void) - { - struct rcu_head *next, *list; - unsigned long flags; -diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c -index 593df7edfe97..3285d81d8a26 100644 ---- a/kernel/rcu/tree.c -+++ b/kernel/rcu/tree.c -@@ -2722,7 +2722,7 @@ static __latent_entropy void rcu_core(void) - queue_work_on(rdp->cpu, rcu_gp_wq, &rdp->strict_work); - } - --static void rcu_core_si(struct softirq_action *h) -+static void rcu_core_si(void) - { - rcu_core(); - } -diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c -index ae7ceba8fd4f..d118be5f18b8 100644 ---- a/kernel/sched/fair.c -+++ b/kernel/sched/fair.c -@@ -10628,7 +10628,7 @@ static int newidle_balance(struct rq *this_rq, struct rq_flags *rf) - * run_rebalance_domains is triggered when needed from the scheduler tick. - * Also triggered for nohz idle balancing (with nohz_balancing_kick set). - */ --static __latent_entropy void run_rebalance_domains(struct softirq_action *h) -+static __latent_entropy void run_rebalance_domains(void) - { - struct rq *this_rq = this_rq(); - enum cpu_idle_type idle = this_rq->idle_balance ? -diff --git a/kernel/softirq.c b/kernel/softirq.c -index 0595a8248c4a..3a21b22227c1 100644 ---- a/kernel/softirq.c -+++ b/kernel/softirq.c -@@ -295,7 +295,7 @@ asmlinkage __visible void __softirq_entry __do_softirq(void) - kstat_incr_softirqs_this_cpu(vec_nr); - - trace_softirq_entry(vec_nr); -- h->action(h); -+ h->action(); - trace_softirq_exit(vec_nr); - if (unlikely(prev_count != preempt_count())) { - pr_err("huh, entered softirq %u %s %p with preempt_count %08x, exited with %08x?\n", -@@ -486,7 +486,7 @@ void __raise_softirq_irqoff(unsigned int nr) - or_softirq_pending(1UL << nr); - } - --void __init open_softirq(int nr, void (*action)(struct softirq_action *)) -+void __init open_softirq(int nr, void (*action)(void)) - { - softirq_vec[nr].action = action; - } -@@ -532,8 +532,7 @@ void __tasklet_hi_schedule(struct tasklet_struct *t) - } - EXPORT_SYMBOL(__tasklet_hi_schedule); - --static void tasklet_action_common(struct softirq_action *a, -- struct tasklet_head *tl_head, -+static void tasklet_action_common(struct tasklet_head *tl_head, - unsigned int softirq_nr) - { - struct tasklet_struct *list; -@@ -573,14 +572,14 @@ static void tasklet_action_common(struct softirq_action *a, - } - } - --static __latent_entropy void tasklet_action(struct softirq_action *a) -+static __latent_entropy void tasklet_action(void) - { -- tasklet_action_common(a, this_cpu_ptr(&tasklet_vec), TASKLET_SOFTIRQ); -+ tasklet_action_common(this_cpu_ptr(&tasklet_vec), TASKLET_SOFTIRQ); - } - --static __latent_entropy void tasklet_hi_action(struct softirq_action *a) -+static __latent_entropy void tasklet_hi_action(void) - { -- tasklet_action_common(a, this_cpu_ptr(&tasklet_hi_vec), HI_SOFTIRQ); -+ tasklet_action_common(this_cpu_ptr(&tasklet_hi_vec), HI_SOFTIRQ); - } - - void tasklet_setup(struct tasklet_struct *t, -diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c -index 387b4bef7dd1..8fe28c28a906 100644 ---- a/kernel/time/hrtimer.c -+++ b/kernel/time/hrtimer.c -@@ -1587,7 +1587,7 @@ static void __hrtimer_run_queues(struct hrtimer_cpu_base *cpu_base, ktime_t now, - } - } - --static __latent_entropy void hrtimer_run_softirq(struct softirq_action *h) -+static __latent_entropy void hrtimer_run_softirq(void) - { - struct hrtimer_cpu_base *cpu_base = this_cpu_ptr(&hrtimer_bases); - unsigned long flags; -diff --git a/kernel/time/timer.c b/kernel/time/timer.c -index c3ad64fb9d8b..217bc49a3856 100644 ---- a/kernel/time/timer.c -+++ b/kernel/time/timer.c -@@ -1753,7 +1753,7 @@ static inline void __run_timers(struct timer_base *base) - /* - * This function runs timers and the timer-tq in bottom half context. - */ --static __latent_entropy void run_timer_softirq(struct softirq_action *h) -+static __latent_entropy void run_timer_softirq(void) - { - struct timer_base *base = this_cpu_ptr(&timer_bases[BASE_STD]); - -diff --git a/lib/irq_poll.c b/lib/irq_poll.c -index 2f17b488d58e..b6e7996a0058 100644 ---- a/lib/irq_poll.c -+++ b/lib/irq_poll.c -@@ -75,7 +75,7 @@ void irq_poll_complete(struct irq_poll *iop) - } - EXPORT_SYMBOL(irq_poll_complete); - --static void __latent_entropy irq_poll_softirq(struct softirq_action *h) -+static void __latent_entropy irq_poll_softirq(void) - { - struct list_head *list = this_cpu_ptr(&blk_cpu_iopoll); - int rearm = 0, budget = irq_poll_budget; -diff --git a/net/core/dev.c b/net/core/dev.c -index 81e5d482c238..172fd10f4b01 100644 ---- a/net/core/dev.c -+++ b/net/core/dev.c -@@ -4856,7 +4856,7 @@ int netif_rx_any_context(struct sk_buff *skb) - } - EXPORT_SYMBOL(netif_rx_any_context); - --static __latent_entropy void net_tx_action(struct softirq_action *h) -+static __latent_entropy void net_tx_action(void) - { - struct softnet_data *sd = this_cpu_ptr(&softnet_data); - -@@ -6803,7 +6803,7 @@ static int napi_poll(struct napi_struct *n, struct list_head *repoll) - return work; - } - --static __latent_entropy void net_rx_action(struct softirq_action *h) -+static __latent_entropy void net_rx_action(void) - { - struct softnet_data *sd = this_cpu_ptr(&softnet_data); - unsigned long time_limit = jiffies + --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0058-mark-softirq_vec-as-__ro_after_init.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0058-mark-softirq_vec-as-__ro_after_init.patch deleted file mode 100644 index 192cd1556a93..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0058-mark-softirq_vec-as-__ro_after_init.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 4f5625b066a4e114cd589c71c727cca582427ce6 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Tue, 4 Jul 2017 01:42:33 -0400 -Subject: [PATCH 058/113] mark softirq_vec as __ro_after_init - -Note: __cacheline_aligned_in_smp conflicts with __ro_after_init on x86. - -Extracted from PaX. ---- - kernel/softirq.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/kernel/softirq.c b/kernel/softirq.c -index 3a21b22227c1..6a02d63b135a 100644 ---- a/kernel/softirq.c -+++ b/kernel/softirq.c -@@ -52,7 +52,7 @@ DEFINE_PER_CPU_ALIGNED(irq_cpustat_t, irq_stat); - EXPORT_PER_CPU_SYMBOL(irq_stat); - #endif - --static struct softirq_action softirq_vec[NR_SOFTIRQS] __cacheline_aligned_in_smp; -+static struct softirq_action softirq_vec[NR_SOFTIRQS] __ro_after_init __aligned(PAGE_SIZE); - - DEFINE_PER_CPU(struct task_struct *, ksoftirqd); - --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0059-mm-slab-trigger-BUG-if-requested-object-is-not-a-sla.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0059-mm-slab-trigger-BUG-if-requested-object-is-not-a-sla.patch deleted file mode 100644 index e523352621b3..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0059-mm-slab-trigger-BUG-if-requested-object-is-not-a-sla.patch +++ /dev/null @@ -1,34 +0,0 @@ -From b4a191009357361eefdc0e13f9f0f9d184850490 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Tue, 17 Sep 2019 18:00:54 +0200 -Subject: [PATCH 059/113] mm: slab: trigger BUG if requested object is not a - slab page - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> -Signed-off-by: Levente Polyak <levente@leventepolyak.net> -Signed-off-by: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr> ---- - mm/slab.h | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/mm/slab.h b/mm/slab.h -index f9977d6613d6..5adb48bb2e68 100644 ---- a/mm/slab.h -+++ b/mm/slab.h -@@ -435,9 +435,13 @@ static inline struct kmem_cache *virt_to_cache(const void *obj) - struct page *page; - - page = virt_to_head_page(obj); -+#ifdef CONFIG_BUG_ON_DATA_CORRUPTION -+ BUG_ON(!PageSlab(page)); -+#else - if (WARN_ONCE(!PageSlab(page), "%s: Object is not a Slab page!\n", - __func__)) - return NULL; -+#endif - return page->slab_cache; - } - --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0060-bug-on-kmem_cache_free-with-the-wrong-cache.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0060-bug-on-kmem_cache_free-with-the-wrong-cache.patch deleted file mode 100644 index b3eaf289b2ca..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0060-bug-on-kmem_cache_free-with-the-wrong-cache.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 6ba516f97cc8db1d67620bc2145258f922cba79a Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Wed, 3 May 2017 11:50:53 -0400 -Subject: [PATCH 060/113] bug on kmem_cache_free with the wrong cache - -At least when CONFIG_BUG_ON_DATA_CORRUPTION is enabled. - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> -Signed-off-by: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr> -Signed-off-by: Levente Polyak <levente@leventepolyak.net> ---- - mm/slab.h | 11 ++++++++--- - 1 file changed, 8 insertions(+), 3 deletions(-) - -diff --git a/mm/slab.h b/mm/slab.h -index 5adb48bb2e68..9fef4285514a 100644 ---- a/mm/slab.h -+++ b/mm/slab.h -@@ -471,10 +471,15 @@ static inline struct kmem_cache *cache_from_obj(struct kmem_cache *s, void *x) - return s; - - cachep = virt_to_cache(x); -- if (WARN(cachep && cachep != s, -- "%s: Wrong slab cache. %s but object is from %s\n", -- __func__, s->name, cachep->name)) -+ if (cachep && cachep != s) { -+#ifdef CONFIG_BUG_ON_DATA_CORRUPTION -+ BUG(); -+#else -+ WARN(1, "%s: Wrong slab cache. %s but object is from %s\n", -+ __func__, s->name, cachep->name); -+#endif - print_tracking(cachep, x); -+ } - return cachep; - } - --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0061-bug-on-PageSlab-PageCompound-in-ksize.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0061-bug-on-PageSlab-PageCompound-in-ksize.patch deleted file mode 100644 index b3d4819f67df..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0061-bug-on-PageSlab-PageCompound-in-ksize.patch +++ /dev/null @@ -1,31 +0,0 @@ -From ca3e5dd002a2862545da66983a242d30a611f200 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Wed, 3 May 2017 11:57:35 -0400 -Subject: [PATCH 061/113] bug on !PageSlab && !PageCompound in ksize - -At least when CONFIG_BUG_ON_DATA_CORRUPTION is enabled. - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - mm/slub.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/mm/slub.c b/mm/slub.c -index e01d54dc46e1..07ce7cac2612 100644 ---- a/mm/slub.c -+++ b/mm/slub.c -@@ -4092,7 +4092,11 @@ size_t __ksize(const void *object) - page = virt_to_head_page(object); - - if (unlikely(!PageSlab(page))) { -+#ifdef CONFIG_BUG_ON_DATA_CORRUPTION -+ BUG_ON(!PageCompound(page)); -+#else - WARN_ON(!PageCompound(page)); -+#endif - return page_size(page); - } - --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0062-mm-add-support-for-verifying-page-sanitization.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0062-mm-add-support-for-verifying-page-sanitization.patch deleted file mode 100644 index 7d2d59bf3683..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0062-mm-add-support-for-verifying-page-sanitization.patch +++ /dev/null @@ -1,70 +0,0 @@ -From 268be364ad71a62af690cd31c9656856aca0ea76 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Wed, 3 May 2017 21:54:56 -0400 -Subject: [PATCH 062/113] mm: add support for verifying page sanitization - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> -Signed-off-by: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr> -Signed-off-by: Levente Polyak <levente@leventepolyak.net> ---- - include/linux/highmem.h | 7 +++++++ - mm/page_alloc.c | 6 ++++++ - security/Kconfig.hardening | 7 +++++++ - 3 files changed, 20 insertions(+) - -diff --git a/include/linux/highmem.h b/include/linux/highmem.h -index 14e6202ce47f..4348ad7f5c50 100644 ---- a/include/linux/highmem.h -+++ b/include/linux/highmem.h -@@ -284,6 +284,13 @@ static inline void clear_highpage(struct page *page) - kunmap_atomic(kaddr); - } - -+static inline void verify_zero_highpage(struct page *page) -+{ -+ void *kaddr = kmap_atomic(page); -+ BUG_ON(memchr_inv(kaddr, 0, PAGE_SIZE)); -+ kunmap_atomic(kaddr); -+} -+ - static inline void zero_user_segments(struct page *page, - unsigned start1, unsigned end1, - unsigned start2, unsigned end2) -diff --git a/mm/page_alloc.c b/mm/page_alloc.c -index 88639706ae17..e014e6df1f39 100644 ---- a/mm/page_alloc.c -+++ b/mm/page_alloc.c -@@ -2284,6 +2284,12 @@ static void prep_new_page(struct page *page, unsigned int order, gfp_t gfp_flags - { - post_alloc_hook(page, order, gfp_flags); - -+ if (IS_ENABLED(CONFIG_PAGE_SANITIZE_VERIFY) && want_init_on_free()) { -+ int i; -+ for (i = 0; i < (1 << order); i++) -+ verify_zero_highpage(page + i); -+ } -+ - if (!free_pages_prezeroed() && want_init_on_alloc(gfp_flags)) - kernel_init_free_pages(page, 1 << order); - -diff --git a/security/Kconfig.hardening b/security/Kconfig.hardening -index 2fa447823405..83ad70ae6bc3 100644 ---- a/security/Kconfig.hardening -+++ b/security/Kconfig.hardening -@@ -219,6 +219,13 @@ config INIT_ON_FREE_DEFAULT_ON - touching "cold" memory areas. Most cases see 3-5% impact. Some - synthetic workloads have measured as high as 8%. - -+config PAGE_SANITIZE_VERIFY -+ bool "Verify sanitized pages" -+ default y -+ help -+ When init_on_free is enabled, verify that newly allocated pages -+ are zeroed to detect write-after-free bugs. -+ - endmenu - - endmenu --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0063-slub-Extend-init_on_free-to-slab-caches-with-constru.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0063-slub-Extend-init_on_free-to-slab-caches-with-constru.patch deleted file mode 100644 index 72f9ba18ae82..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0063-slub-Extend-init_on_free-to-slab-caches-with-constru.patch +++ /dev/null @@ -1,75 +0,0 @@ -From 9144a6cce3d87056048b9ed092eb6a9391f12cf4 Mon Sep 17 00:00:00 2001 -From: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr> -Date: Fri, 20 Sep 2019 14:02:42 +0200 -Subject: [PATCH 063/113] slub: Extend init_on_free to slab caches with - constructors - -This is the remaining non-upstream part of SLAB_SANITIZE, which was a -partial port, from Daniel Micay, of the feature from PaX without the -default fast mode based on passing SLAB_NO_SANITIZE in -performance-critical cases that are not particularly security sensitive. - -Signed-off-by: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr> ---- - mm/slab.h | 12 +++++++++--- - mm/slub.c | 14 +++++++++++++- - 2 files changed, 22 insertions(+), 4 deletions(-) - -diff --git a/mm/slab.h b/mm/slab.h -index 9fef4285514a..0fcd97a4eb6f 100644 ---- a/mm/slab.h -+++ b/mm/slab.h -@@ -641,9 +641,15 @@ static inline bool slab_want_init_on_alloc(gfp_t flags, struct kmem_cache *c) - - static inline bool slab_want_init_on_free(struct kmem_cache *c) - { -- if (static_branch_unlikely(&init_on_free)) -- return !(c->ctor || -- (c->flags & (SLAB_TYPESAFE_BY_RCU | SLAB_POISON))); -+ if (static_branch_unlikely(&init_on_free)) { -+#ifndef CONFIG_SLUB -+ if (c->ctor) -+ return false; -+#endif -+ if (c->flags & (SLAB_TYPESAFE_BY_RCU | SLAB_POISON)) -+ return false; -+ return true; -+ } - return false; - } - -diff --git a/mm/slub.c b/mm/slub.c -index 07ce7cac2612..ac22d6831b9b 100644 ---- a/mm/slub.c -+++ b/mm/slub.c -@@ -1571,7 +1571,8 @@ static inline bool slab_free_freelist_hook(struct kmem_cache *s, - : 0; - memset((char *)object + s->inuse, 0, - s->size - s->inuse - rsize); -- -+ if (s->ctor) -+ s->ctor(object); - } - /* If object's reuse doesn't have to be delayed */ - if (!slab_free_hook(s, object)) { -@@ -1580,6 +1581,17 @@ static inline bool slab_free_freelist_hook(struct kmem_cache *s, - *head = object; - if (!*tail) - *tail = object; -+ } else if (slab_want_init_on_free(s) && s->ctor) { -+ /* Objects that are put into quarantine by KASAN will -+ * still undergo free_consistency_checks() and thus -+ * need to show a valid freepointer to check_object(). -+ * -+ * Note that doing this for all caches (not just ctor -+ * ones, which have s->offset != NULL)) causes a GPF, -+ * due to KASAN poisoning and the way set_freepointer() -+ * eventually dereferences the freepointer. -+ */ -+ set_freepointer(s, object, NULL); - } - } while (object != old_tail); - --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0064-slub-Add-support-for-verifying-slab-sanitization.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0064-slub-Add-support-for-verifying-slab-sanitization.patch deleted file mode 100644 index a41940a4b623..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0064-slub-Add-support-for-verifying-slab-sanitization.patch +++ /dev/null @@ -1,116 +0,0 @@ -From 256e4ff40bc4e2ecebaaa65ce1ac4a75023ba640 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Thu, 4 May 2017 15:58:57 -0400 -Subject: [PATCH 064/113] slub: Add support for verifying slab sanitization - -This is an extension to the sanitization feature in PaX for when -sacricifing more performance for security is acceptable. - -The initial version from Daniel Micay was relying on PAGE_SANITIZE. It -now relies on upstream's init_on_free. - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> -Signed-off-by: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr> -Signed-off-by: Levente Polyak <levente@leventepolyak.net> ---- - mm/slub.c | 36 ++++++++++++++++++++++++++++++++---- - security/Kconfig.hardening | 8 ++++++++ - 2 files changed, 40 insertions(+), 4 deletions(-) - -diff --git a/mm/slub.c b/mm/slub.c -index ac22d6831b9b..e8e0efa18bd3 100644 ---- a/mm/slub.c -+++ b/mm/slub.c -@@ -127,6 +127,12 @@ static inline bool kmem_cache_debug(struct kmem_cache *s) - return kmem_cache_debug_flags(s, SLAB_DEBUG_FLAGS); - } - -+static inline bool has_sanitize_verify(struct kmem_cache *s) -+{ -+ return IS_ENABLED(CONFIG_SLAB_SANITIZE_VERIFY) && -+ slab_want_init_on_free(s); -+} -+ - void *fixup_red_left(struct kmem_cache *s, void *p) - { - if (kmem_cache_debug_flags(s, SLAB_RED_ZONE)) -@@ -1571,7 +1577,7 @@ static inline bool slab_free_freelist_hook(struct kmem_cache *s, - : 0; - memset((char *)object + s->inuse, 0, - s->size - s->inuse - rsize); -- if (s->ctor) -+ if (!IS_ENABLED(CONFIG_SLAB_SANITIZE_VERIFY) && s->ctor) - s->ctor(object); - } - /* If object's reuse doesn't have to be delayed */ -@@ -1606,7 +1612,7 @@ static void *setup_object(struct kmem_cache *s, struct page *page, - { - setup_object_debug(s, page, object); - object = kasan_init_slab_obj(s, object); -- if (unlikely(s->ctor)) { -+ if (unlikely(s->ctor) && !has_sanitize_verify(s)) { - kasan_unpoison_object_data(s, object); - s->ctor(object); - kasan_poison_object_data(s, object); -@@ -2897,7 +2903,16 @@ static __always_inline void *slab_alloc_node(struct kmem_cache *s, - - maybe_wipe_obj_freeptr(s, object); - -- if (unlikely(slab_want_init_on_alloc(gfpflags, s)) && object) -+ if (has_sanitize_verify(s) && object) { -+ /* KASAN hasn't unpoisoned the object yet (this is done in the -+ * post-alloc hook), so let's do it temporarily. -+ */ -+ kasan_unpoison_object_data(s, object); -+ BUG_ON(memchr_inv(object, 0, s->object_size)); -+ if (s->ctor) -+ s->ctor(object); -+ kasan_poison_object_data(s, object); -+ } else if (unlikely(slab_want_init_on_alloc(gfpflags, s)) && object) - memset(object, 0, s->object_size); - - slab_post_alloc_hook(s, objcg, gfpflags, 1, &object); -@@ -3337,7 +3352,20 @@ int kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size, - local_irq_enable(); - - /* Clear memory outside IRQ disabled fastpath loop */ -- if (unlikely(slab_want_init_on_alloc(flags, s))) { -+ if (has_sanitize_verify(s)) { -+ int j; -+ -+ for (j = 0; j < i; j++) { -+ /* KASAN hasn't unpoisoned the object yet (this is done -+ * in the post-alloc hook), so let's do it temporarily. -+ */ -+ kasan_unpoison_object_data(s, p[j]); -+ BUG_ON(memchr_inv(p[j], 0, s->object_size)); -+ if (s->ctor) -+ s->ctor(p[j]); -+ kasan_poison_object_data(s, p[j]); -+ } -+ } else if (unlikely(slab_want_init_on_alloc(flags, s))) { - int j; - - for (j = 0; j < i; j++) -diff --git a/security/Kconfig.hardening b/security/Kconfig.hardening -index 83ad70ae6bc3..7dede18f1074 100644 ---- a/security/Kconfig.hardening -+++ b/security/Kconfig.hardening -@@ -226,6 +226,14 @@ config PAGE_SANITIZE_VERIFY - When init_on_free is enabled, verify that newly allocated pages - are zeroed to detect write-after-free bugs. - -+config SLAB_SANITIZE_VERIFY -+ bool "Verify sanitized SLAB allocations" -+ default y -+ depends on !KASAN -+ help -+ When init_on_free is enabled, verify that newly allocated slab -+ objects are zeroed to detect write-after-free bugs. -+ - endmenu - - endmenu --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0065-slub-add-multi-purpose-random-canaries.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0065-slub-add-multi-purpose-random-canaries.patch deleted file mode 100644 index 5de5c89a82b7..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0065-slub-add-multi-purpose-random-canaries.patch +++ /dev/null @@ -1,264 +0,0 @@ -From 9b9069e3779352ffa3af0924d5cdf4872b18a98c Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Wed, 3 May 2017 16:16:58 -0400 -Subject: [PATCH 065/113] slub: add multi-purpose random canaries - -From the configuration option: - - Place canaries at the end of kernel slab allocations, sacrificing - some performance and memory usage for security. - - Canaries can detect some forms of heap corruption when allocations - are freed and as part of the HARDENED_USERCOPY feature. It provides - basic use-after-free detection for HARDENED_USERCOPY. - - Canaries absorb small overflows (rendering them harmless), mitigate - non-NUL terminated C string overflows on 64-bit via a guaranteed zero - byte and provide basic double-free detection. - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - include/linux/slub_def.h | 5 +++ - init/Kconfig | 17 ++++++++++ - mm/slab.h | 2 +- - mm/slub.c | 69 ++++++++++++++++++++++++++++++++++++++-- - 4 files changed, 89 insertions(+), 4 deletions(-) - -diff --git a/include/linux/slub_def.h b/include/linux/slub_def.h -index 1be0ed5befa1..c71cf30b5987 100644 ---- a/include/linux/slub_def.h -+++ b/include/linux/slub_def.h -@@ -113,6 +113,11 @@ struct kmem_cache { - unsigned long random; - #endif - -+#ifdef CONFIG_SLAB_CANARY -+ unsigned long random_active; -+ unsigned long random_inactive; -+#endif -+ - #ifdef CONFIG_NUMA - /* - * Defragmentation by allocating from a remote node. -diff --git a/init/Kconfig b/init/Kconfig -index 58df4930995f..2af6689d9e71 100644 ---- a/init/Kconfig -+++ b/init/Kconfig -@@ -1943,6 +1943,23 @@ config SLAB_FREELIST_HARDENED - sanity-checking than others. This option is most effective with - CONFIG_SLUB. - -+config SLAB_CANARY -+ depends on SLUB -+ depends on !SLAB_MERGE_DEFAULT -+ bool "SLAB canaries" -+ default y -+ help -+ Place canaries at the end of kernel slab allocations, sacrificing -+ some performance and memory usage for security. -+ -+ Canaries can detect some forms of heap corruption when allocations -+ are freed and as part of the HARDENED_USERCOPY feature. It provides -+ basic use-after-free detection for HARDENED_USERCOPY. -+ -+ Canaries absorb small overflows (rendering them harmless), mitigate -+ non-NUL terminated C string overflows on 64-bit via a guaranteed zero -+ byte and provide basic double-free detection. -+ - config SHUFFLE_PAGE_ALLOCATOR - bool "Page allocator randomization" - default SLAB_FREELIST_RANDOM && ACPI_NUMA -diff --git a/mm/slab.h b/mm/slab.h -index 0fcd97a4eb6f..105dba485a7e 100644 ---- a/mm/slab.h -+++ b/mm/slab.h -@@ -504,7 +504,7 @@ static inline size_t slab_ksize(const struct kmem_cache *s) - * back there or track user information then we can - * only use the space before that information. - */ -- if (s->flags & (SLAB_TYPESAFE_BY_RCU | SLAB_STORE_USER)) -+ if ((s->flags & (SLAB_TYPESAFE_BY_RCU | SLAB_STORE_USER)) || IS_ENABLED(CONFIG_SLAB_CANARY)) - return s->inuse; - /* - * Else we can use all the padding etc for the allocation -diff --git a/mm/slub.c b/mm/slub.c -index e8e0efa18bd3..dd68308c94a9 100644 ---- a/mm/slub.c -+++ b/mm/slub.c -@@ -569,6 +569,33 @@ static inline unsigned int get_info_end(struct kmem_cache *s) - return s->inuse; - } - -+#ifdef CONFIG_SLAB_CANARY -+static inline unsigned long *get_canary(struct kmem_cache *s, void *object) -+{ -+ return object + get_info_end(s); -+} -+ -+static inline unsigned long get_canary_value(const void *canary, unsigned long value) -+{ -+ return (value ^ (unsigned long)canary) & CANARY_MASK; -+} -+ -+static inline void set_canary(struct kmem_cache *s, void *object, unsigned long value) -+{ -+ unsigned long *canary = get_canary(s, object); -+ *canary = get_canary_value(canary, value); -+} -+ -+static inline void check_canary(struct kmem_cache *s, void *object, unsigned long value) -+{ -+ unsigned long *canary = get_canary(s, object); -+ BUG_ON(*canary != get_canary_value(canary, value)); -+} -+#else -+#define set_canary(s, object, value) -+#define check_canary(s, object, value) -+#endif -+ - static struct track *get_track(struct kmem_cache *s, void *object, - enum track_item alloc) - { -@@ -576,6 +603,9 @@ static struct track *get_track(struct kmem_cache *s, void *object, - - p = object + get_info_end(s); - -+ if (IS_ENABLED(CONFIG_SLAB_CANARY)) -+ p = (void *)p + sizeof(void *); -+ - return p + alloc; - } - -@@ -717,6 +747,9 @@ static void print_trailer(struct kmem_cache *s, struct page *page, u8 *p) - - off = get_info_end(s); - -+ if (IS_ENABLED(CONFIG_SLAB_CANARY)) -+ off += sizeof(void *); -+ - if (s->flags & SLAB_STORE_USER) - off += 2 * sizeof(struct track); - -@@ -825,8 +858,9 @@ static int check_bytes_and_report(struct kmem_cache *s, struct page *page, - * Meta data starts here. - * - * A. Free pointer (if we cannot overwrite object on free) -- * B. Tracking data for SLAB_STORE_USER -- * C. Padding to reach required alignment boundary or at mininum -+ * B. Canary for SLAB_CANARY -+ * C. Tracking data for SLAB_STORE_USER -+ * D. Padding to reach required alignment boundary or at mininum - * one word if debugging is on to be able to detect writes - * before the word boundary. - * -@@ -844,6 +878,9 @@ static int check_pad_bytes(struct kmem_cache *s, struct page *page, u8 *p) - { - unsigned long off = get_info_end(s); /* The end of info */ - -+ if (IS_ENABLED(CONFIG_SLAB_CANARY)) -+ off += sizeof(void *); -+ - if (s->flags & SLAB_STORE_USER) - /* We also have user information there */ - off += 2 * sizeof(struct track); -@@ -1567,6 +1604,8 @@ static inline bool slab_free_freelist_hook(struct kmem_cache *s, - object = next; - next = get_freepointer(s, object); - -+ check_canary(s, object, s->random_active); -+ - if (slab_want_init_on_free(s)) { - /* - * Clear the object and the metadata, but don't touch -@@ -1580,6 +1619,9 @@ static inline bool slab_free_freelist_hook(struct kmem_cache *s, - if (!IS_ENABLED(CONFIG_SLAB_SANITIZE_VERIFY) && s->ctor) - s->ctor(object); - } -+ -+ set_canary(s, object, s->random_inactive); -+ - /* If object's reuse doesn't have to be delayed */ - if (!slab_free_hook(s, object)) { - /* Move object to the new freelist */ -@@ -1611,6 +1653,7 @@ static void *setup_object(struct kmem_cache *s, struct page *page, - void *object) - { - setup_object_debug(s, page, object); -+ set_canary(s, object, s->random_inactive); - object = kasan_init_slab_obj(s, object); - if (unlikely(s->ctor) && !has_sanitize_verify(s)) { - kasan_unpoison_object_data(s, object); -@@ -2915,6 +2958,11 @@ static __always_inline void *slab_alloc_node(struct kmem_cache *s, - } else if (unlikely(slab_want_init_on_alloc(gfpflags, s)) && object) - memset(object, 0, s->object_size); - -+ if (object) { -+ check_canary(s, object, s->random_inactive); -+ set_canary(s, object, s->random_active); -+ } -+ - slab_post_alloc_hook(s, objcg, gfpflags, 1, &object); - - return object; -@@ -3302,7 +3350,7 @@ int kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size, - void **p) - { - struct kmem_cache_cpu *c; -- int i; -+ int i, k; - struct obj_cgroup *objcg = NULL; - - /* memcg and kmem_cache debug support */ -@@ -3372,6 +3420,11 @@ int kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size, - memset(p[j], 0, s->object_size); - } - -+ for (k = 0; k < i; k++) { -+ check_canary(s, p[k], s->random_inactive); -+ set_canary(s, p[k], s->random_active); -+ } -+ - /* memcg and kmem_cache debug support */ - slab_post_alloc_hook(s, objcg, flags, size, p); - return i; -@@ -3573,6 +3626,7 @@ static void early_kmem_cache_node_alloc(int node) - init_object(kmem_cache_node, n, SLUB_RED_ACTIVE); - init_tracking(kmem_cache_node, n); - #endif -+ set_canary(kmem_cache_node, n, kmem_cache_node->random_active); - n = kasan_kmalloc(kmem_cache_node, n, sizeof(struct kmem_cache_node), - GFP_KERNEL); - page->freelist = get_freepointer(kmem_cache_node, n); -@@ -3753,6 +3807,9 @@ static int calculate_sizes(struct kmem_cache *s, int forced_order) - s->offset = ALIGN(freepointer_area / 2, sizeof(void *)); - } - -+ if (IS_ENABLED(CONFIG_SLAB_CANARY)) -+ size += sizeof(void *); -+ - #ifdef CONFIG_SLUB_DEBUG - if (flags & SLAB_STORE_USER) - /* -@@ -3826,6 +3883,10 @@ static int kmem_cache_open(struct kmem_cache *s, slab_flags_t flags) - #ifdef CONFIG_SLAB_FREELIST_HARDENED - s->random = get_random_long(); - #endif -+#ifdef CONFIG_SLAB_CANARY -+ s->random_active = get_random_long(); -+ s->random_inactive = get_random_long(); -+#endif - - if (!calculate_sizes(s, -1)) - goto error; -@@ -4099,6 +4160,8 @@ void __check_heap_object(const void *ptr, unsigned long n, struct page *page, - offset -= s->red_left_pad; - } - -+ check_canary(s, (void *)ptr - offset, s->random_active); -+ - /* Allow address range falling entirely within usercopy region. */ - if (offset >= s->useroffset && - offset - s->useroffset <= s->usersize && --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0066-security-perf-Allow-further-restriction-of-perf_even.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0066-security-perf-Allow-further-restriction-of-perf_even.patch deleted file mode 100644 index 7190b5b3633a..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0066-security-perf-Allow-further-restriction-of-perf_even.patch +++ /dev/null @@ -1,122 +0,0 @@ -From e5033a4e93fe0ac2545f62f0128cd73fcc31d881 Mon Sep 17 00:00:00 2001 -From: Ben Hutchings <ben@decadent.org.uk> -Date: Mon, 11 Jan 2016 15:23:55 +0000 -Subject: [PATCH 066/113] security,perf: Allow further restriction of - perf_event_open - -When kernel.perf_event_open is set to 3 (or greater), disallow all -access to performance events by users without CAP_SYS_ADMIN. -Add a Kconfig symbol CONFIG_SECURITY_PERF_EVENTS_RESTRICT that -makes this value the default. - -This is based on a similar feature in grsecurity -(CONFIG_GRKERNSEC_PERF_HARDEN). This version doesn't include making -the variable read-only. It also allows enabling further restriction -at run-time regardless of whether the default is changed. - -Signed-off-by: Ben Hutchings <ben@decadent.org.uk> -Signed-off-by: Levente Polyak <levente@leventepolyak.net> -[thibaut.sautereau@ssi.gouv.fr: Adapt to work with the new CAP_PERFMON capability] -Signed-off-by: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr> ---- - Documentation/admin-guide/sysctl/kernel.rst | 2 ++ - include/linux/perf_event.h | 8 ++++++++ - kernel/events/core.c | 7 ++++++- - security/Kconfig | 9 +++++++++ - tools/perf/Documentation/security.txt | 1 + - 5 files changed, 26 insertions(+), 1 deletion(-) - -diff --git a/Documentation/admin-guide/sysctl/kernel.rst b/Documentation/admin-guide/sysctl/kernel.rst -index d4b32cc32bb7..4c20e6ded0af 100644 ---- a/Documentation/admin-guide/sysctl/kernel.rst -+++ b/Documentation/admin-guide/sysctl/kernel.rst -@@ -860,6 +860,8 @@ with respect to CAP_PERFMON use cases. - >=1 Disallow CPU event access by users without ``CAP_PERFMON``. - - >=2 Disallow kernel profiling by users without ``CAP_PERFMON``. -+ -+>=3 Disallow use of any event by users without ``CAP_PERFMON``. - === ================================================================== - - -diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h -index 96450f6fb1de..d020c26b612a 100644 ---- a/include/linux/perf_event.h -+++ b/include/linux/perf_event.h -@@ -1312,6 +1312,14 @@ static inline int perf_is_paranoid(void) - return sysctl_perf_event_paranoid > -1; - } - -+static inline int perf_allow_open(struct perf_event_attr *attr) -+{ -+ if (sysctl_perf_event_paranoid > 2 && !perfmon_capable()) -+ return -EACCES; -+ -+ return security_perf_event_open(attr, PERF_SECURITY_OPEN); -+} -+ - static inline int perf_allow_kernel(struct perf_event_attr *attr) - { - if (sysctl_perf_event_paranoid > 1 && !perfmon_capable()) -diff --git a/kernel/events/core.c b/kernel/events/core.c -index c3ba29d058b7..6efbf92763b1 100644 ---- a/kernel/events/core.c -+++ b/kernel/events/core.c -@@ -407,8 +407,13 @@ static cpumask_var_t perf_online_mask; - * 0 - disallow raw tracepoint access for unpriv - * 1 - disallow cpu events for unpriv - * 2 - disallow kernel profiling for unpriv -+ * 3 - disallow all unpriv perf event use - */ -+#ifdef CONFIG_SECURITY_PERF_EVENTS_RESTRICT -+int sysctl_perf_event_paranoid __read_mostly = 3; -+#else - int sysctl_perf_event_paranoid __read_mostly = 2; -+#endif - - /* Minimum for 512 kiB + 1 user control page */ - int sysctl_perf_event_mlock __read_mostly = 512 + (PAGE_SIZE / 1024); /* 'free' kiB per user */ -@@ -11638,7 +11643,7 @@ SYSCALL_DEFINE5(perf_event_open, - return -EINVAL; - - /* Do we allow access to perf_event_open(2) ? */ -- err = security_perf_event_open(&attr, PERF_SECURITY_OPEN); -+ err = perf_allow_open(&attr); - if (err) - return err; - -diff --git a/security/Kconfig b/security/Kconfig -index 81d0a08736aa..c797326308f1 100644 ---- a/security/Kconfig -+++ b/security/Kconfig -@@ -19,6 +19,15 @@ config SECURITY_DMESG_RESTRICT - - If you are unsure how to answer this question, answer N. - -+config SECURITY_PERF_EVENTS_RESTRICT -+ bool "Restrict unprivileged use of performance events" -+ depends on PERF_EVENTS -+ help -+ If you say Y here, the kernel.perf_event_paranoid sysctl -+ will be set to 3 by default, and no unprivileged use of the -+ perf_event_open syscall will be permitted unless it is -+ changed. -+ - config SECURITY - bool "Enable different security models" - depends on SYSFS -diff --git a/tools/perf/Documentation/security.txt b/tools/perf/Documentation/security.txt -index 4fe3b8b1958f..a7d88cc23a70 100644 ---- a/tools/perf/Documentation/security.txt -+++ b/tools/perf/Documentation/security.txt -@@ -148,6 +148,7 @@ Perf tool provides a message similar to the one below: - >= 0: Disallow raw and ftrace function tracepoint access - >= 1: Disallow CPU event access - >= 2: Disallow kernel profiling -+ >= 3: Disallow use of any event - To make the adjusted perf_event_paranoid setting permanent preserve it - in /etc/sysctl.conf (e.g. kernel.perf_event_paranoid = <setting>) - --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0067-enable-SECURITY_PERF_EVENTS_RESTRICT-by-default.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0067-enable-SECURITY_PERF_EVENTS_RESTRICT-by-default.patch deleted file mode 100644 index 8c8164d310b4..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0067-enable-SECURITY_PERF_EVENTS_RESTRICT-by-default.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 14e62a087b59ccd0dcfd1ad1cb2c5457293be04b Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Thu, 4 May 2017 14:45:59 -0400 -Subject: [PATCH 067/113] enable SECURITY_PERF_EVENTS_RESTRICT by default - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - security/Kconfig | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/security/Kconfig b/security/Kconfig -index c797326308f1..2348ff7d4e1d 100644 ---- a/security/Kconfig -+++ b/security/Kconfig -@@ -22,6 +22,7 @@ config SECURITY_DMESG_RESTRICT - config SECURITY_PERF_EVENTS_RESTRICT - bool "Restrict unprivileged use of performance events" - depends on PERF_EVENTS -+ default y - help - If you say Y here, the kernel.perf_event_paranoid sysctl - will be set to 3 by default, and no unprivileged use of the --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0068-add-sysctl-to-disallow-unprivileged-CLONE_NEWUSER-by.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0068-add-sysctl-to-disallow-unprivileged-CLONE_NEWUSER-by.patch deleted file mode 100644 index 3eb0b769394b..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0068-add-sysctl-to-disallow-unprivileged-CLONE_NEWUSER-by.patch +++ /dev/null @@ -1,124 +0,0 @@ -From bc3a02af3affde290739e6cd6a41f7a15f1e2368 Mon Sep 17 00:00:00 2001 -From: Serge Hallyn <serge.hallyn@canonical.com> -Date: Fri, 31 May 2013 19:12:12 +0100 -Subject: [PATCH 068/113] add sysctl to disallow unprivileged CLONE_NEWUSER by - default - -Signed-off-by: Serge Hallyn <serge.hallyn@ubuntu.com> -[bwh: Remove unneeded binary sysctl bits] -Signed-off-by: Daniel Micay <danielmicay@gmail.com> -[thibaut.sautereau@ssi.gouv.fr: Adapt to sysctl code refactoring] -Signed-off-by: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr> -Signed-off-by: Levente Polyak <levente@leventepolyak.net> ---- - include/linux/user_namespace.h | 4 ++++ - kernel/fork.c | 11 +++++++++++ - kernel/sysctl.c | 12 ++++++++++++ - kernel/user_namespace.c | 3 +++ - 4 files changed, 30 insertions(+) - -diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h -index 6ef1c7109fc4..2140091b0b8d 100644 ---- a/include/linux/user_namespace.h -+++ b/include/linux/user_namespace.h -@@ -106,6 +106,8 @@ void dec_ucount(struct ucounts *ucounts, enum ucount_type type); - - #ifdef CONFIG_USER_NS - -+extern int unprivileged_userns_clone; -+ - static inline struct user_namespace *get_user_ns(struct user_namespace *ns) - { - if (ns) -@@ -139,6 +141,8 @@ extern bool current_in_userns(const struct user_namespace *target_ns); - struct ns_common *ns_get_owner(struct ns_common *ns); - #else - -+#define unprivileged_userns_clone 0 -+ - static inline struct user_namespace *get_user_ns(struct user_namespace *ns) - { - return &init_user_ns; -diff --git a/kernel/fork.c b/kernel/fork.c -index c675fdbd3dce..cba344194fba 100644 ---- a/kernel/fork.c -+++ b/kernel/fork.c -@@ -82,6 +82,7 @@ - #include <linux/perf_event.h> - #include <linux/posix-timers.h> - #include <linux/user-return-notifier.h> -+#include <linux/user_namespace.h> - #include <linux/oom.h> - #include <linux/khugepaged.h> - #include <linux/signalfd.h> -@@ -1863,6 +1864,10 @@ static __latent_entropy struct task_struct *copy_process( - if ((clone_flags & (CLONE_NEWUSER|CLONE_FS)) == (CLONE_NEWUSER|CLONE_FS)) - return ERR_PTR(-EINVAL); - -+ if ((clone_flags & CLONE_NEWUSER) && !unprivileged_userns_clone) -+ if (!capable(CAP_SYS_ADMIN)) -+ return ERR_PTR(-EPERM); -+ - /* - * Thread groups must share signals as well, and detached threads - * can only be started up within the thread group. -@@ -2928,6 +2933,12 @@ int ksys_unshare(unsigned long unshare_flags) - if (unshare_flags & CLONE_NEWNS) - unshare_flags |= CLONE_FS; - -+ if ((unshare_flags & CLONE_NEWUSER) && !unprivileged_userns_clone) { -+ err = -EPERM; -+ if (!capable(CAP_SYS_ADMIN)) -+ goto bad_unshare_out; -+ } -+ - err = check_unshare_flags(unshare_flags); - if (err) - goto bad_unshare_out; -diff --git a/kernel/sysctl.c b/kernel/sysctl.c -index b2cd3dbbb17a..fccf24a08c8a 100644 ---- a/kernel/sysctl.c -+++ b/kernel/sysctl.c -@@ -103,6 +103,9 @@ - #ifdef CONFIG_LOCKUP_DETECTOR - #include <linux/nmi.h> - #endif -+#ifdef CONFIG_USER_NS -+#include <linux/user_namespace.h> -+#endif - - #if defined(CONFIG_SYSCTL) - -@@ -1902,6 +1905,15 @@ static struct ctl_table kern_table[] = { - .proc_handler = proc_dointvec, - }, - #endif -+#ifdef CONFIG_USER_NS -+ { -+ .procname = "unprivileged_userns_clone", -+ .data = &unprivileged_userns_clone, -+ .maxlen = sizeof(int), -+ .mode = 0644, -+ .proc_handler = proc_dointvec, -+ }, -+#endif - #ifdef CONFIG_PROC_SYSCTL - { - .procname = "tainted", -diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c -index e703d5d9cbe8..29a30cff5e60 100644 ---- a/kernel/user_namespace.c -+++ b/kernel/user_namespace.c -@@ -21,6 +21,9 @@ - #include <linux/bsearch.h> - #include <linux/sort.h> - -+/* sysctl */ -+int unprivileged_userns_clone; -+ - static struct kmem_cache *user_ns_cachep __read_mostly; - static DEFINE_MUTEX(userns_state_mutex); - --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0069-add-CONFIG-for-unprivileged_userns_clone.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0069-add-CONFIG-for-unprivileged_userns_clone.patch deleted file mode 100644 index 50986719a95d..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0069-add-CONFIG-for-unprivileged_userns_clone.patch +++ /dev/null @@ -1,66 +0,0 @@ -From 3c3622cd06c8e430aa1aed6b1dd6cb763b3e2e44 Mon Sep 17 00:00:00 2001 -From: Levente Polyak <levente@leventepolyak.net> -Date: Wed, 31 Jul 2019 20:50:48 +0100 -Subject: [PATCH 069/113] add CONFIG for unprivileged_userns_clone - -When disabled, unprivileged users will not be able to create -new namespaces. Allowing users to create their own namespaces -has been part of several recent local privilege escalation -exploits, so if you need user namespaces but are -paranoid^Wsecurity-conscious you want to disable this. - -By default unprivileged user namespaces are disabled. - -Authored-by: Jan Alexander Steffens (heftig) <jan.steffens@gmail.com> -Edited-by: Levente Polyak (anthraxx) <levente@leventepolyak.net> ---- - init/Kconfig | 16 ++++++++++++++++ - kernel/user_namespace.c | 4 ++++ - 2 files changed, 20 insertions(+) - -diff --git a/init/Kconfig b/init/Kconfig -index 2af6689d9e71..a7b5a4cb7939 100644 ---- a/init/Kconfig -+++ b/init/Kconfig -@@ -1174,6 +1174,22 @@ config USER_NS - - If unsure, say N. - -+config USER_NS_UNPRIVILEGED -+ bool "Allow unprivileged users to create namespaces" -+ depends on USER_NS -+ default n -+ help -+ When disabled, unprivileged users will not be able to create -+ new namespaces. Allowing users to create their own namespaces -+ has been part of several recent local privilege escalation -+ exploits, so if you need user namespaces but are -+ paranoid^Wsecurity-conscious you want to disable this. -+ -+ This setting can be overridden at runtime via the -+ kernel.unprivileged_userns_clone sysctl. -+ -+ If unsure, say N. -+ - config PID_NS - bool "PID Namespaces" - default y -diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c -index 29a30cff5e60..5758274feaee 100644 ---- a/kernel/user_namespace.c -+++ b/kernel/user_namespace.c -@@ -22,7 +22,11 @@ - #include <linux/sort.h> - - /* sysctl */ -+#ifdef CONFIG_USER_NS_UNPRIVILEGED -+int unprivileged_userns_clone = 1; -+#else - int unprivileged_userns_clone; -+#endif - - static struct kmem_cache *user_ns_cachep __read_mostly; - static DEFINE_MUTEX(userns_state_mutex); --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0070-add-kmalloc-krealloc-alloc_size-attributes.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0070-add-kmalloc-krealloc-alloc_size-attributes.patch deleted file mode 100644 index 89456f360c34..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0070-add-kmalloc-krealloc-alloc_size-attributes.patch +++ /dev/null @@ -1,65 +0,0 @@ -From 941b4478a3e32204eec70e073a1a00fe3a8ef266 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Wed, 3 May 2017 12:02:56 -0400 -Subject: [PATCH 070/113] add kmalloc/krealloc alloc_size attributes - -Note that this is overly strict when combined with ksize users accessing -beyond the requested data size. - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - include/linux/slab.h | 10 +++++----- - 1 file changed, 5 insertions(+), 5 deletions(-) - -diff --git a/include/linux/slab.h b/include/linux/slab.h -index dd6897f62010..78f99835b91b 100644 ---- a/include/linux/slab.h -+++ b/include/linux/slab.h -@@ -181,7 +181,7 @@ int kmem_cache_shrink(struct kmem_cache *); - /* - * Common kmalloc functions provided by all allocators - */ --void * __must_check krealloc(const void *, size_t, gfp_t); -+void * __must_check krealloc(const void *, size_t, gfp_t) __attribute((alloc_size(2))); - void kfree(const void *); - void kfree_sensitive(const void *); - size_t __ksize(const void *); -@@ -386,7 +386,7 @@ static __always_inline unsigned int kmalloc_index(size_t size) - } - #endif /* !CONFIG_SLOB */ - --void *__kmalloc(size_t size, gfp_t flags) __assume_kmalloc_alignment __malloc; -+void *__kmalloc(size_t size, gfp_t flags) __assume_kmalloc_alignment __malloc __attribute__((alloc_size(1))); - void *kmem_cache_alloc(struct kmem_cache *, gfp_t flags) __assume_slab_alignment __malloc; - void kmem_cache_free(struct kmem_cache *, void *); - -@@ -410,7 +410,7 @@ static __always_inline void kfree_bulk(size_t size, void **p) - } - - #ifdef CONFIG_NUMA --void *__kmalloc_node(size_t size, gfp_t flags, int node) __assume_kmalloc_alignment __malloc; -+void *__kmalloc_node(size_t size, gfp_t flags, int node) __assume_kmalloc_alignment __malloc __attribute__((alloc_size(1))); - void *kmem_cache_alloc_node(struct kmem_cache *, gfp_t flags, int node) __assume_slab_alignment __malloc; - #else - static __always_inline void *__kmalloc_node(size_t size, gfp_t flags, int node) -@@ -535,7 +535,7 @@ static __always_inline void *kmalloc_large(size_t size, gfp_t flags) - * Try really hard to succeed the allocation but fail - * eventually. - */ --static __always_inline void *kmalloc(size_t size, gfp_t flags) -+static __always_inline __attribute__((alloc_size(1))) void *kmalloc(size_t size, gfp_t flags) - { - if (__builtin_constant_p(size)) { - #ifndef CONFIG_SLOB -@@ -557,7 +557,7 @@ static __always_inline void *kmalloc(size_t size, gfp_t flags) - return __kmalloc(size, flags); - } - --static __always_inline void *kmalloc_node(size_t size, gfp_t flags, int node) -+static __always_inline __attribute__((alloc_size(1))) void *kmalloc_node(size_t size, gfp_t flags, int node) - { - #ifndef CONFIG_SLOB - if (__builtin_constant_p(size) && --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0071-add-vmalloc-alloc_size-attributes.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0071-add-vmalloc-alloc_size-attributes.patch deleted file mode 100644 index 4fe354ad08cd..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0071-add-vmalloc-alloc_size-attributes.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 7b72861a9f6de49ad511e2619fa7aaa92f9cda93 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Wed, 3 May 2017 12:04:03 -0400 -Subject: [PATCH 071/113] add vmalloc alloc_size attributes - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> -Signed-off-by: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr> -Signed-off-by: Levente Polyak <levente@leventepolyak.net> ---- - include/linux/vmalloc.h | 18 +++++++++--------- - 1 file changed, 9 insertions(+), 9 deletions(-) - -diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h -index 938eaf9517e2..7c069063c20d 100644 ---- a/include/linux/vmalloc.h -+++ b/include/linux/vmalloc.h -@@ -102,18 +102,18 @@ static inline void vmalloc_init(void) - static inline unsigned long vmalloc_nr_pages(void) { return 0; } - #endif - --extern void *vmalloc(unsigned long size); --extern void *vzalloc(unsigned long size); --extern void *vmalloc_user(unsigned long size); --extern void *vmalloc_node(unsigned long size, int node); --extern void *vzalloc_node(unsigned long size, int node); --extern void *vmalloc_32(unsigned long size); --extern void *vmalloc_32_user(unsigned long size); --extern void *__vmalloc(unsigned long size, gfp_t gfp_mask); -+extern void *vmalloc(unsigned long size) __attribute__((alloc_size(1))); -+extern void *vzalloc(unsigned long size) __attribute__((alloc_size(1))); -+extern void *vmalloc_user(unsigned long size) __attribute__((alloc_size(1))); -+extern void *vmalloc_node(unsigned long size, int node) __attribute__((alloc_size(1))); -+extern void *vzalloc_node(unsigned long size, int node) __attribute__((alloc_size(1))); -+extern void *vmalloc_32(unsigned long size) __attribute__((alloc_size(1))); -+extern void *vmalloc_32_user(unsigned long size) __attribute__((alloc_size(1))); -+extern void *__vmalloc(unsigned long size, gfp_t gfp_mask) __attribute__((alloc_size(1))); - extern void *__vmalloc_node_range(unsigned long size, unsigned long align, - unsigned long start, unsigned long end, gfp_t gfp_mask, - pgprot_t prot, unsigned long vm_flags, int node, -- const void *caller); -+ const void *caller) __attribute__((alloc_size(1))); - void *__vmalloc_node(unsigned long size, unsigned long align, gfp_t gfp_mask, - int node, const void *caller); - --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0072-add-kvmalloc-alloc_size-attribute.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0072-add-kvmalloc-alloc_size-attribute.patch deleted file mode 100644 index df711dded1d5..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0072-add-kvmalloc-alloc_size-attribute.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 2deb1d273cf03c7c4327ced90feb26414e0d0f13 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Tue, 4 Jul 2017 00:51:33 -0400 -Subject: [PATCH 072/113] add kvmalloc alloc_size attribute - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - include/linux/mm.h | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/include/linux/mm.h b/include/linux/mm.h -index cd5c313729ea..746f6d05bd81 100644 ---- a/include/linux/mm.h -+++ b/include/linux/mm.h -@@ -759,7 +759,7 @@ static inline int is_vmalloc_or_module_addr(const void *x) - } - #endif - --extern void *kvmalloc_node(size_t size, gfp_t flags, int node); -+extern void *kvmalloc_node(size_t size, gfp_t flags, int node) __attribute__((alloc_size(1))); - static inline void *kvmalloc(size_t size, gfp_t flags) - { - return kvmalloc_node(size, flags, NUMA_NO_NODE); --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0073-add-percpu-alloc_size-attributes.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0073-add-percpu-alloc_size-attributes.patch deleted file mode 100644 index 03ded158dc09..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0073-add-percpu-alloc_size-attributes.patch +++ /dev/null @@ -1,37 +0,0 @@ -From d3ccee2b1a9f4cbb8c05a17218473517198bb36b Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Sun, 14 May 2017 16:39:36 -0400 -Subject: [PATCH 073/113] add percpu alloc_size attributes - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - include/linux/percpu.h | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/include/linux/percpu.h b/include/linux/percpu.h -index 5e76af742c80..9a6c682ec127 100644 ---- a/include/linux/percpu.h -+++ b/include/linux/percpu.h -@@ -123,7 +123,7 @@ extern int __init pcpu_page_first_chunk(size_t reserved_size, - pcpu_fc_populate_pte_fn_t populate_pte_fn); - #endif - --extern void __percpu *__alloc_reserved_percpu(size_t size, size_t align); -+extern void __percpu *__alloc_reserved_percpu(size_t size, size_t align) __attribute__((alloc_size(1))); - extern bool __is_kernel_percpu_address(unsigned long addr, unsigned long *can_addr); - extern bool is_kernel_percpu_address(unsigned long addr); - -@@ -131,8 +131,8 @@ extern bool is_kernel_percpu_address(unsigned long addr); - extern void __init setup_per_cpu_areas(void); - #endif - --extern void __percpu *__alloc_percpu_gfp(size_t size, size_t align, gfp_t gfp); --extern void __percpu *__alloc_percpu(size_t size, size_t align); -+extern void __percpu *__alloc_percpu_gfp(size_t size, size_t align, gfp_t gfp) __attribute__((alloc_size(1))); -+extern void __percpu *__alloc_percpu(size_t size, size_t align) __attribute__((alloc_size(1))); - extern void free_percpu(void __percpu *__pdata); - extern phys_addr_t per_cpu_ptr_to_phys(void *addr); - --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0074-add-alloc_pages_exact-alloc_size-attributes.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0074-add-alloc_pages_exact-alloc_size-attributes.patch deleted file mode 100644 index f6328965bc7d..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0074-add-alloc_pages_exact-alloc_size-attributes.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 87ee060c78b634403773380d8046842edf106c22 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Sun, 14 May 2017 16:53:59 -0400 -Subject: [PATCH 074/113] add alloc_pages_exact alloc_size attributes - -Edited-by: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr> -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - include/linux/gfp.h | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/include/linux/gfp.h b/include/linux/gfp.h -index c603237e006c..893378b0262e 100644 ---- a/include/linux/gfp.h -+++ b/include/linux/gfp.h -@@ -568,9 +568,9 @@ static inline struct page *alloc_pages(gfp_t gfp_mask, unsigned int order) - extern unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order); - extern unsigned long get_zeroed_page(gfp_t gfp_mask); - --void *alloc_pages_exact(size_t size, gfp_t gfp_mask); -+void *alloc_pages_exact(size_t size, gfp_t gfp_mask) __attribute__((alloc_size(1))); - void free_pages_exact(void *virt, size_t size); --void * __meminit alloc_pages_exact_nid(int nid, size_t size, gfp_t gfp_mask); -+void * __meminit alloc_pages_exact_nid(int nid, size_t size, gfp_t gfp_mask) __attribute__((alloc_size(2))); - - #define __get_free_page(gfp_mask) \ - __get_free_pages((gfp_mask), 0) --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0075-Add-the-extra_latent_entropy-kernel-parameter.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0075-Add-the-extra_latent_entropy-kernel-parameter.patch deleted file mode 100644 index 4fb5343298c9..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0075-Add-the-extra_latent_entropy-kernel-parameter.patch +++ /dev/null @@ -1,104 +0,0 @@ -From 55ba39ba2604617b16b015105f69c180944acb35 Mon Sep 17 00:00:00 2001 -From: Emese Revfy <re.emese@gmail.com> -Date: Tue, 31 May 2016 01:34:02 +0200 -Subject: [PATCH 075/113] Add the extra_latent_entropy kernel parameter - -When extra_latent_entropy is passed on the kernel command line, -entropy will be extracted from up to the first 4GB of RAM while the -runtime memory allocator is being initialized. - -Based on work created by the PaX Team. - -Signed-off-by: Emese Revfy <re.emese@gmail.com> -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - .../admin-guide/kernel-parameters.txt | 5 ++++ - mm/page_alloc.c | 25 +++++++++++++++++++ - scripts/gcc-plugins/Kconfig | 5 ++++ - 3 files changed, 35 insertions(+) - -diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt -index 26bfe7ae711b..e7ea794320e8 100644 ---- a/Documentation/admin-guide/kernel-parameters.txt -+++ b/Documentation/admin-guide/kernel-parameters.txt -@@ -3566,6 +3566,11 @@ - the specified number of seconds. This is to be used if - your oopses keep scrolling off the screen. - -+ extra_latent_entropy -+ Enable a very simple form of latent entropy extraction -+ from the first 4GB of memory as the bootmem allocator -+ passes the memory pages to the buddy allocator. -+ - pcbit= [HW,ISDN] - - pcd. [PARIDE] -diff --git a/mm/page_alloc.c b/mm/page_alloc.c -index e014e6df1f39..965d49be78ed 100644 ---- a/mm/page_alloc.c -+++ b/mm/page_alloc.c -@@ -70,6 +70,7 @@ - #include <linux/psi.h> - #include <linux/padata.h> - #include <linux/khugepaged.h> -+#include <linux/random.h> - - #include <asm/sections.h> - #include <asm/tlbflush.h> -@@ -136,6 +137,15 @@ struct pcpu_drain { - static DEFINE_MUTEX(pcpu_drain_mutex); - static DEFINE_PER_CPU(struct pcpu_drain, pcpu_drain); - -+bool __meminitdata extra_latent_entropy; -+ -+static int __init setup_extra_latent_entropy(char *str) -+{ -+ extra_latent_entropy = true; -+ return 0; -+} -+early_param("extra_latent_entropy", setup_extra_latent_entropy); -+ - #ifdef CONFIG_GCC_PLUGIN_LATENT_ENTROPY - volatile unsigned long latent_entropy __latent_entropy; - EXPORT_SYMBOL(latent_entropy); -@@ -1549,6 +1559,21 @@ void __free_pages_core(struct page *page, unsigned int order) - __ClearPageReserved(p); - set_page_count(p, 0); - -+ if (extra_latent_entropy && !PageHighMem(page) && page_to_pfn(page) < 0x100000) { -+ unsigned long hash = 0; -+ size_t index, end = PAGE_SIZE * nr_pages / sizeof hash; -+ const unsigned long *data = lowmem_page_address(page); -+ -+ for (index = 0; index < end; index++) -+ hash ^= hash + data[index]; -+#ifdef CONFIG_GCC_PLUGIN_LATENT_ENTROPY -+ latent_entropy ^= hash; -+ add_device_randomness((const void *)&latent_entropy, sizeof(latent_entropy)); -+#else -+ add_device_randomness((const void *)&hash, sizeof(hash)); -+#endif -+ } -+ - atomic_long_add(nr_pages, &page_zone(page)->managed_pages); - - /* -diff --git a/scripts/gcc-plugins/Kconfig b/scripts/gcc-plugins/Kconfig -index ae19fb0243b9..ad78375ece5e 100644 ---- a/scripts/gcc-plugins/Kconfig -+++ b/scripts/gcc-plugins/Kconfig -@@ -53,6 +53,11 @@ config GCC_PLUGIN_LATENT_ENTROPY - is some slowdown of the boot process (about 0.5%) and fork and - irq processing. - -+ When extra_latent_entropy is passed on the kernel command line, -+ entropy will be extracted from up to the first 4GB of RAM while the -+ runtime memory allocator is being initialized. This costs even more -+ slowdown of the boot process. -+ - Note that entropy extracted this way is not cryptographically - secure! - --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0076-ata-avoid-null-pointer-dereference-on-bug.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0076-ata-avoid-null-pointer-dereference-on-bug.patch deleted file mode 100644 index 61b25cf9b68a..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0076-ata-avoid-null-pointer-dereference-on-bug.patch +++ /dev/null @@ -1,37 +0,0 @@ -From dc48fdd6bef9d5b8a4c38dd94d800f2df33c4f36 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Mon, 15 May 2017 23:45:34 -0400 -Subject: [PATCH 076/113] ata: avoid null pointer dereference on bug - -Extracted from PaX. - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - drivers/ata/libata-core.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c -index 61c762961ca8..02a83039c25b 100644 ---- a/drivers/ata/libata-core.c -+++ b/drivers/ata/libata-core.c -@@ -4540,7 +4540,7 @@ void ata_qc_free(struct ata_queued_cmd *qc) - struct ata_port *ap; - unsigned int tag; - -- WARN_ON_ONCE(qc == NULL); /* ata_qc_from_tag _might_ return NULL */ -+ BUG_ON(qc == NULL); /* ata_qc_from_tag _might_ return NULL */ - ap = qc->ap; - - qc->flags = 0; -@@ -4557,7 +4557,7 @@ void __ata_qc_complete(struct ata_queued_cmd *qc) - struct ata_port *ap; - struct ata_link *link; - -- WARN_ON_ONCE(qc == NULL); /* ata_qc_from_tag _might_ return NULL */ -+ BUG_ON(qc == NULL); /* ata_qc_from_tag _might_ return NULL */ - WARN_ON_ONCE(!(qc->flags & ATA_QCFLAG_ACTIVE)); - ap = qc->ap; - link = qc->dev->link; --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0077-sanity-check-for-negative-length-in-nla_memcpy.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0077-sanity-check-for-negative-length-in-nla_memcpy.patch deleted file mode 100644 index cc497e839d5f..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0077-sanity-check-for-negative-length-in-nla_memcpy.patch +++ /dev/null @@ -1,28 +0,0 @@ -From cc3ef16a957ba9036fa4c0e1efb8ce643b5b2dec Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Mon, 15 May 2017 23:51:12 -0400 -Subject: [PATCH 077/113] sanity check for negative length in nla_memcpy - -Extracted from PaX. - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - lib/nlattr.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/lib/nlattr.c b/lib/nlattr.c -index 74019c8ebf6b..c480b4e7ffef 100644 ---- a/lib/nlattr.c -+++ b/lib/nlattr.c -@@ -778,6 +778,8 @@ int nla_memcpy(void *dest, const struct nlattr *src, int count) - { - int minlen = min_t(int, count, nla_len(src)); - -+ BUG_ON(minlen < 0); -+ - memcpy(dest, nla_data(src), minlen); - if (count > minlen) - memset(dest + minlen, 0, count - minlen); --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0078-add-page-destructor-sanity-check.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0078-add-page-destructor-sanity-check.patch deleted file mode 100644 index 4b3c0cdb0439..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0078-add-page-destructor-sanity-check.patch +++ /dev/null @@ -1,71 +0,0 @@ -From 09c9b039e5be1eab1a5930f5b8fcc2468f700cdb Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Mon, 15 May 2017 23:59:18 -0400 -Subject: [PATCH 078/113] add page destructor sanity check - -Taken from the public PaX patches. - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> -[thibaut.sautereau@ssi.gouv.fr: Restore get_compound_page_dtor()] -Signed-off-by: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr> -Reviewd-by: Levente Polyak <levente@leventepolyak.net> ---- - include/linux/mm.h | 9 +++++++-- - mm/swap.c | 12 +++++++++++- - 2 files changed, 18 insertions(+), 3 deletions(-) - -diff --git a/include/linux/mm.h b/include/linux/mm.h -index 746f6d05bd81..a463ffe84eb4 100644 ---- a/include/linux/mm.h -+++ b/include/linux/mm.h -@@ -894,10 +894,15 @@ static inline void set_compound_page_dtor(struct page *page, - page[1].compound_dtor = compound_dtor; - } - --static inline void destroy_compound_page(struct page *page) -+static inline compound_page_dtor *get_compound_page_dtor(struct page *page) - { - VM_BUG_ON_PAGE(page[1].compound_dtor >= NR_COMPOUND_DTORS, page); -- compound_page_dtors[page[1].compound_dtor](page); -+ return compound_page_dtors[page[1].compound_dtor]; -+} -+ -+static inline void destroy_compound_page(struct page *page) -+{ -+ (*get_compound_page_dtor(page))(page); - } - - static inline unsigned int compound_order(struct page *page) -diff --git a/mm/swap.c b/mm/swap.c -index 47a47681c86b..762095d95092 100644 ---- a/mm/swap.c -+++ b/mm/swap.c -@@ -102,6 +102,8 @@ static void __put_single_page(struct page *page) - - static void __put_compound_page(struct page *page) - { -+ compound_page_dtor *dtor; -+ - /* - * __page_cache_release() is supposed to be called for thp, not for - * hugetlb. This is because hugetlb page does never have PageLRU set -@@ -110,7 +112,15 @@ static void __put_compound_page(struct page *page) - */ - if (!PageHuge(page)) - __page_cache_release(page); -- destroy_compound_page(page); -+ dtor = get_compound_page_dtor(page); -+ if (!PageHuge(page)) -+ BUG_ON(dtor != free_compound_page -+#ifdef CONFIG_TRANSPARENT_HUGEPAGE -+ && dtor != free_transhuge_page -+#endif -+ ); -+ -+ (*dtor)(page); - } - - void __put_page(struct page *page) --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0079-PaX-shadow-cr4-sanity-check-essentially-a-revert.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0079-PaX-shadow-cr4-sanity-check-essentially-a-revert.patch deleted file mode 100644 index f6ea840c797a..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0079-PaX-shadow-cr4-sanity-check-essentially-a-revert.patch +++ /dev/null @@ -1,52 +0,0 @@ -From 0a40e217049884e911b510d7529062716936e561 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Tue, 16 May 2017 00:59:48 -0400 -Subject: [PATCH 079/113] PaX shadow cr4 sanity check (essentially a revert) - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> -Signed-off-by: Levente Polyak <levente@leventepolyak.net> ---- - arch/x86/kernel/cpu/common.c | 1 + - arch/x86/kernel/process.c | 1 + - arch/x86/mm/tlb.c | 1 + - 3 files changed, 3 insertions(+) - -diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c -index 35ad8480c464..edaeeab9df4b 100644 ---- a/arch/x86/kernel/cpu/common.c -+++ b/arch/x86/kernel/cpu/common.c -@@ -399,6 +399,7 @@ EXPORT_SYMBOL_GPL(native_write_cr4); - void cr4_update_irqsoff(unsigned long set, unsigned long clear) - { - unsigned long newval, cr4 = this_cpu_read(cpu_tlbstate.cr4); -+ BUG_ON(cr4 != __read_cr4()); - - lockdep_assert_irqs_disabled(); - -diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c -index 145a7ac0c19a..058941e9ae40 100644 ---- a/arch/x86/kernel/process.c -+++ b/arch/x86/kernel/process.c -@@ -596,6 +596,7 @@ void speculation_ctrl_update_current(void) - static inline void cr4_toggle_bits_irqsoff(unsigned long mask) - { - unsigned long newval, cr4 = this_cpu_read(cpu_tlbstate.cr4); -+ BUG_ON(cr4 != __read_cr4()); - - newval = cr4 ^ mask; - if (newval != cr4) { -diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c -index 569ac1d57f55..044d88da4aee 100644 ---- a/arch/x86/mm/tlb.c -+++ b/arch/x86/mm/tlb.c -@@ -1066,6 +1066,7 @@ STATIC_NOPV void native_flush_tlb_global(void) - raw_local_irq_save(flags); - - cr4 = this_cpu_read(cpu_tlbstate.cr4); -+ BUG_ON(cr4 != __read_cr4()); - /* toggle PGE */ - native_write_cr4(cr4 ^ X86_CR4_PGE); - /* write old PGE again and flush TLBs */ --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0080-add-writable-function-pointer-detection.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0080-add-writable-function-pointer-detection.patch deleted file mode 100644 index 7bc04533e9fb..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0080-add-writable-function-pointer-detection.patch +++ /dev/null @@ -1,98 +0,0 @@ -From 3b29d50f0ec3aa25fd5291acc7a87d8fccfa5731 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Sun, 9 Jul 2017 17:53:23 -0400 -Subject: [PATCH 080/113] add writable function pointer detection - -Taken from the public PaX patches. - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - scripts/mod/modpost.c | 28 +++++++++++++++++++++++++--- - 1 file changed, 25 insertions(+), 3 deletions(-) - -diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c -index f882ce0d9327..50e9baefc4e7 100644 ---- a/scripts/mod/modpost.c -+++ b/scripts/mod/modpost.c -@@ -34,6 +34,7 @@ static int external_module = 0; - static int warn_unresolved = 0; - /* How a symbol is exported */ - static int sec_mismatch_count = 0; -+static int writable_fptr_count = 0; - static int sec_mismatch_fatal = 0; - /* ignore missing files */ - static int ignore_missing_files; -@@ -1007,6 +1008,7 @@ enum mismatch { - ANY_EXIT_TO_ANY_INIT, - EXPORT_TO_INIT_EXIT, - EXTABLE_TO_NON_TEXT, -+ DATA_TO_TEXT - }; - - /** -@@ -1133,6 +1135,12 @@ static const struct sectioncheck sectioncheck[] = { - .good_tosec = {ALL_TEXT_SECTIONS , NULL}, - .mismatch = EXTABLE_TO_NON_TEXT, - .handler = extable_mismatch_handler, -+}, -+/* Do not reference code from writable data */ -+{ -+ .fromsec = { DATA_SECTIONS, NULL }, -+ .bad_tosec = { ALL_TEXT_SECTIONS, NULL }, -+ .mismatch = DATA_TO_TEXT - } - }; - -@@ -1320,10 +1328,10 @@ static Elf_Sym *find_elf_symbol(struct elf_info *elf, Elf64_Sword addr, - continue; - if (!is_valid_name(elf, sym)) - continue; -- if (sym->st_value == addr) -- return sym; - /* Find a symbol nearby - addr are maybe negative */ - d = sym->st_value - addr; -+ if (d == 0) -+ return sym; - if (d < 0) - d = addr - sym->st_value; - if (d < distance) { -@@ -1458,7 +1466,10 @@ static void report_sec_mismatch(const char *modname, - char *prl_from; - char *prl_to; - -- sec_mismatch_count++; -+ if (mismatch->mismatch == DATA_TO_TEXT) -+ writable_fptr_count++; -+ else -+ sec_mismatch_count++; - - get_pretty_name(from_is_func, &from, &from_p); - get_pretty_name(to_is_func, &to, &to_p); -@@ -1580,6 +1591,14 @@ static void report_sec_mismatch(const char *modname, - fatal("There's a special handler for this mismatch type, " - "we should never get here."); - break; -+ case DATA_TO_TEXT: -+#if 0 -+ fprintf(stderr, -+ "The %s %s:%s references\n" -+ "the %s %s:%s%s\n", -+ from, fromsec, fromsym, to, tosec, tosym, to_p); -+#endif -+ break; - } - fprintf(stderr, "\n"); - } -@@ -2670,6 +2689,9 @@ int main(int argc, char **argv) - } - - free(buf.p); -+ if (writable_fptr_count) -+ warn("modpost: Found %d writable function pointer(s).\n", -+ writable_fptr_count); - - return err; - } --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0081-support-overriding-early-audit-kernel-cmdline.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0081-support-overriding-early-audit-kernel-cmdline.patch deleted file mode 100644 index 5f5bc2e74d34..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0081-support-overriding-early-audit-kernel-cmdline.patch +++ /dev/null @@ -1,26 +0,0 @@ -From ee257a5d7142058fad519c3e0c1347641956e49c Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Sun, 9 Jul 2017 17:20:29 -0400 -Subject: [PATCH 081/113] support overriding early audit kernel cmdline - ---- - kernel/audit.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/kernel/audit.c b/kernel/audit.c -index 68cee3bc8cfe..2059c66f7c9b 100644 ---- a/kernel/audit.c -+++ b/kernel/audit.c -@@ -1693,6 +1693,9 @@ static int __init audit_enable(char *str) - - if (audit_default == AUDIT_OFF) - audit_initialized = AUDIT_DISABLED; -+ else if (!audit_ever_enabled) -+ audit_initialized = AUDIT_UNINITIALIZED; -+ - if (audit_set_enabled(audit_default)) - pr_err("audit: error setting audit state (%d)\n", - audit_default); --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0082-FORTIFY_SOURCE-intra-object-overflow-checking.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0082-FORTIFY_SOURCE-intra-object-overflow-checking.patch deleted file mode 100644 index ec7a284f0f06..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0082-FORTIFY_SOURCE-intra-object-overflow-checking.patch +++ /dev/null @@ -1,135 +0,0 @@ -From c37790fe2fe6b91ba235235eb730a12f0f97303d Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Sat, 3 Jun 2017 17:34:13 -0400 -Subject: [PATCH 082/113] FORTIFY_SOURCE intra-object overflow checking - -This adds supporting for detecting buffer overflows from inner objects -for the fortified string family functions. It's comparable to the -_FORTIFY_SOURCE=2 feature in glibc with the additional coverage of -intra-object read overflows for supported functions. - -The mem* family functions are left with only the inter-object overflow -checks as is the case with glibc _FORTIFY_SOURCE=2. - -This feature is currently hidden behind CONFIG_EXPERT because it's a lot -more likely to uncover benign / intended issues and will need a lot of -runtime testing. It's already useful for finding bugs but it may not yet -be a good idea to use it for hardening unless panics for benign issues -are seen as a lesser evil than the vulnerabilities it can catch. - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - include/linux/string.h | 26 ++++++++++++++++---------- - security/Kconfig | 10 ++++++++++ - 2 files changed, 26 insertions(+), 10 deletions(-) - -diff --git a/include/linux/string.h b/include/linux/string.h -index b1f3894a0a3e..4c5564a6ad80 100644 ---- a/include/linux/string.h -+++ b/include/linux/string.h -@@ -264,6 +264,12 @@ void __read_overflow2(void) __compiletime_error("detected read beyond size of ob - void __read_overflow3(void) __compiletime_error("detected read beyond size of object passed as 3rd parameter"); - void __write_overflow(void) __compiletime_error("detected write beyond size of object passed as 1st parameter"); - -+#ifdef CONFIG_FORTIFY_SOURCE_STRICT_STRING -+#define __string_size(p) __builtin_object_size(p, 1) -+#else -+#define __string_size(p) __builtin_object_size(p, 0) -+#endif -+ - #if !defined(__NO_FORTIFY) && defined(__OPTIMIZE__) && defined(CONFIG_FORTIFY_SOURCE) - - #ifdef CONFIG_KASAN -@@ -292,7 +298,7 @@ extern char *__underlying_strncpy(char *p, const char *q, __kernel_size_t size) - - __FORTIFY_INLINE char *strncpy(char *p, const char *q, __kernel_size_t size) - { -- size_t p_size = __builtin_object_size(p, 0); -+ size_t p_size = __string_size(p); - if (__builtin_constant_p(size) && p_size < size) - __write_overflow(); - if (p_size < size) -@@ -302,7 +308,7 @@ __FORTIFY_INLINE char *strncpy(char *p, const char *q, __kernel_size_t size) - - __FORTIFY_INLINE char *strcat(char *p, const char *q) - { -- size_t p_size = __builtin_object_size(p, 0); -+ size_t p_size = __string_size(p); - if (p_size == (size_t)-1) - return __underlying_strcat(p, q); - if (strlcat(p, q, p_size) >= p_size) -@@ -313,7 +319,7 @@ __FORTIFY_INLINE char *strcat(char *p, const char *q) - __FORTIFY_INLINE __kernel_size_t strlen(const char *p) - { - __kernel_size_t ret; -- size_t p_size = __builtin_object_size(p, 0); -+ size_t p_size = __string_size(p); - - /* Work around gcc excess stack consumption issue */ - if (p_size == (size_t)-1 || -@@ -328,7 +334,7 @@ __FORTIFY_INLINE __kernel_size_t strlen(const char *p) - extern __kernel_size_t __real_strnlen(const char *, __kernel_size_t) __RENAME(strnlen); - __FORTIFY_INLINE __kernel_size_t strnlen(const char *p, __kernel_size_t maxlen) - { -- size_t p_size = __builtin_object_size(p, 0); -+ size_t p_size = __string_size(p); - __kernel_size_t ret = __real_strnlen(p, maxlen < p_size ? maxlen : p_size); - if (p_size <= ret && maxlen != ret) - fortify_panic(__func__); -@@ -340,8 +346,8 @@ extern size_t __real_strlcpy(char *, const char *, size_t) __RENAME(strlcpy); - __FORTIFY_INLINE size_t strlcpy(char *p, const char *q, size_t size) - { - size_t ret; -- size_t p_size = __builtin_object_size(p, 0); -- size_t q_size = __builtin_object_size(q, 0); -+ size_t p_size = __string_size(p); -+ size_t q_size = __string_size(q); - if (p_size == (size_t)-1 && q_size == (size_t)-1) - return __real_strlcpy(p, q, size); - ret = strlen(q); -@@ -361,8 +367,8 @@ __FORTIFY_INLINE size_t strlcpy(char *p, const char *q, size_t size) - __FORTIFY_INLINE char *strncat(char *p, const char *q, __kernel_size_t count) - { - size_t p_len, copy_len; -- size_t p_size = __builtin_object_size(p, 0); -- size_t q_size = __builtin_object_size(q, 0); -+ size_t p_size = __string_size(p); -+ size_t q_size = __string_size(q); - if (p_size == (size_t)-1 && q_size == (size_t)-1) - return __underlying_strncat(p, q, count); - p_len = strlen(p); -@@ -475,8 +481,8 @@ __FORTIFY_INLINE void *kmemdup(const void *p, size_t size, gfp_t gfp) - /* defined after fortified strlen and memcpy to reuse them */ - __FORTIFY_INLINE char *strcpy(char *p, const char *q) - { -- size_t p_size = __builtin_object_size(p, 0); -- size_t q_size = __builtin_object_size(q, 0); -+ size_t p_size = __string_size(p); -+ size_t q_size = __string_size(q); - if (p_size == (size_t)-1 && q_size == (size_t)-1) - return __underlying_strcpy(p, q); - memcpy(p, q, strlen(q) + 1); -diff --git a/security/Kconfig b/security/Kconfig -index 2348ff7d4e1d..f3c995bd79cf 100644 ---- a/security/Kconfig -+++ b/security/Kconfig -@@ -208,6 +208,16 @@ config FORTIFY_SOURCE - Detect overflows of buffers in common string and memory functions - where the compiler can determine and validate the buffer sizes. - -+config FORTIFY_SOURCE_STRICT_STRING -+ bool "Harden common functions against buffer overflows" -+ depends on FORTIFY_SOURCE -+ depends on EXPERT -+ help -+ Perform stricter overflow checks catching overflows within objects -+ for common C string functions rather than only between objects. -+ -+ This is not yet intended for production use, only bug finding. -+ - config STATIC_USERMODEHELPER - bool "Force all usermode helper calls through a single binary" - help --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0083-Revert-mm-revert-x86_64-and-arm64-ELF_ET_DYN_BASE-ba.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0083-Revert-mm-revert-x86_64-and-arm64-ELF_ET_DYN_BASE-ba.patch deleted file mode 100644 index a257b1d1ffb6..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0083-Revert-mm-revert-x86_64-and-arm64-ELF_ET_DYN_BASE-ba.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 4da4039518f44bc90e4974e4651126c8b05e780e Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Sat, 26 Aug 2017 20:16:03 -0400 -Subject: [PATCH 083/113] Revert "mm: revert x86_64 and arm64 ELF_ET_DYN_BASE - base changes" - -This reverts commit aab425db4279aeb83b7911693f0cccbd3644c9fd. ---- - arch/arm64/include/asm/elf.h | 8 ++------ - arch/x86/include/asm/elf.h | 4 ++-- - 2 files changed, 4 insertions(+), 8 deletions(-) - -diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h -index 8d1c8dcb87fd..26d27c7a2c2e 100644 ---- a/arch/arm64/include/asm/elf.h -+++ b/arch/arm64/include/asm/elf.h -@@ -124,14 +124,10 @@ - - /* - * This is the base location for PIE (ET_DYN with INTERP) loads. On -- * 64-bit, this is above 4GB to leave the entire 32-bit address -+ * 64-bit, this is raised to 4GB to leave the entire 32-bit address - * space open for things that want to use the area for 32-bit pointers. - */ --#ifdef CONFIG_ARM64_FORCE_52BIT --#define ELF_ET_DYN_BASE (2 * TASK_SIZE_64 / 3) --#else --#define ELF_ET_DYN_BASE (2 * DEFAULT_MAP_WINDOW_64 / 3) --#endif /* CONFIG_ARM64_FORCE_52BIT */ -+#define ELF_ET_DYN_BASE 0x100000000UL - - #ifndef __ASSEMBLY__ - -diff --git a/arch/x86/include/asm/elf.h b/arch/x86/include/asm/elf.h -index b9a5d488f1a5..b55054566ece 100644 ---- a/arch/x86/include/asm/elf.h -+++ b/arch/x86/include/asm/elf.h -@@ -246,11 +246,11 @@ extern int force_personality32; - - /* - * This is the base location for PIE (ET_DYN with INTERP) loads. On -- * 64-bit, this is above 4GB to leave the entire 32-bit address -+ * 64-bit, this is raised to 4GB to leave the entire 32-bit address - * space open for things that want to use the area for 32-bit pointers. - */ - #define ELF_ET_DYN_BASE (mmap_is_ia32() ? 0x000400000UL : \ -- (DEFAULT_MAP_WINDOW / 3 * 2)) -+ 0x100000000UL) - - /* This yields a mask that user programs can use to figure out what - instruction set this CPU supports. This could be done in user space, --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0084-x86_64-move-vdso-to-mmap-region-from-stack-region.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0084-x86_64-move-vdso-to-mmap-region-from-stack-region.patch deleted file mode 100644 index c37dab0bb349..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0084-x86_64-move-vdso-to-mmap-region-from-stack-region.patch +++ /dev/null @@ -1,118 +0,0 @@ -From 1f403103506f1a23a60a3325552a457493ee8de2 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Thu, 11 May 2017 16:52:00 -0400 -Subject: [PATCH 084/113] x86_64: move vdso to mmap region from stack region - -This removes the only executable code from the stack region and gives -the vdso the same randomized base as other mmap mappings including the -linker and other shared objects. It results in a sane amount of entropy -being provided and there's little to no advantage in separating this -from the existing executable code there. - -It's sensible for userspace to reserve the initial mmap base as a region -for executable code with a random gap for other mmap allocations, along -with providing randomization within that region. However, there isn't -much the kernel can do to help due to how dynamic linkers load the -shared objects. - -This was extracted from the PaX RANDMMAP feature. - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - arch/x86/entry/vdso/vma.c | 48 +----------------------------------- - arch/x86/include/asm/elf.h | 1 - - arch/x86/kernel/sys_x86_64.c | 7 ------ - 3 files changed, 1 insertion(+), 55 deletions(-) - -diff --git a/arch/x86/entry/vdso/vma.c b/arch/x86/entry/vdso/vma.c -index 9185cb1d13b9..543912071557 100644 ---- a/arch/x86/entry/vdso/vma.c -+++ b/arch/x86/entry/vdso/vma.c -@@ -315,55 +315,9 @@ static int map_vdso(const struct vdso_image *image, unsigned long addr) - } - - #ifdef CONFIG_X86_64 --/* -- * Put the vdso above the (randomized) stack with another randomized -- * offset. This way there is no hole in the middle of address space. -- * To save memory make sure it is still in the same PTE as the stack -- * top. This doesn't give that many random bits. -- * -- * Note that this algorithm is imperfect: the distribution of the vdso -- * start address within a PMD is biased toward the end. -- * -- * Only used for the 64-bit and x32 vdsos. -- */ --static unsigned long vdso_addr(unsigned long start, unsigned len) --{ -- unsigned long addr, end; -- unsigned offset; -- -- /* -- * Round up the start address. It can start out unaligned as a result -- * of stack start randomization. -- */ -- start = PAGE_ALIGN(start); -- -- /* Round the lowest possible end address up to a PMD boundary. */ -- end = (start + len + PMD_SIZE - 1) & PMD_MASK; -- if (end >= TASK_SIZE_MAX) -- end = TASK_SIZE_MAX; -- end -= len; -- -- if (end > start) { -- offset = get_random_int() % (((end - start) >> PAGE_SHIFT) + 1); -- addr = start + (offset << PAGE_SHIFT); -- } else { -- addr = start; -- } -- -- /* -- * Forcibly align the final address in case we have a hardware -- * issue that requires alignment for performance reasons. -- */ -- addr = align_vdso_addr(addr); -- -- return addr; --} -- - static int map_vdso_randomized(const struct vdso_image *image) - { -- unsigned long addr = vdso_addr(current->mm->start_stack, image->size-image->sym_vvar_start); -- -- return map_vdso(image, addr); -+ return map_vdso(image, 0); - } - #endif - -diff --git a/arch/x86/include/asm/elf.h b/arch/x86/include/asm/elf.h -index b55054566ece..58292600112d 100644 ---- a/arch/x86/include/asm/elf.h -+++ b/arch/x86/include/asm/elf.h -@@ -398,5 +398,4 @@ struct va_alignment { - } ____cacheline_aligned; - - extern struct va_alignment va_align; --extern unsigned long align_vdso_addr(unsigned long); - #endif /* _ASM_X86_ELF_H */ -diff --git a/arch/x86/kernel/sys_x86_64.c b/arch/x86/kernel/sys_x86_64.c -index 504fa5425bce..c4e35a3b3733 100644 ---- a/arch/x86/kernel/sys_x86_64.c -+++ b/arch/x86/kernel/sys_x86_64.c -@@ -52,13 +52,6 @@ static unsigned long get_align_bits(void) - return va_align.bits & get_align_mask(); - } - --unsigned long align_vdso_addr(unsigned long addr) --{ -- unsigned long align_mask = get_align_mask(); -- addr = (addr + align_mask) & ~align_mask; -- return addr | get_align_bits(); --} -- - static int __init control_va_addr_alignment(char *str) - { - /* guard against enabling this on other CPU families */ --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0085-x86-determine-stack-entropy-based-on-mmap-entropy.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0085-x86-determine-stack-entropy-based-on-mmap-entropy.patch deleted file mode 100644 index 652e6a2eaef1..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0085-x86-determine-stack-entropy-based-on-mmap-entropy.patch +++ /dev/null @@ -1,60 +0,0 @@ -From 7886dd7cdefed4f32ab1c17df880462622f04a70 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Sun, 21 May 2017 20:30:44 -0400 -Subject: [PATCH 085/113] x86: determine stack entropy based on mmap entropy - -Stack mapping entropy is currently hard-wired to 11 bits of entropy on -32-bit and 22 bits of entropy on 64-bit. The stack itself gains an extra -8 bits of entropy from lower bit randomization within 16 byte alignment -constraints. The argument block could have all lower bits randomized but -it currently only gets the mapping randomization. - -Rather than hard-wiring values this switches to using the mmap entropy -configuration like the mmap base and executable base, resulting in a -range of 8 to 16 bits on 32-bit and 28 to 32 bits on 64-bit depending on -kernel configuration and overridable via the sysctl entries. - -It's worth noting that since these kernel configuration options default -to the minimum supported entropy value, the entropy on 32-bit will drop -from 11 to 8 bits for builds using the defaults. However, following the -configuration seems like the right thing to do regardless. At the very -least, changing the defaults for COMPAT (32-bit processes on 64-bit) -should be considered due to the larger address space compared to real -32-bit. - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - arch/x86/include/asm/elf.h | 10 +++++++--- - 1 file changed, 7 insertions(+), 3 deletions(-) - -diff --git a/arch/x86/include/asm/elf.h b/arch/x86/include/asm/elf.h -index 58292600112d..608cca19cf8c 100644 ---- a/arch/x86/include/asm/elf.h -+++ b/arch/x86/include/asm/elf.h -@@ -330,8 +330,8 @@ extern bool mmap_address_hint_valid(unsigned long addr, unsigned long len); - - #ifdef CONFIG_X86_32 - --#define __STACK_RND_MASK(is32bit) (0x7ff) --#define STACK_RND_MASK (0x7ff) -+#define __STACK_RND_MASK(is32bit) ((1UL << mmap_rnd_bits) - 1) -+#define STACK_RND_MASK ((1UL << mmap_rnd_bits) - 1) - - #define ARCH_DLINFO ARCH_DLINFO_IA32 - -@@ -340,7 +340,11 @@ extern bool mmap_address_hint_valid(unsigned long addr, unsigned long len); - #else /* CONFIG_X86_32 */ - - /* 1GB for 64bit, 8MB for 32bit */ --#define __STACK_RND_MASK(is32bit) ((is32bit) ? 0x7ff : 0x3fffff) -+#ifdef CONFIG_COMPAT -+#define __STACK_RND_MASK(is32bit) ((is32bit) ? (1UL << mmap_rnd_compat_bits) - 1 : (1UL << mmap_rnd_bits) - 1) -+#else -+#define __STACK_RND_MASK(is32bit) ((1UL << mmap_rnd_bits) - 1) -+#endif - #define STACK_RND_MASK __STACK_RND_MASK(mmap_is_ia32()) - - #define ARCH_DLINFO \ --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0086-arm64-determine-stack-entropy-based-on-mmap-entropy.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0086-arm64-determine-stack-entropy-based-on-mmap-entropy.patch deleted file mode 100644 index f814b346de7c..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0086-arm64-determine-stack-entropy-based-on-mmap-entropy.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 7a9997243a77003f2741faa992b0889969915337 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Mon, 22 May 2017 05:06:20 -0400 -Subject: [PATCH 086/113] arm64: determine stack entropy based on mmap entropy - -Stack mapping entropy is currently hard-wired to 11 bits of entropy on -32-bit and 18 bits of entropy on 64-bit. The stack itself gains an extra -8 bits of entropy from lower bit randomization within 16 byte alignment -constraints. The argument block could have all lower bits randomized but -it currently only gets the mapping randomization. - -Rather than hard-wiring values this switches to using the mmap entropy -configuration like the mmap base and executable base, resulting in a -range of 8 to 16 bits on 32-bit and 18 to 24 bits on 64-bit (with 4k -pages and 3 level page tables) depending on kernel configuration and -overridable via the sysctl entries. - -It's worth noting that since these kernel configuration options default -to the minimum supported entropy value, the entropy on 32-bit will drop -from 11 to 8 bits for builds using the defaults. However, following the -configuration seems like the right thing to do regardless. At the very -least, changing the defaults for COMPAT (32-bit processes on 64-bit) -should be considered due to the larger address space compared to real -32-bit. - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - arch/arm64/include/asm/elf.h | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h -index 26d27c7a2c2e..32c1609a1158 100644 ---- a/arch/arm64/include/asm/elf.h -+++ b/arch/arm64/include/asm/elf.h -@@ -185,10 +185,10 @@ extern int arch_setup_additional_pages(struct linux_binprm *bprm, - /* 1GB of VA */ - #ifdef CONFIG_COMPAT - #define STACK_RND_MASK (test_thread_flag(TIF_32BIT) ? \ -- 0x7ff >> (PAGE_SHIFT - 12) : \ -- 0x3ffff >> (PAGE_SHIFT - 12)) -+ ((1UL << mmap_rnd_compat_bits) - 1) >> (PAGE_SHIFT - 12) : \ -+ ((1UL << mmap_rnd_bits) - 1) >> (PAGE_SHIFT - 12)) - #else --#define STACK_RND_MASK (0x3ffff >> (PAGE_SHIFT - 12)) -+#define STACK_RND_MASK (((1UL << mmap_rnd_bits) - 1) >> (PAGE_SHIFT - 12)) - #endif - - #ifdef __AARCH64EB__ --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0087-randomize-lower-bits-of-the-argument-block.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0087-randomize-lower-bits-of-the-argument-block.patch deleted file mode 100644 index dc6a007b7a22..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0087-randomize-lower-bits-of-the-argument-block.patch +++ /dev/null @@ -1,47 +0,0 @@ -From ec8a6342397f4d75cea932e163a02d913d350b57 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Thu, 11 May 2017 16:02:49 -0400 -Subject: [PATCH 087/113] randomize lower bits of the argument block - -This was based on the PaX RANDUSTACK feature in grsecurity, where all of -the lower bits are randomized. PaX keeps 16-byte alignment. - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> -[levente@leventepolyak.net: do not randomize with ADDR_NO_RANDOMIZE personality] -Signed-off-by: Levente Polyak <levente@leventepolyak.net> ---- - fs/exec.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/fs/exec.c b/fs/exec.c -index ca89e0e3ef10..d2a03d32e195 100644 ---- a/fs/exec.c -+++ b/fs/exec.c -@@ -34,6 +34,7 @@ - #include <linux/swap.h> - #include <linux/string.h> - #include <linux/init.h> -+#include <linux/sched.h> - #include <linux/sched/mm.h> - #include <linux/sched/coredump.h> - #include <linux/sched/signal.h> -@@ -64,6 +65,7 @@ - #include <linux/compat.h> - #include <linux/vmalloc.h> - #include <linux/io_uring.h> -+#include <linux/random.h> - - #include <linux/uaccess.h> - #include <asm/mmu_context.h> -@@ -280,6 +282,8 @@ static int __bprm_mm_init(struct linux_binprm *bprm) - mm->stack_vm = mm->total_vm = 1; - mmap_write_unlock(mm); - bprm->p = vma->vm_end - sizeof(void *); -+ if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space) -+ bprm->p ^= get_random_int() & ~PAGE_MASK; - return 0; - err: - mmap_write_unlock(mm); --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0088-x86_64-match-arm64-brk-randomization-entropy.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0088-x86_64-match-arm64-brk-randomization-entropy.patch deleted file mode 100644 index 4dd084e86825..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0088-x86_64-match-arm64-brk-randomization-entropy.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 7c462ca9c247669cf7001b339537714537ab99c6 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Tue, 30 May 2017 07:19:48 -0400 -Subject: [PATCH 088/113] x86_64: match arm64 brk randomization entropy - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - arch/x86/kernel/process.c | 7 ++++++- - 1 file changed, 6 insertions(+), 1 deletion(-) - -diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c -index 058941e9ae40..61460d55dd72 100644 ---- a/arch/x86/kernel/process.c -+++ b/arch/x86/kernel/process.c -@@ -43,6 +43,8 @@ - #include <asm/io_bitmap.h> - #include <asm/proto.h> - #include <asm/frame.h> -+#include <asm/elf.h> -+#include <linux/sizes.h> - - #include "process.h" - -@@ -906,7 +908,10 @@ unsigned long arch_align_stack(unsigned long sp) - - unsigned long arch_randomize_brk(struct mm_struct *mm) - { -- return randomize_page(mm->brk, 0x02000000); -+ if (mmap_is_ia32()) -+ return randomize_page(mm->brk, SZ_32M); -+ else -+ return randomize_page(mm->brk, SZ_1G); - } - - /* --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0089-support-randomizing-the-lower-bits-of-brk.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0089-support-randomizing-the-lower-bits-of-brk.patch deleted file mode 100644 index 74521ae0abfc..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0089-support-randomizing-the-lower-bits-of-brk.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 3a786b13d3d3eaca44a116a539f8a465bae0a169 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Tue, 30 May 2017 18:03:30 -0400 -Subject: [PATCH 089/113] support randomizing the lower bits of brk - -This adds support for arch_randomize_brk implementations not performing -page alignment in order to randomize the lower bits of the brk heap. - -This idea is taken from PaX but the approach is different. This reuses -the existing code and avoids forcing early creation of the heap mapping, -avoiding mapping it if it's not used which is the case with many modern -allocators based solely on mmap. - -The malloc implementation can be relied upon to align this as needed to -the requirements it has, so using 16 byte alignment here is unnecessary. - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - mm/mmap.c | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/mm/mmap.c b/mm/mmap.c -index 5c8b4485860d..0e26c225bb53 100644 ---- a/mm/mmap.c -+++ b/mm/mmap.c -@@ -231,6 +231,13 @@ SYSCALL_DEFINE1(brk, unsigned long, brk) - - newbrk = PAGE_ALIGN(brk); - oldbrk = PAGE_ALIGN(mm->brk); -+ /* properly handle unaligned min_brk as an empty heap */ -+ if (min_brk & ~PAGE_MASK) { -+ if (brk == min_brk) -+ newbrk -= PAGE_SIZE; -+ if (mm->brk == min_brk) -+ oldbrk -= PAGE_SIZE; -+ } - if (oldbrk == newbrk) { - mm->brk = brk; - goto success; --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0090-mm-randomize-lower-bits-of-brk.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0090-mm-randomize-lower-bits-of-brk.patch deleted file mode 100644 index 87d68eff987b..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0090-mm-randomize-lower-bits-of-brk.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 4b1f2c7238a4b5c6c6fbb4cdd43686f23e5c0672 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Thu, 1 Jun 2017 03:22:38 -0400 -Subject: [PATCH 090/113] mm: randomize lower bits of brk - -Per PaX, but for this alternate brk randomization approach. - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - mm/util.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/mm/util.c b/mm/util.c -index 4ddb6e186dd5..4ca72f952329 100644 ---- a/mm/util.c -+++ b/mm/util.c -@@ -336,9 +336,9 @@ unsigned long arch_randomize_brk(struct mm_struct *mm) - { - /* Is the current task 32bit ? */ - if (!IS_ENABLED(CONFIG_64BIT) || is_compat_task()) -- return randomize_page(mm->brk, SZ_32M); -+ return mm->brk + get_random_long() % SZ_32M; - -- return randomize_page(mm->brk, SZ_1G); -+ return mm->brk + get_random_long() % SZ_1G; - } - - unsigned long arch_mmap_rnd(void) --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0091-x86-randomize-lower-bits-of-brk.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0091-x86-randomize-lower-bits-of-brk.patch deleted file mode 100644 index e298285bef98..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0091-x86-randomize-lower-bits-of-brk.patch +++ /dev/null @@ -1,31 +0,0 @@ -From ee36f8847014ce9c6f8b2ae7ecf582fa7e9212f1 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Thu, 1 Jun 2017 03:23:06 -0400 -Subject: [PATCH 091/113] x86: randomize lower bits of brk - -Per PaX, but for this alternate brk randomization approach. - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - arch/x86/kernel/process.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c -index 61460d55dd72..0d4c3887229d 100644 ---- a/arch/x86/kernel/process.c -+++ b/arch/x86/kernel/process.c -@@ -909,9 +909,9 @@ unsigned long arch_align_stack(unsigned long sp) - unsigned long arch_randomize_brk(struct mm_struct *mm) - { - if (mmap_is_ia32()) -- return randomize_page(mm->brk, SZ_32M); -+ return mm->brk + get_random_long() % SZ_32M; - else -- return randomize_page(mm->brk, SZ_1G); -+ return mm->brk + get_random_long() % SZ_1G; - } - - /* --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0092-mm-guarantee-brk-gap-is-at-least-one-page.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0092-mm-guarantee-brk-gap-is-at-least-one-page.patch deleted file mode 100644 index b0c754847efd..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0092-mm-guarantee-brk-gap-is-at-least-one-page.patch +++ /dev/null @@ -1,31 +0,0 @@ -From c8d91234889dc8f16c7b65ad5c82006705f1639f Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Thu, 1 Jun 2017 03:23:39 -0400 -Subject: [PATCH 092/113] mm: guarantee brk gap is at least one page - -Per PaX, but for this alternate brk randomization approach. - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - mm/util.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/mm/util.c b/mm/util.c -index 4ca72f952329..62ed34dfceb7 100644 ---- a/mm/util.c -+++ b/mm/util.c -@@ -336,9 +336,9 @@ unsigned long arch_randomize_brk(struct mm_struct *mm) - { - /* Is the current task 32bit ? */ - if (!IS_ENABLED(CONFIG_64BIT) || is_compat_task()) -- return mm->brk + get_random_long() % SZ_32M; -+ return mm->brk + get_random_long() % SZ_32M + PAGE_SIZE; - -- return mm->brk + get_random_long() % SZ_1G; -+ return mm->brk + get_random_long() % SZ_1G + PAGE_SIZE; - } - - unsigned long arch_mmap_rnd(void) --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0093-x86-guarantee-brk-gap-is-at-least-one-page.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0093-x86-guarantee-brk-gap-is-at-least-one-page.patch deleted file mode 100644 index bfa1ee7ebd01..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0093-x86-guarantee-brk-gap-is-at-least-one-page.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 917039f2905ed6432e56b444b36803d853de1b47 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Thu, 1 Jun 2017 03:23:48 -0400 -Subject: [PATCH 093/113] x86: guarantee brk gap is at least one page - -Per PaX, but for this alternate brk randomization approach. - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - arch/x86/kernel/process.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c -index 0d4c3887229d..161e25d02fd5 100644 ---- a/arch/x86/kernel/process.c -+++ b/arch/x86/kernel/process.c -@@ -909,9 +909,9 @@ unsigned long arch_align_stack(unsigned long sp) - unsigned long arch_randomize_brk(struct mm_struct *mm) - { - if (mmap_is_ia32()) -- return mm->brk + get_random_long() % SZ_32M; -+ return mm->brk + get_random_long() % SZ_32M + PAGE_SIZE; - else -- return mm->brk + get_random_long() % SZ_1G; -+ return mm->brk + get_random_long() % SZ_1G + PAGE_SIZE; - } - - /* --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0094-x86_64-bound-mmap-between-legacy-modern-bases.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0094-x86_64-bound-mmap-between-legacy-modern-bases.patch deleted file mode 100644 index efa4e279dc40..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0094-x86_64-bound-mmap-between-legacy-modern-bases.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 561c6c6469dd335b4e7de5932a115dd2cb77ad34 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Tue, 4 Jul 2017 14:50:54 -0400 -Subject: [PATCH 094/113] x86_64: bound mmap between legacy/modern bases - ---- - arch/x86/kernel/sys_x86_64.c | 7 ++----- - 1 file changed, 2 insertions(+), 5 deletions(-) - -diff --git a/arch/x86/kernel/sys_x86_64.c b/arch/x86/kernel/sys_x86_64.c -index c4e35a3b3733..e30ec4c750d1 100644 ---- a/arch/x86/kernel/sys_x86_64.c -+++ b/arch/x86/kernel/sys_x86_64.c -@@ -113,10 +113,7 @@ static void find_start_end(unsigned long addr, unsigned long flags, - } - - *begin = get_mmap_base(1); -- if (in_32bit_syscall()) -- *end = task_size_32bit(); -- else -- *end = task_size_64bit(addr > DEFAULT_MAP_WINDOW); -+ *end = get_mmap_base(0); - } - - unsigned long -@@ -193,7 +190,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, - - info.flags = VM_UNMAPPED_AREA_TOPDOWN; - info.length = len; -- info.low_limit = PAGE_SIZE; -+ info.low_limit = get_mmap_base(1); - info.high_limit = get_mmap_base(0); - - /* --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0095-restrict-device-timing-side-channels.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0095-restrict-device-timing-side-channels.patch deleted file mode 100644 index f2f4563b237e..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0095-restrict-device-timing-side-channels.patch +++ /dev/null @@ -1,174 +0,0 @@ -From 776a04a1a0d87c4dfb815d4a272617ed9109ecd7 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Tue, 16 May 2017 18:26:10 -0400 -Subject: [PATCH 095/113] restrict device timing side channels - -Based on the public grsecurity patches. - -Signed-off-by: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr> -Signed-off-by: Levente Polyak <levente@leventepolyak.net> ---- - fs/inode.c | 4 ++++ - fs/stat.c | 20 +++++++++++++++----- - include/linux/capability.h | 5 +++++ - include/linux/fs.h | 11 +++++++++++ - include/linux/fsnotify.h | 4 ++++ - kernel/capability.c | 6 ++++++ - kernel/sysctl.c | 9 +++++++++ - 7 files changed, 54 insertions(+), 5 deletions(-) - -diff --git a/fs/inode.c b/fs/inode.c -index 5eea9912a0b9..f86f383a3e1d 100644 ---- a/fs/inode.c -+++ b/fs/inode.c -@@ -116,6 +116,10 @@ int proc_nr_inodes(struct ctl_table *table, int write, - } - #endif - -+/* sysctl */ -+int device_sidechannel_restrict __read_mostly = 1; -+EXPORT_SYMBOL(device_sidechannel_restrict); -+ - static int no_open(struct inode *inode, struct file *file) - { - return -ENXIO; -diff --git a/fs/stat.c b/fs/stat.c -index dacecdda2e79..14173d0f777d 100644 ---- a/fs/stat.c -+++ b/fs/stat.c -@@ -43,8 +43,13 @@ void generic_fillattr(struct inode *inode, struct kstat *stat) - stat->gid = inode->i_gid; - stat->rdev = inode->i_rdev; - stat->size = i_size_read(inode); -- stat->atime = inode->i_atime; -- stat->mtime = inode->i_mtime; -+ if (is_sidechannel_device(inode) && !capable_noaudit(CAP_MKNOD)) { -+ stat->atime = inode->i_ctime; -+ stat->mtime = inode->i_ctime; -+ } else { -+ stat->atime = inode->i_atime; -+ stat->mtime = inode->i_mtime; -+ } - stat->ctime = inode->i_ctime; - stat->blksize = i_blocksize(inode); - stat->blocks = inode->i_blocks; -@@ -83,9 +88,14 @@ int vfs_getattr_nosec(const struct path *path, struct kstat *stat, - if (IS_DAX(inode)) - stat->attributes |= STATX_ATTR_DAX; - -- if (inode->i_op->getattr) -- return inode->i_op->getattr(path, stat, request_mask, -- query_flags); -+ if (inode->i_op->getattr) { -+ int retval = inode->i_op->getattr(path, stat, request_mask, query_flags); -+ if (!retval && is_sidechannel_device(inode) && !capable_noaudit(CAP_MKNOD)) { -+ stat->atime = stat->ctime; -+ stat->mtime = stat->ctime; -+ } -+ return retval; -+ } - - generic_fillattr(inode, stat); - return 0; -diff --git a/include/linux/capability.h b/include/linux/capability.h -index 1e7fe311cabe..a5b6d4c9acf5 100644 ---- a/include/linux/capability.h -+++ b/include/linux/capability.h -@@ -208,6 +208,7 @@ extern bool has_capability_noaudit(struct task_struct *t, int cap); - extern bool has_ns_capability_noaudit(struct task_struct *t, - struct user_namespace *ns, int cap); - extern bool capable(int cap); -+extern bool capable_noaudit(int cap); - extern bool ns_capable(struct user_namespace *ns, int cap); - extern bool ns_capable_noaudit(struct user_namespace *ns, int cap); - extern bool ns_capable_setid(struct user_namespace *ns, int cap); -@@ -234,6 +235,10 @@ static inline bool capable(int cap) - { - return true; - } -+static inline bool capable_noaudit(int cap) -+{ -+ return true; -+} - static inline bool ns_capable(struct user_namespace *ns, int cap) - { - return true; -diff --git a/include/linux/fs.h b/include/linux/fs.h -index 8bde32cf9711..83d50b0a2a18 100644 ---- a/include/linux/fs.h -+++ b/include/linux/fs.h -@@ -3475,4 +3475,15 @@ static inline int inode_drain_writes(struct inode *inode) - return filemap_write_and_wait(inode->i_mapping); - } - -+extern int device_sidechannel_restrict; -+ -+static inline bool is_sidechannel_device(const struct inode *inode) -+{ -+ umode_t mode; -+ if (!device_sidechannel_restrict) -+ return false; -+ mode = inode->i_mode; -+ return ((S_ISCHR(mode) || S_ISBLK(mode)) && (mode & (S_IROTH | S_IWOTH))); -+} -+ - #endif /* _LINUX_FS_H */ -diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h -index f8acddcf54fb..7b109980327f 100644 ---- a/include/linux/fsnotify.h -+++ b/include/linux/fsnotify.h -@@ -83,10 +83,14 @@ static inline void fsnotify_dentry(struct dentry *dentry, __u32 mask) - static inline int fsnotify_file(struct file *file, __u32 mask) - { - const struct path *path = &file->f_path; -+ struct inode *inode = file_inode(file); - - if (file->f_mode & FMODE_NONOTIFY) - return 0; - -+ if (mask & (FS_ACCESS | FS_MODIFY) && is_sidechannel_device(inode)) -+ return 0; -+ - return fsnotify_parent(path->dentry, mask, path, FSNOTIFY_EVENT_PATH); - } - -diff --git a/kernel/capability.c b/kernel/capability.c -index de7eac903a2a..5602178f3d21 100644 ---- a/kernel/capability.c -+++ b/kernel/capability.c -@@ -449,6 +449,12 @@ bool capable(int cap) - return ns_capable(&init_user_ns, cap); - } - EXPORT_SYMBOL(capable); -+ -+bool capable_noaudit(int cap) -+{ -+ return ns_capable_noaudit(&init_user_ns, cap); -+} -+EXPORT_SYMBOL(capable_noaudit); - #endif /* CONFIG_MULTIUSER */ - - /** -diff --git a/kernel/sysctl.c b/kernel/sysctl.c -index fccf24a08c8a..7fda9f61ea1a 100644 ---- a/kernel/sysctl.c -+++ b/kernel/sysctl.c -@@ -2272,6 +2272,15 @@ static struct ctl_table kern_table[] = { - .extra2 = &two, - }, - #endif -+ { -+ .procname = "device_sidechannel_restrict", -+ .data = &device_sidechannel_restrict, -+ .maxlen = sizeof(int), -+ .mode = 0644, -+ .proc_handler = proc_dointvec_minmax_sysadmin, -+ .extra1 = SYSCTL_ZERO, -+ .extra2 = SYSCTL_ONE, -+ }, - { - .procname = "ngroups_max", - .data = &ngroups_max, --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0096-sysctl-expose-proc_dointvec_minmax_sysadmin-as-API-f.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0096-sysctl-expose-proc_dointvec_minmax_sysadmin-as-API-f.patch deleted file mode 100644 index 5db5a7e5ea97..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0096-sysctl-expose-proc_dointvec_minmax_sysadmin-as-API-f.patch +++ /dev/null @@ -1,95 +0,0 @@ -From 245008adfd6a5dec75ee9dc30eab0f0b6fc3cfab Mon Sep 17 00:00:00 2001 -From: Levente Polyak <levente@leventepolyak.net> -Date: Sun, 6 Sep 2020 20:28:32 +0200 -Subject: [PATCH 096/113] sysctl: expose proc_dointvec_minmax_sysadmin as API - function - -Orthogonal to the other sysctl proc functions expose the variant that is -checking CAP_SYS_ADMIN on write for consumption in external subsystem's -sysctl tables. - -Signed-off-by: Levente Polyak <levente@leventepolyak.net> ---- - include/linux/sysctl.h | 2 ++ - kernel/sysctl.c | 31 ++++++++++++++++++++++++++++--- - 2 files changed, 30 insertions(+), 3 deletions(-) - -diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h -index 51298a4f4623..b835c57330f2 100644 ---- a/include/linux/sysctl.h -+++ b/include/linux/sysctl.h -@@ -53,6 +53,8 @@ int proc_douintvec(struct ctl_table *, int, void *, size_t *, loff_t *); - int proc_dointvec_minmax(struct ctl_table *, int, void *, size_t *, loff_t *); - int proc_douintvec_minmax(struct ctl_table *table, int write, void *buffer, - size_t *lenp, loff_t *ppos); -+int proc_dointvec_minmax_sysadmin(struct ctl_table *table, int write, -+ void *buffer, size_t *lenp, loff_t *ppos); - int proc_dointvec_jiffies(struct ctl_table *, int, void *, size_t *, loff_t *); - int proc_dointvec_userhz_jiffies(struct ctl_table *, int, void *, size_t *, - loff_t *); -diff --git a/kernel/sysctl.c b/kernel/sysctl.c -index 7fda9f61ea1a..13b619e46ade 100644 ---- a/kernel/sysctl.c -+++ b/kernel/sysctl.c -@@ -890,8 +890,27 @@ static int proc_taint(struct ctl_table *table, int write, - return err; - } - --#ifdef CONFIG_PRINTK --static int proc_dointvec_minmax_sysadmin(struct ctl_table *table, int write, -+/** -+ * proc_dointvec_minmax_sysadmin - read a vector of integers with min/max values -+ * checking CAP_SYS_ADMIN on write -+ * @table: the sysctl table -+ * @write: %TRUE if this is a write to the sysctl file -+ * @buffer: the user buffer -+ * @lenp: the size of the user buffer -+ * @ppos: file position -+ * -+ * Reads/writes up to table->maxlen/sizeof(unsigned int) integer -+ * values from/to the user buffer, treated as an ASCII string. -+ * -+ * This routine will ensure the values are within the range specified by -+ * table->extra1 (min) and table->extra2 (max). -+ * -+ * Writing is only allowed when root has CAP_SYS_ADMIN. -+ * -+ * Returns 0 on success, -EPERM on permission failure or -EINVAL on write -+ * when the range check fails. -+ */ -+int proc_dointvec_minmax_sysadmin(struct ctl_table *table, int write, - void *buffer, size_t *lenp, loff_t *ppos) - { - if (write && !capable(CAP_SYS_ADMIN)) -@@ -899,7 +918,6 @@ static int proc_dointvec_minmax_sysadmin(struct ctl_table *table, int write, - - return proc_dointvec_minmax(table, write, buffer, lenp, ppos); - } --#endif - - /** - * struct do_proc_dointvec_minmax_conv_param - proc_dointvec_minmax() range checking structure -@@ -1585,6 +1603,12 @@ int proc_douintvec_minmax(struct ctl_table *table, int write, - return -ENOSYS; - } - -+int proc_dointvec_minmax_sysadmin(struct ctl_table *table, int write, -+ void *buffer, size_t *lenp, loff_t *ppos) -+{ -+ return -ENOSYS; -+} -+ - int proc_dointvec_jiffies(struct ctl_table *table, int write, - void *buffer, size_t *lenp, loff_t *ppos) - { -@@ -3436,6 +3460,7 @@ EXPORT_SYMBOL(proc_douintvec); - EXPORT_SYMBOL(proc_dointvec_jiffies); - EXPORT_SYMBOL(proc_dointvec_minmax); - EXPORT_SYMBOL_GPL(proc_douintvec_minmax); -+EXPORT_SYMBOL(proc_dointvec_minmax_sysadmin); - EXPORT_SYMBOL(proc_dointvec_userhz_jiffies); - EXPORT_SYMBOL(proc_dointvec_ms_jiffies); - EXPORT_SYMBOL(proc_dostring); --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0097-usb-add-toggle-for-disabling-newly-added-USB-devices.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0097-usb-add-toggle-for-disabling-newly-added-USB-devices.patch deleted file mode 100644 index d6b50c588c33..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0097-usb-add-toggle-for-disabling-newly-added-USB-devices.patch +++ /dev/null @@ -1,92 +0,0 @@ -From 474acec9ac886a45771b335fe0a1becc5a7901f1 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Tue, 16 May 2017 17:51:48 -0400 -Subject: [PATCH 097/113] usb: add toggle for disabling newly added USB devices - -Based on the public grsecurity patches. - -[thibaut.sautereau@ssi.gouv.fr: Adapt to sysctl code refactoring] -Signed-off-by: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr> -Signed-off-by: Levente Polyak <levente@leventepolyak.net> ---- - drivers/usb/core/hub.c | 9 +++++++++ - include/linux/usb.h | 3 +++ - kernel/sysctl.c | 14 ++++++++++++++ - 3 files changed, 26 insertions(+) - -diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c -index 17202b2ee063..9385c745d55e 100644 ---- a/drivers/usb/core/hub.c -+++ b/drivers/usb/core/hub.c -@@ -5054,6 +5054,9 @@ static int descriptors_changed(struct usb_device *udev, - return changed; - } - -+/* sysctl */ -+int deny_new_usb __read_mostly = 0; -+ - static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus, - u16 portchange) - { -@@ -5114,6 +5117,12 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus, - goto done; - return; - } -+ -+ if (deny_new_usb) { -+ dev_err(&port_dev->dev, "denied insert of USB device on port %d\n", port1); -+ goto done; -+ } -+ - if (hub_is_superspeed(hub->hdev)) - unit_load = 150; - else -diff --git a/include/linux/usb.h b/include/linux/usb.h -index 7d72c4e0713c..8e7549e3012a 100644 ---- a/include/linux/usb.h -+++ b/include/linux/usb.h -@@ -2035,6 +2035,9 @@ extern void usb_led_activity(enum usb_led_event ev); - static inline void usb_led_activity(enum usb_led_event ev) {} - #endif - -+/* sysctl */ -+extern int deny_new_usb; -+ - #endif /* __KERNEL__ */ - - #endif -diff --git a/kernel/sysctl.c b/kernel/sysctl.c -index 13b619e46ade..f867606fbd80 100644 ---- a/kernel/sysctl.c -+++ b/kernel/sysctl.c -@@ -106,6 +106,9 @@ - #ifdef CONFIG_USER_NS - #include <linux/user_namespace.h> - #endif -+#if IS_ENABLED(CONFIG_USB) -+#include <linux/usb.h> -+#endif - - #if defined(CONFIG_SYSCTL) - -@@ -2305,6 +2308,17 @@ static struct ctl_table kern_table[] = { - .extra1 = SYSCTL_ZERO, - .extra2 = SYSCTL_ONE, - }, -+#if IS_ENABLED(CONFIG_USB) -+ { -+ .procname = "deny_new_usb", -+ .data = &deny_new_usb, -+ .maxlen = sizeof(int), -+ .mode = 0644, -+ .proc_handler = proc_dointvec_minmax_sysadmin, -+ .extra1 = SYSCTL_ZERO, -+ .extra2 = SYSCTL_ONE, -+ }, -+#endif - { - .procname = "ngroups_max", - .data = &ngroups_max, --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0098-usb-implement-dedicated-subsystem-sysctl-tables.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0098-usb-implement-dedicated-subsystem-sysctl-tables.patch deleted file mode 100644 index c4cedc8b9bff..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0098-usb-implement-dedicated-subsystem-sysctl-tables.patch +++ /dev/null @@ -1,195 +0,0 @@ -From 0772d6cfa20bdf02f474623428e68f9bef338655 Mon Sep 17 00:00:00 2001 -From: Levente Polyak <levente@leventepolyak.net> -Date: Sun, 6 Sep 2020 21:08:16 +0200 -Subject: [PATCH 098/113] usb: implement dedicated subsystem sysctl tables - -This moves the usb related sysctl knobs to an own usb local sysctl table -in order to clean up the global sysctl as well as allow the knob to be -exported and referenced appropriately when building the usb components -as dedicated modules. - -Signed-off-by: Levente Polyak <levente@leventepolyak.net> ---- - drivers/usb/core/Makefile | 1 + - drivers/usb/core/hub.c | 3 --- - drivers/usb/core/sysctl.c | 44 +++++++++++++++++++++++++++++++++++++++ - drivers/usb/core/usb.c | 9 ++++++++ - include/linux/usb.h | 10 ++++++++- - kernel/sysctl.c | 14 ------------- - 6 files changed, 63 insertions(+), 18 deletions(-) - create mode 100644 drivers/usb/core/sysctl.c - -diff --git a/drivers/usb/core/Makefile b/drivers/usb/core/Makefile -index 18e874b0441e..fc7a3a9aa72a 100644 ---- a/drivers/usb/core/Makefile -+++ b/drivers/usb/core/Makefile -@@ -11,6 +11,7 @@ usbcore-y += phy.o port.o - usbcore-$(CONFIG_OF) += of.o - usbcore-$(CONFIG_USB_PCI) += hcd-pci.o - usbcore-$(CONFIG_ACPI) += usb-acpi.o -+usbcore-$(CONFIG_SYSCTL) += sysctl.o - - obj-$(CONFIG_USB) += usbcore.o - -diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c -index 9385c745d55e..b62b3da81ac4 100644 ---- a/drivers/usb/core/hub.c -+++ b/drivers/usb/core/hub.c -@@ -5054,9 +5054,6 @@ static int descriptors_changed(struct usb_device *udev, - return changed; - } - --/* sysctl */ --int deny_new_usb __read_mostly = 0; -- - static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus, - u16 portchange) - { -diff --git a/drivers/usb/core/sysctl.c b/drivers/usb/core/sysctl.c -new file mode 100644 -index 000000000000..3fa188ac8f67 ---- /dev/null -+++ b/drivers/usb/core/sysctl.c -@@ -0,0 +1,44 @@ -+#include <linux/errno.h> -+#include <linux/init.h> -+#include <linux/kmemleak.h> -+#include <linux/sysctl.h> -+#include <linux/usb.h> -+ -+static struct ctl_table usb_table[] = { -+ { -+ .procname = "deny_new_usb", -+ .data = &deny_new_usb, -+ .maxlen = sizeof(int), -+ .mode = 0644, -+ .proc_handler = proc_dointvec_minmax_sysadmin, -+ .extra1 = SYSCTL_ZERO, -+ .extra2 = SYSCTL_ONE, -+ }, -+ { } -+}; -+ -+static struct ctl_table usb_root_table[] = { -+ { .procname = "kernel", -+ .mode = 0555, -+ .child = usb_table }, -+ { } -+}; -+ -+static struct ctl_table_header *usb_table_header; -+ -+int __init usb_init_sysctl(void) -+{ -+ usb_table_header = register_sysctl_table(usb_root_table); -+ if (!usb_table_header) { -+ pr_warn("usb: sysctl registration failed\n"); -+ return -ENOMEM; -+ } -+ -+ kmemleak_not_leak(usb_table_header); -+ return 0; -+} -+ -+void usb_exit_sysctl(void) -+{ -+ unregister_sysctl_table(usb_table_header); -+} -diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c -index 9b4ac4415f1a..93b4b798bdcc 100644 ---- a/drivers/usb/core/usb.c -+++ b/drivers/usb/core/usb.c -@@ -72,6 +72,9 @@ MODULE_PARM_DESC(autosuspend, "default autosuspend delay"); - #define usb_autosuspend_delay 0 - #endif - -+int deny_new_usb __read_mostly = 0; -+EXPORT_SYMBOL(deny_new_usb); -+ - static bool match_endpoint(struct usb_endpoint_descriptor *epd, - struct usb_endpoint_descriptor **bulk_in, - struct usb_endpoint_descriptor **bulk_out, -@@ -978,6 +981,9 @@ static int __init usb_init(void) - usb_debugfs_init(); - - usb_acpi_register(); -+ retval = usb_init_sysctl(); -+ if (retval) -+ goto sysctl_init_failed; - retval = bus_register(&usb_bus_type); - if (retval) - goto bus_register_failed; -@@ -1012,6 +1018,8 @@ static int __init usb_init(void) - bus_notifier_failed: - bus_unregister(&usb_bus_type); - bus_register_failed: -+ usb_exit_sysctl(); -+sysctl_init_failed: - usb_acpi_unregister(); - usb_debugfs_cleanup(); - out: -@@ -1035,6 +1043,7 @@ static void __exit usb_exit(void) - usb_hub_cleanup(); - bus_unregister_notifier(&usb_bus_type, &usb_bus_nb); - bus_unregister(&usb_bus_type); -+ usb_exit_sysctl(); - usb_acpi_unregister(); - usb_debugfs_cleanup(); - idr_destroy(&usb_bus_idr); -diff --git a/include/linux/usb.h b/include/linux/usb.h -index 8e7549e3012a..653265115e56 100644 ---- a/include/linux/usb.h -+++ b/include/linux/usb.h -@@ -2035,8 +2035,16 @@ extern void usb_led_activity(enum usb_led_event ev); - static inline void usb_led_activity(enum usb_led_event ev) {} - #endif - --/* sysctl */ -+/* sysctl.c */ - extern int deny_new_usb; -+#ifdef CONFIG_SYSCTL -+extern int usb_init_sysctl(void); -+extern void usb_exit_sysctl(void); -+#else -+static inline int usb_init_sysctl(void) { return 0; } -+static inline void usb_exit_sysctl(void) { } -+#endif /* CONFIG_SYSCTL */ -+ - - #endif /* __KERNEL__ */ - -diff --git a/kernel/sysctl.c b/kernel/sysctl.c -index f867606fbd80..13b619e46ade 100644 ---- a/kernel/sysctl.c -+++ b/kernel/sysctl.c -@@ -106,9 +106,6 @@ - #ifdef CONFIG_USER_NS - #include <linux/user_namespace.h> - #endif --#if IS_ENABLED(CONFIG_USB) --#include <linux/usb.h> --#endif - - #if defined(CONFIG_SYSCTL) - -@@ -2308,17 +2305,6 @@ static struct ctl_table kern_table[] = { - .extra1 = SYSCTL_ZERO, - .extra2 = SYSCTL_ONE, - }, --#if IS_ENABLED(CONFIG_USB) -- { -- .procname = "deny_new_usb", -- .data = &deny_new_usb, -- .maxlen = sizeof(int), -- .mode = 0644, -- .proc_handler = proc_dointvec_minmax_sysadmin, -- .extra1 = SYSCTL_ZERO, -- .extra2 = SYSCTL_ONE, -- }, --#endif - { - .procname = "ngroups_max", - .data = &ngroups_max, --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0099-hard-wire-legacy-checkreqprot-option-to-0.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0099-hard-wire-legacy-checkreqprot-option-to-0.patch deleted file mode 100644 index 7951f0b2f06e..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0099-hard-wire-legacy-checkreqprot-option-to-0.patch +++ /dev/null @@ -1,133 +0,0 @@ -From e98a7d178cfa3c57efb9a642cca152a1ad9c1875 Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Sun, 25 Feb 2018 03:26:45 -0500 -Subject: [PATCH 099/113] hard-wire legacy checkreqprot option to 0 - -The userspace API is left intact for compatibility. - -Signed-off-by: Levente Polyak <levente@leventepolyak.net> ---- - .../admin-guide/kernel-parameters.txt | 11 --------- - security/selinux/Kconfig | 23 ------------------- - security/selinux/hooks.c | 16 +------------ - security/selinux/selinuxfs.c | 12 +--------- - 4 files changed, 2 insertions(+), 60 deletions(-) - -diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt -index e7ea794320e8..0e8e3fdd7005 100644 ---- a/Documentation/admin-guide/kernel-parameters.txt -+++ b/Documentation/admin-guide/kernel-parameters.txt -@@ -518,17 +518,6 @@ - nosocket -- Disable socket memory accounting. - nokmem -- Disable kernel memory accounting. - -- checkreqprot [SELINUX] Set initial checkreqprot flag value. -- Format: { "0" | "1" } -- See security/selinux/Kconfig help text. -- 0 -- check protection applied by kernel (includes -- any implied execute protection). -- 1 -- check protection requested by application. -- Default value is set via a kernel config option. -- Value can be changed at runtime via -- /sys/fs/selinux/checkreqprot. -- Setting checkreqprot to 1 is deprecated. -- - cio_ignore= [S390] - See Documentation/s390/common_io.rst for details. - clk_ignore_unused -diff --git a/security/selinux/Kconfig b/security/selinux/Kconfig -index 76d7ed11513c..ae851a826c26 100644 ---- a/security/selinux/Kconfig -+++ b/security/selinux/Kconfig -@@ -70,29 +70,6 @@ config SECURITY_SELINUX_AVC_STATS - /sys/fs/selinux/avc/cache_stats, which may be monitored via - tools such as avcstat. - --config SECURITY_SELINUX_CHECKREQPROT_VALUE -- int "NSA SELinux checkreqprot default value" -- depends on SECURITY_SELINUX -- range 0 1 -- default 0 -- help -- This option sets the default value for the 'checkreqprot' flag -- that determines whether SELinux checks the protection requested -- by the application or the protection that will be applied by the -- kernel (including any implied execute for read-implies-exec) for -- mmap and mprotect calls. If this option is set to 0 (zero), -- SELinux will default to checking the protection that will be applied -- by the kernel. If this option is set to 1 (one), SELinux will -- default to checking the protection requested by the application. -- The checkreqprot flag may be changed from the default via the -- 'checkreqprot=' boot parameter. It may also be changed at runtime -- via /sys/fs/selinux/checkreqprot if authorized by policy. -- -- WARNING: this option is deprecated and will be removed in a future -- kernel release. -- -- If you are unsure how to answer this question, answer 0. -- - config SECURITY_SELINUX_SIDTAB_HASH_BITS - int "NSA SELinux sidtab hashtable size" - depends on SECURITY_SELINUX -diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c -index c46312710e73..541c65650c5e 100644 ---- a/security/selinux/hooks.c -+++ b/security/selinux/hooks.c -@@ -136,21 +136,7 @@ static int __init selinux_enabled_setup(char *str) - __setup("selinux=", selinux_enabled_setup); - #endif - --static unsigned int selinux_checkreqprot_boot = -- CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE; -- --static int __init checkreqprot_setup(char *str) --{ -- unsigned long checkreqprot; -- -- if (!kstrtoul(str, 0, &checkreqprot)) { -- selinux_checkreqprot_boot = checkreqprot ? 1 : 0; -- if (checkreqprot) -- pr_warn("SELinux: checkreqprot set to 1 via kernel parameter. This is deprecated and will be rejected in a future kernel release.\n"); -- } -- return 1; --} --__setup("checkreqprot=", checkreqprot_setup); -+static const unsigned int selinux_checkreqprot_boot; - - /** - * selinux_secmark_enabled - Check to see if SECMARK is currently enabled -diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c -index 4bde570d56a2..cc5caffc07fa 100644 ---- a/security/selinux/selinuxfs.c -+++ b/security/selinux/selinuxfs.c -@@ -725,7 +725,6 @@ static ssize_t sel_read_checkreqprot(struct file *filp, char __user *buf, - static ssize_t sel_write_checkreqprot(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) - { -- struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info; - char *page; - ssize_t length; - unsigned int new_value; -@@ -749,18 +748,9 @@ static ssize_t sel_write_checkreqprot(struct file *file, const char __user *buf, - return PTR_ERR(page); - - length = -EINVAL; -- if (sscanf(page, "%u", &new_value) != 1) -+ if (sscanf(page, "%u", &new_value) != 1 || new_value) - goto out; - -- if (new_value) { -- char comm[sizeof(current->comm)]; -- -- memcpy(comm, current->comm, sizeof(comm)); -- pr_warn_once("SELinux: %s (%d) set checkreqprot to 1. This is deprecated and will be rejected in a future kernel release.\n", -- comm, current->pid); -- } -- -- checkreqprot_set(fsi->state, (new_value ? 1 : 0)); - length = count; - out: - kfree(page); --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0100-security-tty-Add-owner-user-namespace-to-tty_struct.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0100-security-tty-Add-owner-user-namespace-to-tty_struct.patch deleted file mode 100644 index 13963c0fc39b..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0100-security-tty-Add-owner-user-namespace-to-tty_struct.patch +++ /dev/null @@ -1,70 +0,0 @@ -From 48228b49d9243d026b6c3eee1a8a8547e88c6624 Mon Sep 17 00:00:00 2001 -From: Matt Brown <matt@nmatt.com> -Date: Mon, 29 May 2017 17:37:59 -0400 -Subject: [PATCH 100/113] security: tty: Add owner user namespace to tty_struct - -This patch adds struct user_namespace *owner_user_ns to the tty_struct. -Then it is set to current_user_ns() in the alloc_tty_struct function. - -This is done to facilitate capability checks against the original user -namespace that allocated the tty. - -E.g. ns_capable(tty->owner_user_ns,CAP_SYS_ADMIN) - -This combined with the use of user namespace's will allow hardening -protections to be built to mitigate container escapes that utilize TTY -ioctls such as TIOCSTI. - -See: https://bugzilla.redhat.com/show_bug.cgi?id=1411256 - -Acked-by: Serge Hallyn <serge@hallyn.com> -Reviewed-by: Kees Cook <keescook@chromium.org> -Signed-off-by: Matt Brown <matt@nmatt.com> ---- - drivers/tty/tty_io.c | 2 ++ - include/linux/tty.h | 2 ++ - 2 files changed, 4 insertions(+) - -diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c -index ff87cb51747d..a3b0d0c68c34 100644 ---- a/drivers/tty/tty_io.c -+++ b/drivers/tty/tty_io.c -@@ -171,6 +171,7 @@ static void free_tty_struct(struct tty_struct *tty) - put_device(tty->dev); - kfree(tty->write_buf); - tty->magic = 0xDEADDEAD; -+ put_user_ns(tty->owner_user_ns); - kfree(tty); - } - -@@ -3031,6 +3032,7 @@ struct tty_struct *alloc_tty_struct(struct tty_driver *driver, int idx) - tty->index = idx; - tty_line_name(driver, idx, tty->name); - tty->dev = tty_get_device(tty); -+ tty->owner_user_ns = get_user_ns(current_user_ns()); - - return tty; - } -diff --git a/include/linux/tty.h b/include/linux/tty.h -index bc8caac390fc..29fd018fc255 100644 ---- a/include/linux/tty.h -+++ b/include/linux/tty.h -@@ -14,6 +14,7 @@ - #include <uapi/linux/tty.h> - #include <linux/rwsem.h> - #include <linux/llist.h> -+#include <linux/user_namespace.h> - - - /* -@@ -342,6 +343,7 @@ struct tty_struct { - /* If the tty has a pending do_SAK, queue it here - akpm */ - struct work_struct SAK_work; - struct tty_port *port; -+ struct user_namespace *owner_user_ns; - } __randomize_layout; - - /* Each of a tty's open files has private_data pointing to tty_file_private */ --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0101-security-tty-make-TIOCSTI-ioctl-require-CAP_SYS_ADMI.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0101-security-tty-make-TIOCSTI-ioctl-require-CAP_SYS_ADMI.patch deleted file mode 100644 index 1db8a94a0308..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0101-security-tty-make-TIOCSTI-ioctl-require-CAP_SYS_ADMI.patch +++ /dev/null @@ -1,197 +0,0 @@ -From 04fc45d4854878826c1e2738c0b5528b7f9ee637 Mon Sep 17 00:00:00 2001 -From: Matt Brown <matt@nmatt.com> -Date: Mon, 29 May 2017 17:38:00 -0400 -Subject: [PATCH 101/113] security: tty: make TIOCSTI ioctl require - CAP_SYS_ADMIN - -This introduces the tiocsti_restrict sysctl, whose default is controlled -via CONFIG_SECURITY_TIOCSTI_RESTRICT. When activated, this control -restricts all TIOCSTI ioctl calls from non CAP_SYS_ADMIN users. - -This patch depends on patch 1/2 - -This patch was inspired from GRKERNSEC_HARDEN_TTY. - -This patch would have prevented -https://bugzilla.redhat.com/show_bug.cgi?id=1411256 under the following -conditions: -* non-privileged container -* container run inside new user namespace - -Possible effects on userland: - -There could be a few user programs that would be effected by this -change. -See: <https://codesearch.debian.net/search?q=ioctl%5C%28.*TIOCSTI> -notable programs are: agetty, csh, xemacs and tcsh - -However, I still believe that this change is worth it given that the -Kconfig defaults to n. This will be a feature that is turned on for the -same reason that people activate it when using grsecurity. Users of this -opt-in feature will realize that they are choosing security over some OS -features like unprivileged TIOCSTI ioctls, as should be clear in the -Kconfig help message. - -Threat Model/Patch Rational: - ->From grsecurity's config for GRKERNSEC_HARDEN_TTY. - - | There are very few legitimate uses for this functionality and it - | has made vulnerabilities in several 'su'-like programs possible in - | the past. Even without these vulnerabilities, it provides an - | attacker with an easy mechanism to move laterally among other - | processes within the same user's compromised session. - -So if one process within a tty session becomes compromised it can follow -that additional processes, that are thought to be in different security -boundaries, can be compromised as a result. When using a program like su -or sudo, these additional processes could be in a tty session where TTY -file descriptors are indeed shared over privilege boundaries. - -This is also an excellent writeup about the issue: -<http://www.halfdog.net/Security/2012/TtyPushbackPrivilegeEscalation/> - -When user namespaces are in use, the check for the capability -CAP_SYS_ADMIN is done against the user namespace that originally opened -the tty. - -Acked-by: Serge Hallyn <serge@hallyn.com> -Reviewed-by: Kees Cook <keescook@chromium.org> -Signed-off-by: Matt Brown <matt@nmatt.com> -Signed-off-by: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr> -Signed-off-by: Levente Polyak <levente@leventepolyak.net> ---- - Documentation/admin-guide/sysctl/kernel.rst | 20 ++++++++++++++++++++ - drivers/tty/tty_io.c | 8 ++++++++ - include/linux/tty.h | 2 ++ - kernel/sysctl.c | 14 ++++++++++++++ - security/Kconfig | 13 +++++++++++++ - 5 files changed, 57 insertions(+) - -diff --git a/Documentation/admin-guide/sysctl/kernel.rst b/Documentation/admin-guide/sysctl/kernel.rst -index 4c20e6ded0af..3cd263f8ac46 100644 ---- a/Documentation/admin-guide/sysctl/kernel.rst -+++ b/Documentation/admin-guide/sysctl/kernel.rst -@@ -1385,6 +1385,26 @@ If a value outside of this range is written to ``threads-max`` an - ``EINVAL`` error occurs. - - -+tiocsti_restrict -+================ -+ -+This toggle indicates whether unprivileged users are prevented from using the -+``TIOCSTI`` ioctl to inject commands into other processes which share a tty -+session. -+ -+= ============================================================================ -+0 No restriction, except the default one of only being able to inject commands -+ into one's own tty. -+1 Users must have ``CAP_SYS_ADMIN`` to use the ``TIOCSTI`` ioctl. -+= ============================================================================ -+ -+When user namespaces are in use, the check for ``CAP_SYS_ADMIN`` is done -+against the user namespace that originally opened the tty. -+ -+The kernel config option ``CONFIG_SECURITY_TIOCSTI_RESTRICT`` sets the default -+value of ``tiocsti_restrict``. -+ -+ - traceoff_on_warning - =================== - -diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c -index a3b0d0c68c34..b0acd66e0878 100644 ---- a/drivers/tty/tty_io.c -+++ b/drivers/tty/tty_io.c -@@ -2193,11 +2193,19 @@ static int tty_fasync(int fd, struct file *filp, int on) - * FIXME: may race normal receive processing - */ - -+int tiocsti_restrict = IS_ENABLED(CONFIG_SECURITY_TIOCSTI_RESTRICT); -+ - static int tiocsti(struct tty_struct *tty, char __user *p) - { - char ch, mbz = 0; - struct tty_ldisc *ld; - -+ if (tiocsti_restrict && -+ !ns_capable(tty->owner_user_ns, CAP_SYS_ADMIN)) { -+ dev_warn_ratelimited(tty->dev, -+ "Denied TIOCSTI ioctl for non-privileged process\n"); -+ return -EPERM; -+ } - if ((current->signal->tty != tty) && !capable(CAP_SYS_ADMIN)) - return -EPERM; - if (get_user(ch, p)) -diff --git a/include/linux/tty.h b/include/linux/tty.h -index 29fd018fc255..743e3964a03a 100644 ---- a/include/linux/tty.h -+++ b/include/linux/tty.h -@@ -353,6 +353,8 @@ struct tty_file_private { - struct list_head list; - }; - -+extern int tiocsti_restrict; -+ - /* tty magic number */ - #define TTY_MAGIC 0x5401 - -diff --git a/kernel/sysctl.c b/kernel/sysctl.c -index 13b619e46ade..8fd007fbec4c 100644 ---- a/kernel/sysctl.c -+++ b/kernel/sysctl.c -@@ -106,6 +106,9 @@ - #ifdef CONFIG_USER_NS - #include <linux/user_namespace.h> - #endif -+#if defined CONFIG_TTY -+#include <linux/tty.h> -+#endif - - #if defined(CONFIG_SYSCTL) - -@@ -2295,6 +2298,17 @@ static struct ctl_table kern_table[] = { - .extra1 = SYSCTL_ZERO, - .extra2 = &two, - }, -+#endif -+#if defined CONFIG_TTY -+ { -+ .procname = "tiocsti_restrict", -+ .data = &tiocsti_restrict, -+ .maxlen = sizeof(int), -+ .mode = 0644, -+ .proc_handler = proc_dointvec_minmax_sysadmin, -+ .extra1 = SYSCTL_ZERO, -+ .extra2 = SYSCTL_ONE, -+ }, - #endif - { - .procname = "device_sidechannel_restrict", -diff --git a/security/Kconfig b/security/Kconfig -index f3c995bd79cf..c8ea5a6ecce0 100644 ---- a/security/Kconfig -+++ b/security/Kconfig -@@ -29,6 +29,19 @@ config SECURITY_PERF_EVENTS_RESTRICT - perf_event_open syscall will be permitted unless it is - changed. - -+config SECURITY_TIOCSTI_RESTRICT -+ bool "Restrict unprivileged use of tiocsti command injection" -+ default n -+ help -+ This enforces restrictions on unprivileged users injecting commands -+ into other processes which share a tty session using the TIOCSTI -+ ioctl. This option makes TIOCSTI use require CAP_SYS_ADMIN. -+ -+ If this option is not selected, no restrictions will be enforced -+ unless the tiocsti_restrict sysctl is explicitly set to (1). -+ -+ If you are unsure how to answer this question, answer N. -+ - config SECURITY - bool "Enable different security models" - depends on SYSFS --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0102-enable-SECURITY_TIOCSTI_RESTRICT-by-default.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0102-enable-SECURITY_TIOCSTI_RESTRICT-by-default.patch deleted file mode 100644 index 6455a10a5129..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0102-enable-SECURITY_TIOCSTI_RESTRICT-by-default.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 714cff25e38b9cc3e069a2cd06b480227769c7ec Mon Sep 17 00:00:00 2001 -From: Daniel Micay <danielmicay@gmail.com> -Date: Wed, 3 May 2017 23:36:14 -0400 -Subject: [PATCH 102/113] enable SECURITY_TIOCSTI_RESTRICT by default - -Signed-off-by: Daniel Micay <danielmicay@gmail.com> ---- - security/Kconfig | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/security/Kconfig b/security/Kconfig -index c8ea5a6ecce0..615205c0113b 100644 ---- a/security/Kconfig -+++ b/security/Kconfig -@@ -31,7 +31,7 @@ config SECURITY_PERF_EVENTS_RESTRICT - - config SECURITY_TIOCSTI_RESTRICT - bool "Restrict unprivileged use of tiocsti command injection" -- default n -+ default y - help - This enforces restrictions on unprivileged users injecting commands - into other processes which share a tty session using the TIOCSTI --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0103-disable-unprivileged-eBPF-access-by-default.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0103-disable-unprivileged-eBPF-access-by-default.patch deleted file mode 100644 index 4d960371cc97..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0103-disable-unprivileged-eBPF-access-by-default.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 6e0e1a78fea78d53a893446f4c98018624ef1a72 Mon Sep 17 00:00:00 2001 -From: Levente Polyak <levente@leventepolyak.net> -Date: Mon, 7 May 2018 20:37:07 +0200 -Subject: [PATCH 103/113] disable unprivileged eBPF access by default - ---- - kernel/bpf/syscall.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c -index 9433ab9995cd..348c36273f1a 100644 ---- a/kernel/bpf/syscall.c -+++ b/kernel/bpf/syscall.c -@@ -50,7 +50,7 @@ static DEFINE_SPINLOCK(map_idr_lock); - static DEFINE_IDR(link_idr); - static DEFINE_SPINLOCK(link_idr_lock); - --int sysctl_unprivileged_bpf_disabled __read_mostly; -+int sysctl_unprivileged_bpf_disabled __read_mostly = 1; - - static const struct bpf_map_ops * const bpf_map_types[] = { - #define BPF_PROG_TYPE(_id, _name, prog_ctx_type, kern_ctx_type) --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0104-enable-BPF-JIT-hardening-by-default-if-available.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0104-enable-BPF-JIT-hardening-by-default-if-available.patch deleted file mode 100644 index a9dc01c78239..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0104-enable-BPF-JIT-hardening-by-default-if-available.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 1cbafc2eaedb28b5b4d7ed12e452c77b0ef89385 Mon Sep 17 00:00:00 2001 -From: Levente Polyak <levente@leventepolyak.net> -Date: Mon, 7 May 2018 20:37:55 +0200 -Subject: [PATCH 104/113] enable BPF JIT hardening by default (if available) - ---- - kernel/bpf/core.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c -index 55454d2278b1..de02792dc2fc 100644 ---- a/kernel/bpf/core.c -+++ b/kernel/bpf/core.c -@@ -524,7 +524,7 @@ void bpf_prog_kallsyms_del_all(struct bpf_prog *fp) - /* All BPF JIT sysctl knobs here. */ - int bpf_jit_enable __read_mostly = IS_BUILTIN(CONFIG_BPF_JIT_DEFAULT_ON); - int bpf_jit_kallsyms __read_mostly = IS_BUILTIN(CONFIG_BPF_JIT_DEFAULT_ON); --int bpf_jit_harden __read_mostly; -+int bpf_jit_harden __read_mostly = 2; - long bpf_jit_limit __read_mostly; - - static void --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0105-enable-protected_-fifos-regular-by-default.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0105-enable-protected_-fifos-regular-by-default.patch deleted file mode 100644 index b34d802b3138..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0105-enable-protected_-fifos-regular-by-default.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 10eb8949c298512a3cfc98d40a87090a06c1a09b Mon Sep 17 00:00:00 2001 -From: Levente Polyak <levente@leventepolyak.net> -Date: Sun, 4 Nov 2018 18:48:53 +0100 -Subject: [PATCH 105/113] enable protected_{fifos,regular} by default - ---- - fs/namei.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/fs/namei.c b/fs/namei.c -index 59ff3ce21026..72f912c68975 100644 ---- a/fs/namei.c -+++ b/fs/namei.c -@@ -934,8 +934,8 @@ static inline void put_link(struct nameidata *nd) - - int sysctl_protected_symlinks __read_mostly = 1; - int sysctl_protected_hardlinks __read_mostly = 1; --int sysctl_protected_fifos __read_mostly; --int sysctl_protected_regular __read_mostly; -+int sysctl_protected_fifos __read_mostly = 2; -+int sysctl_protected_regular __read_mostly = 2; - - /** - * may_follow_link - Check symlink following for unsafe situations --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0106-modpost-Add-CONFIG_DEBUG_WRITABLE_FUNCTION_POINTERS_.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0106-modpost-Add-CONFIG_DEBUG_WRITABLE_FUNCTION_POINTERS_.patch deleted file mode 100644 index aaa5f09dbe16..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0106-modpost-Add-CONFIG_DEBUG_WRITABLE_FUNCTION_POINTERS_.patch +++ /dev/null @@ -1,129 +0,0 @@ -From 814f4aea891f6c09e11ea22029ce6531c7d40cd2 Mon Sep 17 00:00:00 2001 -From: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr> -Date: Mon, 6 May 2019 17:07:11 +0200 -Subject: [PATCH 106/113] modpost: Add - CONFIG_DEBUG_WRITABLE_FUNCTION_POINTERS_VERBOSE - -With 46c7dd56d541 ("modpost: always show verbose warning for section -mismatch"), sec_mismatch_verbose was removed which would have printed -errors for all writable function pointers during compilation if it -hadn't been "#if 0"ed out for quite some time now. - -Let's introduce a new DEBUG_WRITABLE_FUNCTION_POINTERS_VERBOSE Kconfig -option to cleanly control this linux-hardened functionality. - -Signed-off-by: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr> -Signed-off-by: Levente Polyak <levente@leventepolyak.net> ---- - lib/Kconfig.debug | 3 +++ - scripts/Makefile.modpost | 1 + - scripts/mod/modpost.c | 25 ++++++++++++++++--------- - 3 files changed, 20 insertions(+), 9 deletions(-) - -diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug -index 4a1a32a059f4..5fce84adc315 100644 ---- a/lib/Kconfig.debug -+++ b/lib/Kconfig.debug -@@ -374,6 +374,9 @@ config DEBUG_FORCE_FUNCTION_ALIGN_32B - - It is mainly for debug and performance tuning use. - -+config DEBUG_WRITABLE_FUNCTION_POINTERS_VERBOSE -+ bool "Enable verbose reporting of writable function pointers" -+ - # - # Select this config option from the architecture Kconfig, if it - # is preferred to always offer frame pointers as a config -diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost -index f54b6ac37ac2..e53b3057d4cb 100644 ---- a/scripts/Makefile.modpost -+++ b/scripts/Makefile.modpost -@@ -47,6 +47,7 @@ MODPOST = scripts/mod/modpost \ - $(if $(CONFIG_MODVERSIONS),-m) \ - $(if $(CONFIG_MODULE_SRCVERSION_ALL),-a) \ - $(if $(CONFIG_SECTION_MISMATCH_WARN_ONLY),,-E) \ -+ $(if $(CONFIG_DEBUG_WRITABLE_FUNCTION_POINTERS_VERBOSE),-f) \ - $(if $(KBUILD_MODPOST_WARN),-w) \ - -o $@ - -diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c -index 50e9baefc4e7..2cbc4e8a6295 100644 ---- a/scripts/mod/modpost.c -+++ b/scripts/mod/modpost.c -@@ -34,8 +34,9 @@ static int external_module = 0; - static int warn_unresolved = 0; - /* How a symbol is exported */ - static int sec_mismatch_count = 0; --static int writable_fptr_count = 0; - static int sec_mismatch_fatal = 0; -+static int writable_fptr_count = 0; -+static int writable_fptr_verbose = 0; - /* ignore missing files */ - static int ignore_missing_files; - /* If set to 1, only warn (instead of error) about missing ns imports */ -@@ -1466,10 +1467,13 @@ static void report_sec_mismatch(const char *modname, - char *prl_from; - char *prl_to; - -- if (mismatch->mismatch == DATA_TO_TEXT) -+ if (mismatch->mismatch == DATA_TO_TEXT) { - writable_fptr_count++; -- else -+ if (!writable_fptr_verbose) -+ return; -+ } else { - sec_mismatch_count++; -+ } - - get_pretty_name(from_is_func, &from, &from_p); - get_pretty_name(to_is_func, &to, &to_p); -@@ -1592,12 +1596,10 @@ static void report_sec_mismatch(const char *modname, - "we should never get here."); - break; - case DATA_TO_TEXT: --#if 0 - fprintf(stderr, - "The %s %s:%s references\n" - "the %s %s:%s%s\n", - from, fromsec, fromsym, to, tosec, tosym, to_p); --#endif - break; - } - fprintf(stderr, "\n"); -@@ -2578,7 +2580,7 @@ int main(int argc, char **argv) - struct dump_list *dump_read_start = NULL; - struct dump_list **dump_read_iter = &dump_read_start; - -- while ((opt = getopt(argc, argv, "ei:mnT:o:awENd:")) != -1) { -+ while ((opt = getopt(argc, argv, "ei:fmnT:o:awENd:")) != -1) { - switch (opt) { - case 'e': - external_module = 1; -@@ -2589,6 +2591,9 @@ int main(int argc, char **argv) - (*dump_read_iter)->file = optarg; - dump_read_iter = &(*dump_read_iter)->next; - break; -+ case 'f': -+ writable_fptr_verbose = 1; -+ break; - case 'm': - modversions = 1; - break; -@@ -2689,9 +2694,11 @@ int main(int argc, char **argv) - } - - free(buf.p); -- if (writable_fptr_count) -- warn("modpost: Found %d writable function pointer(s).\n", -- writable_fptr_count); -+ if (writable_fptr_count && !writable_fptr_verbose) -+ warn("modpost: Found %d writable function pointer%s.\n" -+ "To see full details build your kernel with:\n" -+ "'make CONFIG_DEBUG_WRITABLE_FUNCTION_POINTERS_VERBOSE=y'\n", -+ writable_fptr_count, (writable_fptr_count == 1 ? "" : "s")); - - return err; - } --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0107-mm-Fix-extra_latent_entropy.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0107-mm-Fix-extra_latent_entropy.patch deleted file mode 100644 index c02ede21220b..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0107-mm-Fix-extra_latent_entropy.patch +++ /dev/null @@ -1,103 +0,0 @@ -From 5922d5d781f7f95ffbd4dc08be6236c84b2a8c82 Mon Sep 17 00:00:00 2001 -From: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr> -Date: Tue, 7 May 2019 11:46:21 +0200 -Subject: [PATCH 107/113] mm: Fix extra_latent_entropy - -Commit a9cd410a3d29 ("mm/page_alloc.c: memory hotplug: free pages as -higher order") changed `static void __init __free_pages_boot_core()` -into `void __free_pages_core()`, causing the following section mismatch -warning at compile time: - - WARNING: vmlinux.o(.text+0x180fe4): Section mismatch in reference from the function __free_pages_core() to the variable .meminit.data:extra_latent_entropy - The function __free_pages_core() references the variable __meminitdata extra_latent_entropy. - This is often because __free_pages_core lacks a __meminitdata annotation or the annotation of extra_latent_entropy is wrong. - -This commit is an attempt at fixing this issue. I'm not sure it's OK as -we are accessing pages that are still managed by the bootmem allocator. -The prefetching part is not an issue as it only affects struct pages. - -Signed-off-by: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr> ---- - mm/page_alloc.c | 38 ++++++++++++++++++++++---------------- - 1 file changed, 22 insertions(+), 16 deletions(-) - -diff --git a/mm/page_alloc.c b/mm/page_alloc.c -index 965d49be78ed..cb7501769331 100644 ---- a/mm/page_alloc.c -+++ b/mm/page_alloc.c -@@ -1539,6 +1539,25 @@ static void __free_pages_ok(struct page *page, unsigned int order, - local_irq_restore(flags); - } - -+static void __init __gather_extra_latent_entropy(struct page *page, -+ unsigned int nr_pages) -+{ -+ if (extra_latent_entropy && !PageHighMem(page) && page_to_pfn(page) < 0x100000) { -+ unsigned long hash = 0; -+ size_t index, end = PAGE_SIZE * nr_pages / sizeof hash; -+ const unsigned long *data = lowmem_page_address(page); -+ -+ for (index = 0; index < end; index++) -+ hash ^= hash + data[index]; -+#ifdef CONFIG_GCC_PLUGIN_LATENT_ENTROPY -+ latent_entropy ^= hash; -+ add_device_randomness((const void *)&latent_entropy, sizeof(latent_entropy)); -+#else -+ add_device_randomness((const void *)&hash, sizeof(hash)); -+#endif -+ } -+} -+ - void __free_pages_core(struct page *page, unsigned int order) - { - unsigned int nr_pages = 1 << order; -@@ -1558,22 +1577,6 @@ void __free_pages_core(struct page *page, unsigned int order) - } - __ClearPageReserved(p); - set_page_count(p, 0); -- -- if (extra_latent_entropy && !PageHighMem(page) && page_to_pfn(page) < 0x100000) { -- unsigned long hash = 0; -- size_t index, end = PAGE_SIZE * nr_pages / sizeof hash; -- const unsigned long *data = lowmem_page_address(page); -- -- for (index = 0; index < end; index++) -- hash ^= hash + data[index]; --#ifdef CONFIG_GCC_PLUGIN_LATENT_ENTROPY -- latent_entropy ^= hash; -- add_device_randomness((const void *)&latent_entropy, sizeof(latent_entropy)); --#else -- add_device_randomness((const void *)&hash, sizeof(hash)); --#endif -- } -- - atomic_long_add(nr_pages, &page_zone(page)->managed_pages); - - /* -@@ -1632,6 +1635,7 @@ void __init memblock_free_pages(struct page *page, unsigned long pfn, - { - if (early_page_uninitialised(pfn)) - return; -+ __gather_extra_latent_entropy(page, 1 << order); - __free_pages_core(page, order); - } - -@@ -1723,6 +1727,7 @@ static void __init deferred_free_range(unsigned long pfn, - if (nr_pages == pageblock_nr_pages && - (pfn & (pageblock_nr_pages - 1)) == 0) { - set_pageblock_migratetype(page, MIGRATE_MOVABLE); -+ __gather_extra_latent_entropy(page, 1 << pageblock_order); - __free_pages_core(page, pageblock_order); - return; - } -@@ -1730,6 +1735,7 @@ static void __init deferred_free_range(unsigned long pfn, - for (i = 0; i < nr_pages; i++, page++, pfn++) { - if ((pfn & (pageblock_nr_pages - 1)) == 0) - set_pageblock_migratetype(page, MIGRATE_MOVABLE); -+ __gather_extra_latent_entropy(page, 1); - __free_pages_core(page, 0); - } - } --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0108-add-CONFIG-for-unprivileged_userfaultfd.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0108-add-CONFIG-for-unprivileged_userfaultfd.patch deleted file mode 100644 index 30dafb7cef67..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0108-add-CONFIG-for-unprivileged_userfaultfd.patch +++ /dev/null @@ -1,68 +0,0 @@ -From 4a95200b96f6433aabae2f224a306f89c67344be Mon Sep 17 00:00:00 2001 -From: Levente Polyak <levente@leventepolyak.net> -Date: Wed, 2 Oct 2019 01:22:17 +0200 -Subject: [PATCH 108/113] add CONFIG for unprivileged_userfaultfd - -When disabled, unprivileged users will not be able to use the userfaultfd -syscall. Userfaultfd provide attackers with a way to stall a kernel -thread in the middle of memory accesses from userspace by initiating an -access on an unmapped page. To avoid various heap grooming and heap -spraying techniques for exploiting use-after-free flaws this should be -disabled by default. - -This setting can be overridden at runtime via the -vm.unprivileged_userfaultfd sysctl. - -Signed-off-by: Levente Polyak <levente@leventepolyak.net> ---- - fs/userfaultfd.c | 4 ++++ - init/Kconfig | 17 +++++++++++++++++ - 2 files changed, 21 insertions(+) - -diff --git a/fs/userfaultfd.c b/fs/userfaultfd.c -index 000b457ad087..06d35ecdcbc8 100644 ---- a/fs/userfaultfd.c -+++ b/fs/userfaultfd.c -@@ -28,7 +28,11 @@ - #include <linux/security.h> - #include <linux/hugetlb.h> - -+#ifdef CONFIG_USERFAULTFD_UNPRIVILEGED - int sysctl_unprivileged_userfaultfd __read_mostly = 1; -+#else -+int sysctl_unprivileged_userfaultfd __read_mostly; -+#endif - - static struct kmem_cache *userfaultfd_ctx_cachep __read_mostly; - -diff --git a/init/Kconfig b/init/Kconfig -index a7b5a4cb7939..2feea719cc25 100644 ---- a/init/Kconfig -+++ b/init/Kconfig -@@ -1745,6 +1745,23 @@ config USERFAULTFD - Enable the userfaultfd() system call that allows to intercept and - handle page faults in userland. - -+config USERFAULTFD_UNPRIVILEGED -+ bool "Allow unprivileged users to use the userfaultfd syscall" -+ depends on USERFAULTFD -+ default n -+ help -+ When disabled, unprivileged users will not be able to use the userfaultfd -+ syscall. Userfaultfd provide attackers with a way to stall a kernel -+ thread in the middle of memory accesses from userspace by initiating an -+ access on an unmapped page. To avoid various heap grooming and heap -+ spraying techniques for exploiting use-after-free flaws this should be -+ disabled by default. -+ -+ This setting can be overridden at runtime via the -+ vm.unprivileged_userfaultfd sysctl. -+ -+ If unsure, say N. -+ - config ARCH_HAS_MEMBARRIER_CALLBACKS - bool - --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0109-slub-Extend-init_on_alloc-to-slab-caches-with-constr.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0109-slub-Extend-init_on_alloc-to-slab-caches-with-constr.patch deleted file mode 100644 index 56909fb40613..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0109-slub-Extend-init_on_alloc-to-slab-caches-with-constr.patch +++ /dev/null @@ -1,81 +0,0 @@ -From 9c7d5fd0b1087cb52989ccc025a073b4a143c7a6 Mon Sep 17 00:00:00 2001 -From: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr> -Date: Fri, 29 Nov 2019 16:27:14 +0100 -Subject: [PATCH 109/113] slub: Extend init_on_alloc to slab caches with - constructors - -Signed-off-by: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr> -Signed-off-by: Levente Polyak <levente@leventepolyak.net> ---- - mm/slab.h | 2 ++ - mm/slub.c | 23 ++++++++++++++++++----- - 2 files changed, 20 insertions(+), 5 deletions(-) - -diff --git a/mm/slab.h b/mm/slab.h -index 105dba485a7e..2138deacf719 100644 ---- a/mm/slab.h -+++ b/mm/slab.h -@@ -630,8 +630,10 @@ static inline void cache_random_seq_destroy(struct kmem_cache *cachep) { } - static inline bool slab_want_init_on_alloc(gfp_t flags, struct kmem_cache *c) - { - if (static_branch_unlikely(&init_on_alloc)) { -+#ifndef CONFIG_SLUB - if (c->ctor) - return false; -+#endif - if (c->flags & (SLAB_TYPESAFE_BY_RCU | SLAB_POISON)) - return flags & __GFP_ZERO; - return true; -diff --git a/mm/slub.c b/mm/slub.c -index dd68308c94a9..802f9051bc1a 100644 ---- a/mm/slub.c -+++ b/mm/slub.c -@@ -1635,9 +1635,10 @@ static inline bool slab_free_freelist_hook(struct kmem_cache *s, - * need to show a valid freepointer to check_object(). - * - * Note that doing this for all caches (not just ctor -- * ones, which have s->offset != NULL)) causes a GPF, -- * due to KASAN poisoning and the way set_freepointer() -- * eventually dereferences the freepointer. -+ * ones, which have s->offset >= object_size)) causes a -+ * GPF, due to KASAN poisoning and the way -+ * set_freepointer() eventually dereferences the -+ * freepointer. - */ - set_freepointer(s, object, NULL); - } -@@ -2955,8 +2956,14 @@ static __always_inline void *slab_alloc_node(struct kmem_cache *s, - if (s->ctor) - s->ctor(object); - kasan_poison_object_data(s, object); -- } else if (unlikely(slab_want_init_on_alloc(gfpflags, s)) && object) -+ } else if (unlikely(slab_want_init_on_alloc(gfpflags, s)) && object) { - memset(object, 0, s->object_size); -+ if (s->ctor) { -+ kasan_unpoison_object_data(s, object); -+ s->ctor(object); -+ kasan_poison_object_data(s, object); -+ } -+ } - - if (object) { - check_canary(s, object, s->random_inactive); -@@ -3416,8 +3423,14 @@ int kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size, - } else if (unlikely(slab_want_init_on_alloc(flags, s))) { - int j; - -- for (j = 0; j < i; j++) -+ for (j = 0; j < i; j++) { - memset(p[j], 0, s->object_size); -+ if (s->ctor) { -+ kasan_unpoison_object_data(s, p[j]); -+ s->ctor(p[j]); -+ kasan_poison_object_data(s, p[j]); -+ } -+ } - } - - for (k = 0; k < i; k++) { --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0110-net-tcp-add-option-to-disable-TCP-simultaneous-conne.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0110-net-tcp-add-option-to-disable-TCP-simultaneous-conne.patch deleted file mode 100644 index 9e7cfcfc32f3..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0110-net-tcp-add-option-to-disable-TCP-simultaneous-conne.patch +++ /dev/null @@ -1,151 +0,0 @@ -From b39a5838a263e450e0871054a7832cd5149a8f0a Mon Sep 17 00:00:00 2001 -From: madaidan <50278627+madaidan@users.noreply.github.com> -Date: Sun, 9 Feb 2020 00:03:41 +0000 -Subject: [PATCH 110/113] net: tcp: add option to disable TCP simultaneous - connect - -This is modified from Brad Spengler/PaX Team's code in the last public -patch of grsecurity/PaX based on my understanding of the code. Changes -or omissions from the original code are mine and don't reflect the -original grsecurity/PaX code. - -TCP simultaneous connect adds a weakness in Linux's implementation of -TCP that allows two clients to connect to each other without either -entering a listening state. The weakness allows an attacker to easily -prevent a client from connecting to a known server provided the source -port for the connection is guessed correctly. - -As the weakness could be used to prevent an antivirus or IPS from -fetching updates, or prevent an SSL gateway from fetching a CRL, it -should be eliminated. - -This creates a net.ipv4.tcp_simult_connect sysctl that when disabled, -disables TCP simultaneous connect. - -Reviewd-by: Thibaut Sautereau <thibaut.sautereau@ssi.gouv.fr> -Reviewd-by: Levente Polyak <levente@leventepolyak.net> -Signed-off-by: Levente Polyak <levente@leventepolyak.net> ---- - Documentation/networking/ip-sysctl.rst | 18 ++++++++++++++++++ - include/net/tcp.h | 1 + - net/ipv4/Kconfig | 23 +++++++++++++++++++++++ - net/ipv4/sysctl_net_ipv4.c | 9 +++++++++ - net/ipv4/tcp_input.c | 3 ++- - 5 files changed, 53 insertions(+), 1 deletion(-) - -diff --git a/Documentation/networking/ip-sysctl.rst b/Documentation/networking/ip-sysctl.rst -index 25e6673a085a..76f1892d65ed 100644 ---- a/Documentation/networking/ip-sysctl.rst -+++ b/Documentation/networking/ip-sysctl.rst -@@ -665,6 +665,24 @@ tcp_comp_sack_nr - INTEGER - - Default : 44 - -+tcp_simult_connect - BOOLEAN -+ Enable TCP simultaneous connect that adds a weakness in Linux's strict -+ implementation of TCP that allows two clients to connect to each other -+ without either entering a listening state. The weakness allows an attacker -+ to easily prevent a client from connecting to a known server provided the -+ source port for the connection is guessed correctly. -+ -+ As the weakness could be used to prevent an antivirus or IPS from fetching -+ updates, or prevent an SSL gateway from fetching a CRL, it should be -+ eliminated by disabling this option. Though Linux is one of few operating -+ systems supporting simultaneous connect, it has no legitimate use in -+ practice and is rarely supported by firewalls. -+ -+ Disabling this may break TCP STUNT which is used by some applications for -+ NAT traversal. -+ -+ Default: Value of CONFIG_TCP_SIMULT_CONNECT_DEFAULT_ON -+ - tcp_slow_start_after_idle - BOOLEAN - If set, provide RFC2861 behavior and time out the congestion - window after an idle period. An idle period is defined at -diff --git a/include/net/tcp.h b/include/net/tcp.h -index fe9747ee70a6..116c227bb292 100644 ---- a/include/net/tcp.h -+++ b/include/net/tcp.h -@@ -245,6 +245,7 @@ void tcp_time_wait(struct sock *sk, int state, int timeo); - /* sysctl variables for tcp */ - extern int sysctl_tcp_max_orphans; - extern long sysctl_tcp_mem[3]; -+extern int sysctl_tcp_simult_connect; - - #define TCP_RACK_LOSS_DETECTION 0x1 /* Use RACK to detect losses */ - #define TCP_RACK_STATIC_REO_WND 0x2 /* Use static RACK reo wnd */ -diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig -index 989e005bf698..d1584b4b39f9 100644 ---- a/net/ipv4/Kconfig -+++ b/net/ipv4/Kconfig -@@ -743,3 +743,26 @@ config TCP_MD5SIG - on the Internet. - - If unsure, say N. -+ -+config TCP_SIMULT_CONNECT_DEFAULT_ON -+ bool "Enable TCP simultaneous connect" -+ help -+ Enable TCP simultaneous connect that adds a weakness in Linux's strict -+ implementation of TCP that allows two clients to connect to each other -+ without either entering a listening state. The weakness allows an -+ attacker to easily prevent a client from connecting to a known server -+ provided the source port for the connection is guessed correctly. -+ -+ As the weakness could be used to prevent an antivirus or IPS from -+ fetching updates, or prevent an SSL gateway from fetching a CRL, it -+ should be eliminated by disabling this option. Though Linux is one of -+ few operating systems supporting simultaneous connect, it has no -+ legitimate use in practice and is rarely supported by firewalls. -+ -+ Disabling this may break TCP STUNT which is used by some applications -+ for NAT traversal. -+ -+ This setting can be overridden at runtime via the -+ net.ipv4.tcp_simult_connect sysctl. -+ -+ If unsure, say N. -diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c -index 3e5f4f2e705e..791329c77dea 100644 ---- a/net/ipv4/sysctl_net_ipv4.c -+++ b/net/ipv4/sysctl_net_ipv4.c -@@ -588,6 +588,15 @@ static struct ctl_table ipv4_table[] = { - .mode = 0644, - .proc_handler = proc_do_static_key, - }, -+ { -+ .procname = "tcp_simult_connect", -+ .data = &sysctl_tcp_simult_connect, -+ .maxlen = sizeof(int), -+ .mode = 0644, -+ .proc_handler = proc_dointvec_minmax, -+ .extra1 = SYSCTL_ZERO, -+ .extra2 = SYSCTL_ONE, -+ }, - { } - }; - -diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c -index fac5c1469cee..7c3ffb3f4002 100644 ---- a/net/ipv4/tcp_input.c -+++ b/net/ipv4/tcp_input.c -@@ -82,6 +82,7 @@ - #include <net/mptcp.h> - - int sysctl_tcp_max_orphans __read_mostly = NR_FILE; -+int sysctl_tcp_simult_connect __read_mostly = IS_ENABLED(CONFIG_TCP_SIMULT_CONNECT_DEFAULT_ON); - - #define FLAG_DATA 0x01 /* Incoming frame contained data. */ - #define FLAG_WIN_UPDATE 0x02 /* Incoming ACK was a window update. */ -@@ -6197,7 +6198,7 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, - tcp_paws_reject(&tp->rx_opt, 0)) - goto discard_and_undo; - -- if (th->syn) { -+ if (th->syn && sysctl_tcp_simult_connect) { - /* We see SYN without ACK. It is attempt of - * simultaneous connect with crossed SYNs. - * Particularly, it can be connect to self. --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0111-dccp-ccid-move-timers-to-struct-dccp_sock.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0111-dccp-ccid-move-timers-to-struct-dccp_sock.patch deleted file mode 100644 index 686a2d2b7a57..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0111-dccp-ccid-move-timers-to-struct-dccp_sock.patch +++ /dev/null @@ -1,238 +0,0 @@ -From 1f98b5c4225878e41a89a94328c3c6368a97c81a Mon Sep 17 00:00:00 2001 -From: Thadeu Lima de Souza Cascardo <cascardo@canonical.com> -Date: Tue, 13 Oct 2020 19:18:48 +0200 -Subject: [PATCH 111/113] dccp: ccid: move timers to struct dccp_sock - -When dccps_hc_tx_ccid is freed, ccid timers may still trigger. The reason -del_timer_sync can't be used is because this relies on keeping a reference -to struct sock. But as we keep a pointer to dccps_hc_tx_ccid and free that -during disconnect, the timer should really belong to struct dccp_sock. - -This addresses CVE-2020-16119. - -Fixes: 839a6094140a (net: dccp: Convert timers to use timer_setup()) -Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@canonical.com> -Signed-off-by: Kleber Sacilotto de Souza <kleber.souza@canonical.com> ---- - include/linux/dccp.h | 2 ++ - net/dccp/ccids/ccid2.c | 32 +++++++++++++++++++------------- - net/dccp/ccids/ccid3.c | 30 ++++++++++++++++++++---------- - 3 files changed, 41 insertions(+), 23 deletions(-) - -diff --git a/include/linux/dccp.h b/include/linux/dccp.h -index 07e547c02fd8..504afa1a4be6 100644 ---- a/include/linux/dccp.h -+++ b/include/linux/dccp.h -@@ -259,6 +259,7 @@ struct dccp_ackvec; - * @dccps_sync_scheduled - flag which signals "send out-of-band message soon" - * @dccps_xmitlet - tasklet scheduled by the TX CCID to dequeue data packets - * @dccps_xmit_timer - used by the TX CCID to delay sending (rate-based pacing) -+ * @dccps_ccid_timer - used by the CCIDs - * @dccps_syn_rtt - RTT sample from Request/Response exchange (in usecs) - */ - struct dccp_sock { -@@ -303,6 +304,7 @@ struct dccp_sock { - __u8 dccps_sync_scheduled:1; - struct tasklet_struct dccps_xmitlet; - struct timer_list dccps_xmit_timer; -+ struct timer_list dccps_ccid_timer; - }; - - static inline struct dccp_sock *dccp_sk(const struct sock *sk) -diff --git a/net/dccp/ccids/ccid2.c b/net/dccp/ccids/ccid2.c -index 3da1f77bd039..dbca1f1e2449 100644 ---- a/net/dccp/ccids/ccid2.c -+++ b/net/dccp/ccids/ccid2.c -@@ -126,21 +126,26 @@ static void dccp_tasklet_schedule(struct sock *sk) - - static void ccid2_hc_tx_rto_expire(struct timer_list *t) - { -- struct ccid2_hc_tx_sock *hc = from_timer(hc, t, tx_rtotimer); -- struct sock *sk = hc->sk; -- const bool sender_was_blocked = ccid2_cwnd_network_limited(hc); -+ struct dccp_sock *dp = from_timer(dp, t, dccps_ccid_timer); -+ struct sock *sk = (struct sock *)dp; -+ struct ccid2_hc_tx_sock *hc; -+ bool sender_was_blocked; - - bh_lock_sock(sk); -+ -+ if (inet_sk_state_load(sk) == DCCP_CLOSED) -+ goto out; -+ -+ hc = ccid_priv(dp->dccps_hc_tx_ccid); -+ sender_was_blocked = ccid2_cwnd_network_limited(hc); -+ - if (sock_owned_by_user(sk)) { -- sk_reset_timer(sk, &hc->tx_rtotimer, jiffies + HZ / 5); -+ sk_reset_timer(sk, &dp->dccps_ccid_timer, jiffies + HZ / 5); - goto out; - } - - ccid2_pr_debug("RTO_EXPIRE\n"); - -- if (sk->sk_state == DCCP_CLOSED) -- goto out; -- - /* back-off timer */ - hc->tx_rto <<= 1; - if (hc->tx_rto > DCCP_RTO_MAX) -@@ -166,7 +171,7 @@ static void ccid2_hc_tx_rto_expire(struct timer_list *t) - if (sender_was_blocked) - dccp_tasklet_schedule(sk); - /* restart backed-off timer */ -- sk_reset_timer(sk, &hc->tx_rtotimer, jiffies + hc->tx_rto); -+ sk_reset_timer(sk, &dp->dccps_ccid_timer, jiffies + hc->tx_rto); - out: - bh_unlock_sock(sk); - sock_put(sk); -@@ -330,7 +335,7 @@ static void ccid2_hc_tx_packet_sent(struct sock *sk, unsigned int len) - } - #endif - -- sk_reset_timer(sk, &hc->tx_rtotimer, jiffies + hc->tx_rto); -+ sk_reset_timer(sk, &dp->dccps_ccid_timer, jiffies + hc->tx_rto); - - #ifdef CONFIG_IP_DCCP_CCID2_DEBUG - do { -@@ -700,9 +705,9 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) - - /* restart RTO timer if not all outstanding data has been acked */ - if (hc->tx_pipe == 0) -- sk_stop_timer(sk, &hc->tx_rtotimer); -+ sk_stop_timer(sk, &dp->dccps_ccid_timer); - else -- sk_reset_timer(sk, &hc->tx_rtotimer, jiffies + hc->tx_rto); -+ sk_reset_timer(sk, &dp->dccps_ccid_timer, jiffies + hc->tx_rto); - done: - /* check if incoming Acks allow pending packets to be sent */ - if (sender_was_blocked && !ccid2_cwnd_network_limited(hc)) -@@ -737,17 +742,18 @@ static int ccid2_hc_tx_init(struct ccid *ccid, struct sock *sk) - hc->tx_last_cong = hc->tx_lsndtime = hc->tx_cwnd_stamp = ccid2_jiffies32; - hc->tx_cwnd_used = 0; - hc->sk = sk; -- timer_setup(&hc->tx_rtotimer, ccid2_hc_tx_rto_expire, 0); -+ timer_setup(&dp->dccps_ccid_timer, ccid2_hc_tx_rto_expire, 0); - INIT_LIST_HEAD(&hc->tx_av_chunks); - return 0; - } - - static void ccid2_hc_tx_exit(struct sock *sk) - { -+ struct dccp_sock *dp = dccp_sk(sk); - struct ccid2_hc_tx_sock *hc = ccid2_hc_tx_sk(sk); - int i; - -- sk_stop_timer(sk, &hc->tx_rtotimer); -+ sk_stop_timer(sk, &dp->dccps_ccid_timer); - - for (i = 0; i < hc->tx_seqbufc; i++) - kfree(hc->tx_seqbuf[i]); -diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c -index b9ee1a4a8955..685f4d046c0d 100644 ---- a/net/dccp/ccids/ccid3.c -+++ b/net/dccp/ccids/ccid3.c -@@ -184,17 +184,24 @@ static inline void ccid3_hc_tx_update_win_count(struct ccid3_hc_tx_sock *hc, - - static void ccid3_hc_tx_no_feedback_timer(struct timer_list *t) - { -- struct ccid3_hc_tx_sock *hc = from_timer(hc, t, tx_no_feedback_timer); -- struct sock *sk = hc->sk; -+ struct dccp_sock *dp = from_timer(dp, t, dccps_ccid_timer); -+ struct ccid3_hc_tx_sock *hc; -+ struct sock *sk = (struct sock *)dp; - unsigned long t_nfb = USEC_PER_SEC / 5; - - bh_lock_sock(sk); -+ -+ if (inet_sk_state_load(sk) == DCCP_CLOSED) -+ goto out; -+ - if (sock_owned_by_user(sk)) { - /* Try again later. */ - /* XXX: set some sensible MIB */ - goto restart_timer; - } - -+ hc = ccid_priv(dp->dccps_hc_tx_ccid); -+ - ccid3_pr_debug("%s(%p, state=%s) - entry\n", dccp_role(sk), sk, - ccid3_tx_state_name(hc->tx_state)); - -@@ -250,8 +257,8 @@ static void ccid3_hc_tx_no_feedback_timer(struct timer_list *t) - t_nfb = max(hc->tx_t_rto, 2 * hc->tx_t_ipi); - - restart_timer: -- sk_reset_timer(sk, &hc->tx_no_feedback_timer, -- jiffies + usecs_to_jiffies(t_nfb)); -+ sk_reset_timer(sk, &dp->dccps_ccid_timer, -+ jiffies + usecs_to_jiffies(t_nfb)); - out: - bh_unlock_sock(sk); - sock_put(sk); -@@ -280,7 +287,7 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb) - return -EBADMSG; - - if (hc->tx_state == TFRC_SSTATE_NO_SENT) { -- sk_reset_timer(sk, &hc->tx_no_feedback_timer, (jiffies + -+ sk_reset_timer(sk, &dp->dccps_ccid_timer, (jiffies + - usecs_to_jiffies(TFRC_INITIAL_TIMEOUT))); - hc->tx_last_win_count = 0; - hc->tx_t_last_win_count = now; -@@ -354,6 +361,7 @@ static void ccid3_hc_tx_packet_sent(struct sock *sk, unsigned int len) - static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) - { - struct ccid3_hc_tx_sock *hc = ccid3_hc_tx_sk(sk); -+ struct dccp_sock *dp = dccp_sk(sk); - struct tfrc_tx_hist_entry *acked; - ktime_t now; - unsigned long t_nfb; -@@ -420,7 +428,7 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) - (unsigned int)(hc->tx_x >> 6)); - - /* unschedule no feedback timer */ -- sk_stop_timer(sk, &hc->tx_no_feedback_timer); -+ sk_stop_timer(sk, &dp->dccps_ccid_timer); - - /* - * As we have calculated new ipi, delta, t_nom it is possible -@@ -445,8 +453,8 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb) - "expire in %lu jiffies (%luus)\n", - dccp_role(sk), sk, usecs_to_jiffies(t_nfb), t_nfb); - -- sk_reset_timer(sk, &hc->tx_no_feedback_timer, -- jiffies + usecs_to_jiffies(t_nfb)); -+ sk_reset_timer(sk, &dp->dccps_ccid_timer, -+ jiffies + usecs_to_jiffies(t_nfb)); - } - - static int ccid3_hc_tx_parse_options(struct sock *sk, u8 packet_type, -@@ -488,21 +496,23 @@ static int ccid3_hc_tx_parse_options(struct sock *sk, u8 packet_type, - - static int ccid3_hc_tx_init(struct ccid *ccid, struct sock *sk) - { -+ struct dccp_sock *dp = dccp_sk(sk); - struct ccid3_hc_tx_sock *hc = ccid_priv(ccid); - - hc->tx_state = TFRC_SSTATE_NO_SENT; - hc->tx_hist = NULL; - hc->sk = sk; -- timer_setup(&hc->tx_no_feedback_timer, -+ timer_setup(&dp->dccps_ccid_timer, - ccid3_hc_tx_no_feedback_timer, 0); - return 0; - } - - static void ccid3_hc_tx_exit(struct sock *sk) - { -+ struct dccp_sock *dp = dccp_sk(sk); - struct ccid3_hc_tx_sock *hc = ccid3_hc_tx_sk(sk); - -- sk_stop_timer(sk, &hc->tx_no_feedback_timer); -+ sk_stop_timer(sk, &dp->dccps_ccid_timer); - tfrc_tx_hist_purge(&hc->tx_hist); - } - --- -2.30.1 - diff --git a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0112-Revert-dccp-don-t-free-ccid2_hc_tx_sock-struct-in-dc.patch b/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0112-Revert-dccp-don-t-free-ccid2_hc_tx_sock-struct-in-dc.patch deleted file mode 100644 index 92c40ed81a6a..000000000000 --- a/sys-kernel/cairn-sources/files/5.10.14/hardened-patches/0112-Revert-dccp-don-t-free-ccid2_hc_tx_sock-struct-in-dc.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 4b8f9f14b8e6e099f53fd14a4f00638701dc0fc5 Mon Sep 17 00:00:00 2001 -From: Thadeu Lima de Souza Cascardo <cascardo@canonical.com> -Date: Tue, 13 Oct 2020 19:18:49 +0200 -Subject: [PATCH 112/113] Revert "dccp: don't free ccid2_hc_tx_sock struct in - dccp_disconnect()" - -This reverts commit 2677d20677314101293e6da0094ede7b5526d2b1. - -This fixes an issue that after disconnect, dccps_hc_tx_ccid will still be -kept, allowing the socket to be reused as a listener socket, and the cloned -socket will free its dccps_hc_tx_ccid, leading to a later use after free, -when the listener socket is closed. - -This addresses CVE-2020-16119. - -Fixes: 2677d2067731 (dccp: don't free ccid2_hc_tx_sock struct in dccp_disconnect()) -Reported-by: Hadar Manor -Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@canonical.com> -Signed-off-by: Kleber Sacilotto de Souza <kleber.souza@canonical.com> ---- - net/dccp/proto.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/net/dccp/proto.c b/net/dccp/proto.c -index 6d705d90c614..359e848dba6c 100644 ---- a/net/dccp/proto.c -+++ b/net/dccp/proto.c -@@ -279,7 +279,9 @@ int dccp_disconnect(struct sock *sk, int flags) - - dccp_clear_xmit_timers(sk); - ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk); -+ ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk); - dp->dccps_hc_rx_ccid = NULL; -+ dp->dccps_hc_tx_ccid = NULL; - - __skb_queue_purge(&sk->sk_receive_queue); - __skb_queue_purge(&sk->sk_write_queue); --- -2.30.1 - diff --git a/sys-kernel/cryptodev/metadata.xml b/sys-kernel/cryptodev/metadata.xml index c7bb627138ce..c2846d62ec6a 100644 --- a/sys-kernel/cryptodev/metadata.xml +++ b/sys-kernel/cryptodev/metadata.xml @@ -1,8 +1,10 @@ <?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE pkgmetadata SYSTEM "http://www.gentoo.org/dtd/metadata.dtd"> +<!DOCTYPE pkgmetadata SYSTEM "https://liguros.gitlab.io/dtd/metadata.dtd"> <pkgmetadata> - <maintainer type="person"> - <email>swegener@gentoo.org</email> - <name>Sven Wegener</name> - </maintainer> -</pkgmetadata> + <maintainer type="person"> + <email>swegener@gentoo.org</email> + <name>Sven Wegener</name> + </maintainer> + + <origin>gentoo-staging</origin> +</pkgmetadata>
\ No newline at end of file diff --git a/sys-kernel/debian-sources/Manifest b/sys-kernel/debian-sources/Manifest index 0e6b290e8890..d6140143eeca 100644 --- a/sys-kernel/debian-sources/Manifest +++ b/sys-kernel/debian-sources/Manifest @@ -1,4 +1,4 @@ DIST linux_4.19.171-2.debian.tar.xz 1480804 BLAKE2B 5a26948990dbe34443a2af38683dd215739add79c420960d39bbc97d6e3652932250f81fa7217b6107e1327c8c70d394f2ba99342d1074db6c3de3d0682328c1 SHA512 24518c688403d0355bfe183c450e462310d69852a865331ac5fd6766ab9c01e0d416d3c545940d864426cb013bd5db504becdef938095c51a8086375aa07f821 DIST linux_4.19.171.orig.tar.xz 107575880 BLAKE2B 5b084939b192e816cf4c9b829bac364decee60176ec0cd274f03ed2f17d712573f28c54005a9ecf20d0e0ab388d9345766cacdbe3e4f7c9df836248d2368ecb3 SHA512 ff8eb0207476feef390f656681e8618b65fa1154a7bb2d0994e88e19b946ea8e77b2cd39c1586f16c3c5c775bed0d0097e13cd175f44fe4f531aab586f95e511 -DIST linux_5.10.12-1.debian.tar.xz 1305284 BLAKE2B d9df179c4ef639c27e7f237c59beaacd149a8484aaf30874d37d6d23c64428f64db56b5d48f3e6c1b230ca748086b8ebafee6fe540ad53d812781946901e964b SHA512 92f24ce3f44d0ad4b294a2610c9c355ecfbd803c22bd5293b708b17aa7a146138063884aae31ad5f80f30ae762458ff834977ff3203b46afc03f14aabf67136b -DIST linux_5.10.12.orig.tar.xz 121447500 BLAKE2B 586ac53037c933c2e15d1a11f33ecafbe02c5bccc71e3612f8ef01ab7be6f03e7a03a22b98439f1fda964da23680dd8dcbeb5a0840a60d4497560b1980d19c2e SHA512 7aeebba8639ddfd33d3f731098eb087102a5bf98e112a288c5faf2c4a265518814ef72312f5a1263c60eb030753dcdd4cef7e1de53113e3e256a47d96b7bdef4 +DIST linux_5.10.13-1.debian.tar.xz 4005688 BLAKE2B c037a10dc97db68e88cae22bbb6159fdddf122afc5e1fe76e73768aba706182c2e6129a7ebac22074f74162142c7b7b41e4945e481e0cede2d766fca06dc3e8c SHA512 5e8342c84b6c8fbc58fabf2d485487fe8dcc590c2ad2241300721381fcf8ee5db39aa98a2308c96b6da61be72dd249404a9c70ab3cd7a8f1c0e2cfa8e0484713 +DIST linux_5.10.13.orig.tar.xz 121445856 BLAKE2B 68f1eb2a08c7eed558a69810fba476f408617a004364fefc6851435b40f0cf57883bc3735f3329adba421ef214dd9754b1c754fd5f078af07a8075875dbb9b08 SHA512 02ce47475511d082d19b9d9d14c5d0af97e331db058d276b357d35a737a7b6b4620d6fdf83f388f588b559d1d4f07ff9280c5221b1f25df89f9f3954e18e55b4 diff --git a/sys-kernel/debian-sources/debian-sources-5.10.12_p1.ebuild b/sys-kernel/debian-sources/debian-sources-5.10.13_p1.ebuild index 265bc8cca223..265bc8cca223 100644 --- a/sys-kernel/debian-sources/debian-sources-5.10.12_p1.ebuild +++ b/sys-kernel/debian-sources/debian-sources-5.10.13_p1.ebuild diff --git a/sys-kernel/debian-sources/metadata.xml b/sys-kernel/debian-sources/metadata.xml index 1fd2999852ac..35b97c0ead43 100644 --- a/sys-kernel/debian-sources/metadata.xml +++ b/sys-kernel/debian-sources/metadata.xml @@ -1,13 +1,14 @@ <?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE pkgmetadata SYSTEM "http://www.gentoo.org/dtd/metadata.dtd"> +<!DOCTYPE pkgmetadata SYSTEM "https://liguros.gitlab.io/dtd/metadata.dtd"> <pkgmetadata> - <maintainer type="project"> - <email>dev@liguros.net</email> - <name>Development</name> - </maintainer> - <use> - <flag name='binary'>Builds and installs kernel automatically</flag> - <flag name='rt'>Applies the CONFIG_PREEMPT_RT patch series</flag> - </use> - <origin>ports</origin> -</pkgmetadata> + <maintainer type="project"> + <email>dev@liguros.net</email> + <name>Development</name> + </maintainer> + + <use> + <flag name="binary">Builds and installs kernel automatically</flag> + <flag name="rt">Applies the CONFIG_PREEMPT_RT patch series</flag> + </use> + <origin>ports</origin> +</pkgmetadata>
\ No newline at end of file diff --git a/sys-kernel/dracut-crypt-ssh/metadata.xml b/sys-kernel/dracut-crypt-ssh/metadata.xml index b5a52fe7a222..a177103c3ee5 100644 --- a/sys-kernel/dracut-crypt-ssh/metadata.xml +++ b/sys-kernel/dracut-crypt-ssh/metadata.xml @@ -1,15 +1,17 @@ <?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE pkgmetadata SYSTEM "http://www.gentoo.org/dtd/metadata.dtd"> +<!DOCTYPE pkgmetadata SYSTEM "https://liguros.gitlab.io/dtd/metadata.dtd"> <pkgmetadata> - <maintainer type="person"> - <email>jakov.smolic@sartura.hr</email> - <name>Jakov Smolic</name> - </maintainer> - <maintainer type="project"> - <email>proxy-maint@gentoo.org</email> - <name>Proxy Maintainers</name> - </maintainer> - <longdescription lang="en"> + <maintainer type="person"> + <email>jakov.smolic@sartura.hr</email> + <name>Jakov Smolic</name> + </maintainer> + <maintainer type="project"> + <email>proxy-maint@gentoo.org</email> + <name>Proxy Maintainers</name> + </maintainer> + <longdescription lang="en"> crypt-ssh is a dracut module which allows remote unlocking of block devices encrypted with LUKS via ssh, during the initramfs stage of the boot. </longdescription> -</pkgmetadata> + + <origin>gentoo-staging</origin> +</pkgmetadata>
\ No newline at end of file diff --git a/sys-kernel/dracut/metadata.xml b/sys-kernel/dracut/metadata.xml index 39e56c08ac47..c924377f0ff8 100644 --- a/sys-kernel/dracut/metadata.xml +++ b/sys-kernel/dracut/metadata.xml @@ -1,16 +1,18 @@ <?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE pkgmetadata SYSTEM "http://www.gentoo.org/dtd/metadata.dtd"> +<!DOCTYPE pkgmetadata SYSTEM "https://liguros.gitlab.io/dtd/metadata.dtd"> <pkgmetadata> - <maintainer type="person"> - <email>chutzpah@gentoo.org</email> - <name>Patrick McLean</name> - </maintainer> - <maintainer type="person"> - <email>alexander@tsoy.me</email> - <name>Alexander Tsoy</name> - </maintainer> - <maintainer type="person"> - <email>floppym@gentoo.org</email> - <name>Mike Gilbert</name> - </maintainer> -</pkgmetadata> + <maintainer type="person"> + <email>chutzpah@gentoo.org</email> + <name>Patrick McLean</name> + </maintainer> + <maintainer type="person"> + <email>alexander@tsoy.me</email> + <name>Alexander Tsoy</name> + </maintainer> + <maintainer type="person"> + <email>floppym@gentoo.org</email> + <name>Mike Gilbert</name> + </maintainer> + + <origin>gentoo-staging</origin> +</pkgmetadata>
\ No newline at end of file diff --git a/sys-kernel/dummy-sources/metadata.xml b/sys-kernel/dummy-sources/metadata.xml new file mode 100644 index 000000000000..93bdefc36981 --- /dev/null +++ b/sys-kernel/dummy-sources/metadata.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE pkgmetadata SYSTEM "https://liguros.gitlab.io/dtd/metadata.dtd"> +<pkgmetadata> + <maintainer type="project"> + <email>core@liguros.net</email> + <name>Development</name> + </maintainer> + + <origin>xor-overlay</origin> +</pkgmetadata>
\ No newline at end of file diff --git a/sys-kernel/genkernel/Manifest b/sys-kernel/genkernel/Manifest index a0b2eb3d2be4..eb04e898dfec 100644 --- a/sys-kernel/genkernel/Manifest +++ b/sys-kernel/genkernel/Manifest @@ -36,7 +36,7 @@ DIST kmod-27.tar.xz 548924 BLAKE2B 9f12bf5792d4c867e28e0776c279369c063e84269212e DIST kmod-28.tar.xz 552448 BLAKE2B af41a0c5681fb94eb5264f46ed2ae666d171d4e2d0dc21419a3c2f4b12a783350a06b408fb02a7afb00fcea1cd994ee35864c1ec8b7a8cc58a8c9dcdeffaf1b3 SHA512 50646dc72675a5e17b01e327e3d41b972f18aaeac20c8b00983c4d099c6218f35c32c184a833a2d7f716755d6a86851c90913d2835874cef933bdc4a9722df9a DIST libaio-0.3.112.tar.gz 46977 BLAKE2B 088f3b195a65bdc97ae2318e47af17c65259ed3208dca7bfef93c81a800602085e5b2078dbd436c740be316d0ebd923a1b3b7c0808257e2e7c7fb0f7ae1e0dba SHA512 5f984529c9f747a6c82f1e4457fc0832bb1fc299ae6e700f2ac5a8ea7b9bfc6ea1e75809728cc115a020cff6685ed1f4e38c6aeacc1ea98dfccce04dd19dafaa DIST libgcrypt-1.8.6.tar.bz2 2997781 BLAKE2B 90ecacae75633dfff248b9c07a72126aaa4a5c285141f89c42237326ae3bfb99c937eef05d87b466c3d8f5cf022725ccee5c0dbc74d4eb57523a8a2892864b65 SHA512 28a26f665b7e327b79815849ee6e84ab384ee9105d81d4d06e4feeea07d986f940cbbb9faaae8712068cace45b4110a62965a93201da0e1ad008b65808b2b29b -DIST libgcrypt-1.8.7.tar.bz2 2985660 BLAKE2B cb2132b826f3f3af240e6c9ac5fd992808aa17ce64144d17452591a5b1e402564af82c021b58f5fd620ebeb5894ac9654835f6d8376ec05ee41fc02189dd6825 SHA512 6309d17624d8029848990d225d5924886c951cef691266c8e010fbbb7f678972cee70cbb91d370ad0bcdc8c8761402a090c2c853c9427ec79293624a59da5060 +DIST libgcrypt-1.9.2.tar.bz2 3206187 BLAKE2B e0ceb02b0c26a7246c4146640a9dcea01429a365bd484532b9d85fdb0c8f4ac1308862e70899a1593f4665e4b2d16ceaa10029702f67720897975258a25d8ab0 SHA512 d2e3dc89788763229f554382b3cf0c3a2680f774258abc4c1fd9ef1ad44920d57d14422af9b6b405e42742e691d19ab2ee458fddf057e778964519eee090f016 DIST libgpg-error-1.38.tar.bz2 957637 BLAKE2B 9532402466748503805366b94c82c9adfe5b448f885c26b33ebf7ba9957161ca046b4057f5ca862224accb9f2af731652a55d20e7a4ab69107190a58c8e11ad6 SHA512 b936a4738c2cee111d855b1ba3ec433da8c77799a87d1f71275f974f871ebfa593c9db06ea53f0490b6cd6b94bef34f6052a587a4d13d839ec0128500c2dd9de DIST libgpg-error-1.39.tar.bz2 961676 BLAKE2B 8753a9295ca57ba79142ffbc7fa01a986addcdd6a8860cf80c9e1bf9f6f9dfce874f804205a5cdd956e026eb006f2662110c63e7ed52c7a42ee0c45923ae52be SHA512 b28be183ac3d3920363558c4b5b2c24f9074a302799915cc076674bb349dcfb6f09160bec1d3fb62e04047c3ce432d345f36b0905100a88cc730b53d4eb78e42 DIST libgpg-error-1.41.tar.bz2 967117 BLAKE2B 9dc95bc09f55915d904e0f956ecf9281615028b8b8d876dbc786b752068fefea56adfb5dd5db65bad656ab664d567e56541e44a584c7f8672c30537ed05c4db0 SHA512 578d1d8090b9f6e6cbe59d9aeebec7df81aae492f75ec343f8df530950d30866fa0a7903ca050bf7bf721413f7b2708abe34f7467e2b208cc1447ffc9bd5b9a5 @@ -54,7 +54,7 @@ DIST thin-provisioning-tools-0.9.0.tar.gz 500998 BLAKE2B ac269fb6dfd1baf1572da27 DIST unionfs-fuse-0.24.tar.bz2 30381 BLAKE2B c3886d7b0cbd4ac62712d7d94bf9544481200e4354539b29770a88974ea3298b0f594cecfc6f7accff3595004ad1453075b947a2633b5300a3684fedba4995e5 SHA512 e0e414f4edbf641ec9d0135a8723e43fc75412359b482f7aedd66fe8245e4df03943c5ecb6f8de4fdbd97f0346033c691e766cc4f4a755f5b43748e1441d3fbd DIST unionfs-fuse-2.0.tar.gz 46537 BLAKE2B 2f5a0da5adb15c408e7b9d0c3658e389a1aea4a9a5f2f3809fc724af43cf2a4b309e4220e46647e3f3fc9b19d48c8d62692e190cf8536182abfe551bfacfcc24 SHA512 5b60204632f498931fff7671cc9f40b1800d34cb8c0d0de0773626e2653eb0a36647566c92c1d0cf79543e01b934602ef5603a06508407f352e48ef27a7ee758 DIST util-linux-2.35.2.tar.xz 5150488 BLAKE2B 93eb90ab33db7795b46425ec4ec87f8a2d3d6e0dad671345375ea02efd654bf72041932d30b41bea494e4b62952e2fd14ea9f9e6c738d4eb4b050bd170b9bb0e SHA512 59e038ba71aa74c9af6f927b357483a965f675ab3ffcd25cf0c1b043656312d2d2d07c55659fd3da69ede165bec313e0ae7e1cd73758e49681ae610604b399a2 -DIST util-linux-2.36.1.tar.xz 5231880 BLAKE2B 52d867aa0b722a84828c37958d80b0bdcc1ceaae4e46fa6550ad0f2f152c52e4aaf2c8bc5fdf4f27b522037a870ff2554382abac0eaa50a6791d8b8016e3d74c SHA512 9dfd01ae4c16fa35015dafd222d555988b72e4d1d2fbadd140791b9ef78f84fa8254d4d08dc67cabf41e873338867f19e786b989d708ccfe5161c4f7679bba7a +DIST util-linux-2.36.2.tar.xz 5348032 BLAKE2B 17e49515f8d0430f3ed26b80bf1d6e811d847141020d0dae1340dc92887549b7b711f3db6e3913120871fc912435def73586a7aef09d8d9cc6ff7ca331b2770f SHA512 6ab141f44ca4cb6b600081f10eae17e15d23abd122a37eb3ac6c845513a6a4396dc9dcff30b3032de80116ddde50e27dfbc86f92708c1051f84f0c919194664b DIST util-linux-2.36.tar.xz 5242420 BLAKE2B a03b626a376815f37a17b3808d1d421c7ec27a133edf857116603de38f7e13f527687691d0c8aa68f4f6868be6f3bcc64573d759308d74731107e02067449ce6 SHA512 cbb4975da8d99a1edd45514171d59ea7b019ce0f77a81e88b447a733f725e91c53540d9dc78bc626dc011dca129b8b150aaf9e64ccf62a4202ae816581acf4fd DIST xfsprogs-5.10.0.tar.xz 1273332 BLAKE2B 8caaa0ca8a94480f131d36b383afcf732b3a5a7a3c7927b4b4da4855fc5a0fb97a56fcebb98391a4dd0f02465868a4bd857e57eeba053a419df47d42f74bc958 SHA512 da09e687c87c4b133888dba7b4458017ec028020637ea5066be0232bf5c7da18239cc33eadd02d9b99d1c835aab38cab1ec9d45ae8b83897f9157cfcb0271fbd DIST xfsprogs-5.6.0.tar.xz 1253112 BLAKE2B 7928b29458e3ad8251b48b6fb14a515e0128701c40cdfa63c05fc85173c70da3f34c948b7791f12ac5bb8d5f0c634016dac71c328a8917d1065aa7fb4cac3291 SHA512 a6bee55b0a23316c73f3921234d1dbaa4cbe91c12e79264e5f9bfe1356a24baa0ab25270405a46e4613a7e48443ef21997ff4f5962663777bed373f89ca29701 diff --git a/sys-kernel/genkernel/genkernel-9999.ebuild b/sys-kernel/genkernel/genkernel-9999.ebuild index bfa1e039fc9e..97bf576750c7 100644 --- a/sys-kernel/genkernel/genkernel-9999.ebuild +++ b/sys-kernel/genkernel/genkernel-9999.ebuild @@ -28,7 +28,7 @@ VERSION_ISCSI="2.0.878" VERSION_JSON_C="0.13.1" VERSION_KMOD="28" VERSION_LIBAIO="0.3.112" -VERSION_LIBGCRYPT="1.8.7" +VERSION_LIBGCRYPT="1.9.2" VERSION_LIBGPGERROR="1.41" VERSION_LVM="2.02.187" VERSION_LZO="2.10" @@ -37,7 +37,7 @@ VERSION_POPT="1.18" VERSION_STRACE="5.10" VERSION_THIN_PROVISIONING_TOOLS="0.9.0" VERSION_UNIONFS_FUSE="2.0" -VERSION_UTIL_LINUX="2.36.1" +VERSION_UTIL_LINUX="2.36.2" VERSION_XFSPROGS="5.10.0" VERSION_XZ="5.2.5" VERSION_ZLIB="1.2.11" diff --git a/sys-kernel/genkernel/metadata.xml b/sys-kernel/genkernel/metadata.xml index fca8c03fc36d..8d64bbf915fd 100644 --- a/sys-kernel/genkernel/metadata.xml +++ b/sys-kernel/genkernel/metadata.xml @@ -1,19 +1,15 @@ -<?xml version='1.0' encoding='UTF-8'?> -<!DOCTYPE pkgmetadata SYSTEM "http://www.gentoo.org/dtd/metadata.dtd"> +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE pkgmetadata SYSTEM "https://liguros.gitlab.io/dtd/metadata.dtd"> <pkgmetadata> - <maintainer type="project"> - <email>genkernel@gentoo.org</email> - </maintainer> - <use> - <flag name="cryptsetup">Enable support for Luks disk encryption using <pkg>sys-fs/cryptsetup</pkg></flag> - <flag name="firmware">Prefer system firmware <pkg>sys-kernel/linux-firmware</pkg> over local copy.</flag> - </use> - <!-- - <upstream> - <remote-id type="gentoo">git://git.gentoo.org/proj/genkernel</remote-id> - </upstream> - --> - <upstream> - <remote-id type="sourceforge">fuse</remote-id> - </upstream> -</pkgmetadata> + <maintainer type="project"> + <email>genkernel@gentoo.org</email> + </maintainer> + <upstream> + <remote-id type="sourceforge">fuse</remote-id> + </upstream> + <use> + <flag name="cryptsetup">Enable support for Luks disk encryption using <pkg>sys-fs/cryptsetup</pkg></flag> + <flag name="firmware">Prefer system firmware <pkg>sys-kernel/linux-firmware</pkg> over local copy.</flag> + </use> + <origin>gentoo-staging</origin> +</pkgmetadata>
\ No newline at end of file diff --git a/sys-kernel/gentoo-kernel-bin/Manifest b/sys-kernel/gentoo-kernel-bin/Manifest index 78b7492a65b3..1c0f24915fd1 100644 --- a/sys-kernel/gentoo-kernel-bin/Manifest +++ b/sys-kernel/gentoo-kernel-bin/Manifest @@ -1,44 +1,27 @@ -DIST gentoo-kernel-5.10.10-1.amd64.xpak 64334952 BLAKE2B 6dbfc8d8dffdd7d2b9cc7fa1bb60868c87a89a910d46323966cac9cc61e9cb387c29453042eb3f8d3e6f7113c0e72b31a02e1657678bc87f195a658591a85681 SHA512 f2593710e4727c730ddb8dac708ba12c9d8bad88cb8b65f6746ae14b522fc47638ffe019ace5a3c578bd52869bed2e2e6d993912690e96204a26b93c12a19d90 -DIST gentoo-kernel-5.10.10-1.arm64.xpak 59568061 BLAKE2B 4cfc3645d31ab062d9cf69cac9ca76a56ee7f57d4895d455c68e3cf24d7eeb01e120a98257ffca3ff000419497ef5fe3f0da1ef6f31c3ba32c77f8d280a50f53 SHA512 c9cfd6c20471413dd6430437b9a6cbfa7b57259ce822016388dd07c566e042f56155de22d8d06c177e73c16c21d04e247eff663df95aa533b089d05055bb1d3a -DIST gentoo-kernel-5.10.10-1.x86.xpak 57274976 BLAKE2B c606a4df7cb2df25a5d1d2668860791788878c2353e4bafd08f22de105f985aa78c9e494e77d041396bcb88cfdc72f0b6a1bb3d0b1e670e00b17eac163bd001e SHA512 13d3dc2fbfa1526e4f365a9f454ceffd7424004bf98f5d3116877758067bb13991ea107371f63ea46520f909b536460343a2b8f024f73b7b01b228fbfd22733e -DIST gentoo-kernel-5.10.11-1.amd64.xpak 64361874 BLAKE2B 81f33a992539d7cc8f7e35de50515d2bd71268cb4d9bf53236d6abcd49cf5e235032d58cdbaa1d1c670ab63b0af150895ccaf1e830df610179392ed114ab7f98 SHA512 639cd26a0bdb4bdcc6dc6ef36702f8aa37cd0747e93e3b2053e0e66139a3d538f019b795bd0bed48a8236ec3f5c768551a105e4f8396824c614b406cc450722d -DIST gentoo-kernel-5.10.11-1.arm64.xpak 59510738 BLAKE2B f7bc2139a24b295f5be4ba9797001a5797c0d5e47a98b7c9e8f38a91733ae64da79610c4f8db67f8e53440a6f18dc44552ab05df528a067492a1bba6f30d1c96 SHA512 e65d51cfb3453d0c098ef484e29af113356739310e0ffd386d27d9933e18e7e1759a425e8a0416b8026176400fd3a69df6f38ba802771cd413a96af8f6d89282 -DIST gentoo-kernel-5.10.11-1.x86.xpak 57287495 BLAKE2B a23fc6067de63dc97c89e3de9310bca4705c21c407601874b9e8f0c68608eb0752fb1add9f351453882a24e1e89f4ab38635161aa177fb0f8f25bbd8d5ca00e8 SHA512 f522d97ef335dbcd3df0444f101add87e530f141d146f65f1c3e4b5776bb9f701557416263122c505d17510b66060f6f4e5d3c4fbd408f8c90c89f76c844c4e8 -DIST gentoo-kernel-5.10.12-1.amd64.xpak 64350144 BLAKE2B 2b20f43d0e0c64af3ef9918bfeeba4997983782cbb9ddda57f5da641f9cf25b57a24c24775048955931047b3b4b0117984818c8fc2981803dcdb93bfae28d58d SHA512 271399b7ac20fd9a10bc7078d31002a6e4f386d83d89b8035c6c494e78644e550e8a7775cf229676ba7ec5aac7803ce41e6f3f068699b06fb43b38bd322c172a -DIST gentoo-kernel-5.10.12-1.arm64.xpak 59600745 BLAKE2B 37d1e3bff20fe9a97ff5b3e3ed003f5f425f45ed13f74f6e2e2dcc3fb28febb24c7a58019066e8dbb0b05b02aa41eb1bb07e357241f1a1ed40769619168e579d SHA512 4625f5758c315cc1b50efd0563a8a6579eec045ab5d88f24871bfe8260109eb51e7e843c65f8bac9c50258521a3922ac28338f9a8591b059c31467691db7f9df -DIST gentoo-kernel-5.10.12-1.x86.xpak 57278945 BLAKE2B 3d97e4fafcaee7d6f9be1f05c3beb844eafac3a188d36db3c540add6c717f41373f2810ba7d9039a83685220e6d622cff35f588d2fa3682bfbbcc0d72edba547 SHA512 c13dddfb7280250e37576727bc4f12fd26aa8973608ca69cf94cd75ca5ab2dbcd89b17ff491634988b9944b53dcfc08bd4e48697834235aca320d580cc3838ef -DIST gentoo-kernel-5.10.13-1.amd64.xpak 64342967 BLAKE2B 9f88a6f23d4403241aed7f2b44de769902eac86ec680abb2d29a0fa789b6dcb9ba68058b34672dca3a8ce8472e06ea5d019e1a13975b9f0b81a6e59bd5d5fea0 SHA512 56a5361134ba063835d4dde0da03c7776a24419a71c427be224ced5264b587b7c0883954bdeb57dea5e5615f0833704fe4e849ffdafd4cb69dd73734fef513bd -DIST gentoo-kernel-5.10.13-1.x86.xpak 57282928 BLAKE2B 4db08e15a64c949f82be99b38801a3b4cdf053165ba3129904bf67627793390872a23fe4c8de4d20d2db527d10da324bf31a8ca5594d2cf17e230f79e85e8af2 SHA512 0cf78998d29b82fe9cca3ac83e1a013178396500f1fd2a870300e541309107eac185bdeb11814cc9b56e1bd00a8a2fe6f175f1814c231527766ab99ffeab8ef1 -DIST gentoo-kernel-5.10.14-1.amd64.xpak 64344950 BLAKE2B d51174b3b2fbb3c25bf2b6423cc1f65d1c40e6849aed60ac62eab7936b34c33fcd16395431aa5a9e49e347425bf6fbe44aea9e7d8a72f14d82b0024b47e488af SHA512 46ea0a591fc705fb6b6da3795f54b6538b710034f87df030e82789d6750d4cf1433be51d6e00fdad2be7e3b8fdf12485cb1b97ff269a4f00d13feec7a33c394d -DIST gentoo-kernel-5.10.14-1.x86.xpak 57279381 BLAKE2B c6192e95414717841b0464eba0b0c037abd71b55ce0599d018ea5760c08d912c2604ea0f8ab6942976ba5c9b3bff5c739c414eeadfd462db52f73f70b00ee614 SHA512 310786e118cf140415009044912c15e2389c0d00078cf8896a91f5a697476ae972b77fcb7b0c3d5a0377023d7c0cce490b16886e04ffe006e9c7b29d6a4bc7a2 -DIST gentoo-kernel-5.10.15-1.amd64.xpak 64341722 BLAKE2B d2a6b3b4b53824a568e924517a3cb4930db5611154d93bf2e33629b6fa72c0da0a18fcfbfc9d09c4cd1ba927558d4180736b63e0b9a022da0f584936ec0f7fc4 SHA512 14f655eef1df2578c905d4273942429bc00f3800de042c48a63b8db0b68dc3ad3fb5ed4b25eec88879220a8ff7bdce23be580eb50b7bcc249e77b8a2bc6b1b4a -DIST gentoo-kernel-5.10.15-1.x86.xpak 57292674 BLAKE2B c97cd518abb97c3511382630ed1ade91a75d7e4ef3520fe104b6b2407b0bc911de387fabd30d03f1a05a9e5154fb039928b7964c74cd53dfa3048ac72f0101d6 SHA512 4862fa1ef3e84d3247a57b3f1eb9bb7751d9fb74649aee537b152c744d12b29c3cd936d109bf7bc7096a5ec6168e0a8ade4edefcade8cc65af7c6b15c3e2e399 -DIST gentoo-kernel-5.10.9-1.amd64.xpak 64344838 BLAKE2B a43bee38c3d4ce1be11d99ee73489cf2d93c794fa06405f7597a7a2fa29c9ef3e64a0f9f34a20467fb730d25682062cba0ad73eb824b34918c5854010bc6cfc7 SHA512 b6c09eac07a3ada4e8ab6573d877ac62ac67858f4b5ad70364e7414fd4d269df88a57dd4fe2bd31a76537fd464b234fac513e898f07969f5d5c6857c8f0fbe65 -DIST gentoo-kernel-5.10.9-1.arm64.xpak 59837992 BLAKE2B 815b3f655ba9f8e8f7f0e000f41575fb752bc50cad2a61af71e83b824ac19f391feb28ae22da0233520629229aed3543ffd3a9f94794c741a8583aaad64d7d4e SHA512 bb1ecbcae01c1cd87bee0a07edb3daf20a9644b89fd3e588180d52e43e6eccc74511e9f74de56b0d729f304683b8ee30ceb1841ad944f9b83222682b2d977e94 -DIST gentoo-kernel-5.10.9-1.x86.xpak 57275255 BLAKE2B b577fbfbf9a470a4383f6d3cf91a26ecb8e41da62807595fded551d52b4629d2f532604e986900c9b8818a48dfbfc87b98deafbffa0c2a96bba8a252446e7675 SHA512 ce5d7bbe47d0c2ec31611580da10af7e4d0ef8979ca14a86c172b75658ef536c25b6336e57aad023de890f806e6e93658d9cf809d3a4f08bb5b2c22b002ae2c8 -DIST gentoo-kernel-5.4.80-r1-1.amd64.xpak 61053571 BLAKE2B 24eebf676e1824b01aa6b75963ff8afe25e797afe90440016f4675e8385e1d6b1a04aa662d7c92217af97d56d79f9631a84c2a271b005b5ea7ad71bb8637d941 SHA512 ea99729ee68a44f6b5081e0d81dd7d5abbb50482eda8c4e435d6ee997572362de09d7c813da2ecf1aac4ed299feb73205bcff7d4d359793889690ce07cfb057f -DIST gentoo-kernel-5.4.80-r1-1.x86.xpak 52880910 BLAKE2B f94a7bbdcdbd383e919f2542251d2552e50e34264ab495a43d75e28dab881162f2549b48383b32a3b2a813a192b7d9f602eaa8210085733ac123e2246e6a285b SHA512 3b5dd91103461306f4a4ea4554792d4cdabedba6165de119523b927abb2009adc7d554f23110ddeac1a1add69b2d1674b7b87b93b1e1b186a2594174808dd9d2 -DIST gentoo-kernel-5.4.83-1.amd64.xpak 61015400 BLAKE2B 73527460e0c430a23c8221f8a736416ef6c3ff0ab93d017096456e72bd6c2c88e2a631bd18b2f995bc929f918e9b5a59aa033119a534a985ae1e33d39ff48790 SHA512 53dbb9fe6d940bd93eeb35c93bb869931f8f423f6c3997433030bede0b0c11dde478e391ff372ff252771a1bb32207cefbfb478f79715ba2ee3910016087bd87 -DIST gentoo-kernel-5.4.83-1.arm64.xpak 56245318 BLAKE2B 53e8e3e3bae66539622bf56c175fe2055905c8a39eb89ea084d0622fab366c0b0614a209d2063e7b44005d438c00759b2a5aca0147b83e9bc17b2a321f693d14 SHA512 657118b04169d9b2bf32fc11138573e0ecf16b27155b6f299e477b211885805bb6c9beab22a19d2d9f93c9a57f0d21759e6ff9b3747c9c7dd76a39867b04b1bc -DIST gentoo-kernel-5.4.83-1.x86.xpak 52886754 BLAKE2B 2594b014c703f9f960d180bb6b2973027d238a2232ff8c358faf76a78d8ec8835e423fed19ad8afd30225c11e884a93411636407ca5a034c8abaa32635c21089 SHA512 70776892d7cd38d3bcd4cd797a14fb25f72bf0f29c2abd14a21b2361fac062c037b139588554b47727929ae60d331e6bd6ceec0c2f8e8f830adea4ed92279ba7 -DIST gentoo-kernel-5.4.88-1.amd64.xpak 61056095 BLAKE2B 67532c81c4c3ae036bcebb30bf08c5371d47ee94adb6d56afd31e3548a82a6e69e2fbf7cf5c4caee42a8a277d1faa609427e9962eba823e49ee82f926fc48f67 SHA512 444ec47f98e0d9344d8ee2083256ea1d83d78f319facee7959564da2d5132a0c26588a1575ac6ccddb15b68f066ebaceda5088c2fba716e6fca29d9e04bf0781 -DIST gentoo-kernel-5.4.88-1.arm64.xpak 56317914 BLAKE2B 3bf2420216a8a4f562d03c45010f3592399b2246dafb3dfd15ccea4327650fdd029284406ad6e49894ae3360a2d7ff0661b2be3d7915aac4e17263ae7e816fed SHA512 ddbfde061506388f8224459eb4f73d61dd43692b456556a5fdaf06b4ddb4dcfafb1fac097015ccc7c25640d1e3488a66a30312b26aa4dfaf565e885dd4f679bd -DIST gentoo-kernel-5.4.88-1.x86.xpak 52893703 BLAKE2B dec54ce2650c69ef3a558b6ab63c622d4e7051fab003923b7f838fa54e247d712fd8c85dc9d00b3430ed02170f99e29b812777ccbf0b62bacca66f0b4e358e30 SHA512 0267b4bffc0c7f76e9fa72fab6d2d55a5e65e228f7eff7a11cf9dd8b731adba41e36ffc8b0efd33306767f5bd645a690fef40750dfa0b83bf427d3e250eba1e5 -DIST gentoo-kernel-5.4.91-1.amd64.xpak 61048020 BLAKE2B f2155b5e4cdf3f142eaa1b81bcef529840dd50c0eb7d6cc225216ce5965bd53f00fc7c6334c6c7e6332feac3a3432dcdbc35622d9015cf750fcbb08202bb9c40 SHA512 fecb178c72e37b12d940e924a320802e4bf1a27338a7f07c0f0cca9c45f65b72b9e03eb120da399aad4e9aebf2ca806134de4350b9b8c936665a2845fae88de6 -DIST gentoo-kernel-5.4.91-1.arm64.xpak 56311101 BLAKE2B 3c84a83b22f6449d9e83f81dfd325de0796d1ce7078fa0b61ac11e0d9e3d5e0535719bf4285f4283cd133e4165d3e3b2bd282a21eda881f4857548769124f65e SHA512 b41342608d65e94bc333e388c6b623df00ca6378d50b95d6b27b50be1374ed90196cf4ac6a118b37f3aacfaf0c0aef16399b3c6e6a25871a80d218dd187e404c -DIST gentoo-kernel-5.4.91-1.x86.xpak 52889220 BLAKE2B d58145b5a092981f90f7699d1455a6f8e21bb5b8c15d4dba100aa0512782248d0017adb19edc7fb7a5348649aa76ea285e4f288c1f748d9de18453db505daa54 SHA512 5b1e5563181c1d5fa6593a5547f22670504edea0f9553e0b4e7d43d8a621f46ff4ebe369c95e1d7239c483ee31d99b9395384cb02e49c2eefecac26d475e9ede -DIST gentoo-kernel-5.4.92-1.amd64.xpak 61046219 BLAKE2B 0e4b4db5eb4e15eb66739a7b756a11f194e420020c47eb89c73c7856865e09cda7d065d2b7a6f32cea925e29cc25b07b5cd0447ee17d41a47656d48f49d8828b SHA512 ec22ea8fa8e1de284f5d3408deb152e5de48ac85e197f29738998bb97aa556c910ba133c154e39ac4f50a7d64195b2b093864b3a171418bfabc2509c2c550665 -DIST gentoo-kernel-5.4.92-1.arm64.xpak 56356094 BLAKE2B 0472855af98713a38e1fed96eb64b72c74ba9b29c7713648c25f91fdab3f5a4f28322b1a37090f357417656af82173e3992a34ec1c5ebfc68c0401ab231c5fea SHA512 295808b8c9c00f803a3519a5ce9eaf6ec99979a58b276d988b9fcbf1f2433c5d45b1d223670b4977a921ee4da7176c2a29cc860e129d7b2e7a4b937b5365d98a -DIST gentoo-kernel-5.4.92-1.x86.xpak 52893632 BLAKE2B 74187e0602932a720faa468c68fc215b8ed347b0364bc532dfcb9f34acc6e072a19b9ee2d82e61aaef2d3a67417c582038f967572b5fa264651e542c6ab00af7 SHA512 31606acd96f4b844ecd476f719ea0153d6b187a23c35a593ce9b70c2c9970b0be2a3a0c0eb57ae341d07231e7577a939ddae87d45dce79eb998fe90a13257d0c -DIST gentoo-kernel-5.4.93-1.amd64.xpak 61051190 BLAKE2B 80cb1938d7ef498796df7008f1bb2a8d30d5d69b75d0b0fcb0c7af45867b5aae87860decd4eb41947ed4a7678cbd94f4f7f480a4d38a8050d4751d0c3058490b SHA512 0100f8d88d9ee798fcc9813b1b086c3551feadffa0ef06a08070614a52f5d4ef146e622017e590a5534c1d1c9d502a9f2c72d450724a60c3f77fcb925eb1d93a -DIST gentoo-kernel-5.4.93-1.arm64.xpak 56339310 BLAKE2B 2b7edabc83e56bcefab8a332fec5c46b9d6fc0c27d38a66509b3964fbab1b3ea86130e1ba1e47a032599916dfc664cd86d62c64525934e1712b39d5c481d87f8 SHA512 619cf0c43b9afd3f37a1d069544db00d96ad6fb95995c731d0b9d1c868755f2af84601e8f7420bfb8c75bbd45de264acdc6d79e406406e72197c08720d8fc82b -DIST gentoo-kernel-5.4.93-1.x86.xpak 52895797 BLAKE2B 069b8e797b479562033dffb19e0772787ee383a22dd4ee5ba2f8d464cba7ee07073198fd2d3b9ecbcfca1ee72900550ee03b2ae52c11eea4b9bec38c5ca5f2e8 SHA512 dd81aa89c9473cb555bca44965e01e39018a06ee6e7de3512b0ee721cf8a462abeb3503b61017b110e6a39167ceacc76e15f61112055ee7dc4645a29d43953a6 +DIST gentoo-kernel-5.10.17-1.amd64.xpak 64346939 BLAKE2B 3387154f735f5f6f50df4fd236c65a1f7c0b4c2257f637bca75d6569c5ac2f3d841828ee94b0072e3edfad947487157d9c42c3add280e97786947fbd305e851d SHA512 7572525cedbbce2d5a2478ab50afac686b01a213af110a570d514c6a7c439e5f5957fcd95c643db3ce1201c50944f64bbbb9a10a38f803cfcf7d3de1368847c2 +DIST gentoo-kernel-5.10.17-1.arm64.xpak 59606648 BLAKE2B 444e43a12a94310b00ed686d3225b61284207f93995bc75375d66435ba22cde42a1882fb1ff7479f1ed6ba369c509de11ba453a945f6608de83b1f121a5fb4e2 SHA512 998cc8342ab5e68f74a80ddf6f1fea68a618139492f5c078eb5c1619611f5635a0635ff362f9414c9518011868bd0f3bf12f110e5e5717e32c728e5f369a6b50 +DIST gentoo-kernel-5.10.17-1.x86.xpak 57292329 BLAKE2B 824b77875aa1336fff7b9f054f837904462c429b625a5085296dcaeee156c2d794242fb35d2d0fd20fb6e8230895bcb5a8b334f04b86034c0818bc0b740f8b66 SHA512 bde8d238b592f7aacf63f3b4464790d3df5901bc772850ec991957c849b634790665a2b9affd0484107017d909a45eb6634a0c345b73bd77274c3101432bacee +DIST gentoo-kernel-5.10.18-1.amd64.xpak 64024674 BLAKE2B 456b0e7e35bf54ba06908212e1a8c98dd8dd99b3670dcf344fa9b4a829413eb2c38e98f52dea3af0df80a31e925c9349851049689f4270a3cd2e03882d66c636 SHA512 9ca89659dd020fae705c71813e276bf36ef874f74d1264b7b33420aa508f01cb018b0ccbcedf774a09d00c2b881f4798b7aa3c42aeaa8319175fc9318af02ba5 +DIST gentoo-kernel-5.10.18-1.arm64.xpak 59269183 BLAKE2B 3ebd1c3ffc96d761132ce899da374286ff800ad6e057fb758ba175b8b07464723df988ce3e2199214c2b4bb50508839ebf3a490966a87d85faf0f8f99cc88012 SHA512 f50a978e376a5ee438c9992ce7afb4cb91277b498a4e6678e91edb903ae4992af237ec2f13c4b737594003bd69ee4dd4e302d1fd3d722d009c121528dde18f46 +DIST gentoo-kernel-5.10.18-1.x86.xpak 56984732 BLAKE2B 8c764915907440e0840f345fa9c7f475f5a016f02d19956a36b00349356755428114629a47ae4a24d212cea2ae3694adbab0d4a5a367dc4992dc542855373ff0 SHA512 b59956497a7ae1f79325108857a6bc7c9abcaea6874ce857a8021e8e26204f860afc6b7e29a9a028b3e0f13409e50ebfc6ff747fe32c0789302296012a9c07b1 +DIST gentoo-kernel-5.10.19-1.amd64.xpak 64036559 BLAKE2B 8f71ea8599f8d26931e6f4314a16fad1d652397f87279af003d7a4f94a83e1f7cb0bb89f197347e0ef8008d3ac7dca3c3478335fa20c8f1ac52a1412468352d8 SHA512 65562dd5297b69a29eacf50d3967d1115ce716b20d40893bc58ac98e29b949b9986a983beef629cf40a6d419997a2f49afc5cf16df720804af0bc1afc6d92ae4 +DIST gentoo-kernel-5.10.19-1.arm64.xpak 59222742 BLAKE2B 0d5468611285d6153a74c597f92c5127322c668b88aa5e20c94c7ba5546a7b33077c769e722e1f1f94f8df907a7e12731b99cf3a926cb1222482248f4d9334a0 SHA512 51601d08269b564894e1d6b27a16e0a7f928c86c83e996efd7efa17caf1a0dcf9ada93eecce72dbb322a952c5261f0056612e1d496fdd122d1e5bb567300fcb2 +DIST gentoo-kernel-5.10.19-1.x86.xpak 56996359 BLAKE2B 58e9d8e9a3c28e95a25f91fa2b7a0e70103b976d52e44ab37ee1d69e59ed4b0ae85078208e5843a1c1d03672ca00b3b12382a4d22a969d34a895b6081123cf1d SHA512 c9d7b41a60032a2b5273c30df01a22300b1a95029c768cb89fa6f1b49d79bd4f0a965766735b418e24f679e534dd545841cbc4749a6f5ce455e91124c4428eee +DIST gentoo-kernel-5.11.2-1.amd64.xpak 64830406 BLAKE2B f9c5d0591a175e497e3ff9f9c12e855e0c7db90aaf28fef5bbc695604c5745e13e3cd16001eb75216c55868497954a58738a7eca2314f077548650ae27b73620 SHA512 9a05cf8ce3218ac7e6b880624cbdc67d7fa221f0440f920de70f883a33978df08297184eeeb7a5b3c420da34ba7cb9ebc38f11c9a4979cf5d8a5c7a33e82b85a +DIST gentoo-kernel-5.11.2-1.arm64.xpak 59866719 BLAKE2B 5c8e59242ac3512488afbc1335845294f6ed6b5f7cf0674c4655689b4e93284b110295da479c14f3bd70111c5f652a2c7c641bd34b06f9d7b21bacdb3965b746 SHA512 978891967b1b2c59ca1d4e77bd7d622585532e39cdaceae087a72c6f72d57764cd9dcdcad918ddb1c2d92a42ddc9859baf532971a280cbbe7c4811acb7cc3f5c +DIST gentoo-kernel-5.11.2-1.x86.xpak 57784553 BLAKE2B 452b7e2bca5f9c83345b14f8a3e9ca54bd18e2b6f89e9d165ee3b59de8b8cd46411858a08d58546cde72180bf78c596f1ab3d595c2e5e818e2df9722101cf0b2 SHA512 9620e721c8c0e474db8861400b3109a2b26af68aafbe94975030a45f620e7f7ca5f9837d8dedfca6e97d5b4cf458ba76d34eee790268ddbcc4677d2b06e220df +DIST gentoo-kernel-5.4.100-1.amd64.xpak 61080710 BLAKE2B 84b33a1aa252b0957eb90ddd792f001942589d7f65399a5b007a2c831d0a1fa3b879814a55e5cf8b1ad6166970d3ac89838f57a2c61cec6b7b136b55d5ea4c7b SHA512 98b3dfd31a2830ed49dfc7094e9f37a39e7fbef54b648b4840122f2b53b8e970fb9c75a653445753d8e4efbd723716b9c56b2f99214c79832f3e49de63b3efbe +DIST gentoo-kernel-5.4.100-1.arm64.xpak 56394488 BLAKE2B b8ea7a56a087e98706099cc151b652dba2a40e2a39ae99670b0989ce2f11c133f07b53dda1a9749f946719ab8a5b97a57ee0a12fcf3d9a568b498859420eeef5 SHA512 549ada0acf8874d3254c8a586f5c4d0ed4f08a103aee74befae38fc47d10c716d86f3f133b8ee3c49e61fcacda2298b04b5fe96bf35917b0963f922fe424e96f +DIST gentoo-kernel-5.4.100-1.x86.xpak 52912122 BLAKE2B 5f1a8f7ccf3f9df6a89650d62df903896cf0342b9cf6e0fc265e67a887aa9a0608d62b023d9641711a2d9196958ddfbddec4e19f5f731356f5bf3a74421145f9 SHA512 6d1e5089bb817cf9e7401bb1be0b1d1433caea884b8ba4208c973fc7bbd879b65b69ace8fe3cba05bcb6aae0607ff1be9a63da42642ec2c32fe5ff7adf6fef28 +DIST gentoo-kernel-5.4.101-1.amd64.xpak 61129676 BLAKE2B 87166f24485d888cf3a76904c38cca21135399f25c58524732e5b3d291c33cfab12b0ddac1450f4fe395ecf17de5b44d0f8e70d685f21c6b5c6b1b2707209149 SHA512 017ec51bf227817aab05a4ba958d8d3c645f9d0ec774c210c3ec3c2b7af7be18a3683e75ccdbf1dab2de7954bdb6bd1527b1d398adbb8ddae616543584e6db09 +DIST gentoo-kernel-5.4.101-1.arm64.xpak 56300423 BLAKE2B 45b69b3f406a4dbd297db8c7ace87c1c28fac2328d4e5c9f26168c61514a71ed861fd35303bdbcc4bac39f12c03e3e8c31f97f3a133606d6314b5b4a5f652059 SHA512 1d638b23f30d686face84a7026e7882c18891c50c107e467615ae7910beef17c48a7c42e7a4efbbc45bf5fdfb413da3cdecc718fbc3ac771a92f076e27793613 +DIST gentoo-kernel-5.4.101-1.x86.xpak 52909165 BLAKE2B 39a094693fe036d75fde0ee331492c8e859a0529e29c45ff7fe8a8f7bb87dd8a5fa8782ee34f297cc046e27701a491ae27c3386c6902f56b1c93bd88d1bc55ca SHA512 f58296401f06c029693639379115d6f94a5203e416e1eb1d75611d0660a1d81385958b2ce2cb66776e9766937bf6df746e3f835e3437bb0b7702143f5050d667 DIST gentoo-kernel-5.4.94-1.amd64.xpak 61075025 BLAKE2B 96f7d69735dacd618266d4220907d2e196d4a59f39fdb6c93e88299ecd26a503684bcfbe0a0dcc8c027c3e1b90fc7c066f0d0cb5e007efee859215c6a4b91807 SHA512 e786c30e4ac3e62f25cb6403105847c20b7673f0e9fee32f513854c6e739cce513409f136da9dfd8c366d74ffc4db00625dc5d6270623af56149e4dd05801c57 DIST gentoo-kernel-5.4.94-1.arm64.xpak 56309818 BLAKE2B 50f9f4d7bfaee560860899a0a16805c0a805a9cd0b915a0dec3f654180db73cc73f3247ccc808842103fefabe9cbc0aa963aff8c649c0fe2d314a6ddf22a02ce SHA512 36ee8c73e76ac00ea6c26a5530d6dab91df46fcf2b5f072bbcc44d8bf8b7df710fa601584ee2707cb1c1bbfad9342e369a00926224a0527f1fd4588d01085508 DIST gentoo-kernel-5.4.94-1.x86.xpak 52893412 BLAKE2B b694d25318a84dd4d458b3ad42193781a42853fef9bc21c7e0f3671b5d74b9358c3408bb478d669d57f3618bc433d29df02bed71d80abc7bb8e8814c6e08997d SHA512 c64d72334079b3650c37427ab38e72d9b0d946d93989a491224a936e59d4eb0e43046bf03d85487d41ae6dec43cf5c5dd8667d3e2c9cf7355ec9e95f61f096e2 -DIST gentoo-kernel-5.4.95-1.amd64.xpak 61046196 BLAKE2B 0473181cbf20219d9007f7f5d0e0fa8f1f9e50a65f21dbbca551a1b3b3a5b22e6ec84c9979d541acb792f8ae9be072cf89e6c2652427195dcac50f5c89862d3d SHA512 16e4543c6de8fab3e0077475e9324fbbbd6a7b67b3baa5e8e7d91b0cb401a5fa39e770620a14a4707acba9a82c30bfa8ef0b0ec286b1d55f4c5ac7028fefeae0 -DIST gentoo-kernel-5.4.95-1.x86.xpak 52897802 BLAKE2B b8cf51aa47d6a3701d78042f3dcab485b9a1664d124dc4113346817d3fb6c6bd9159bd209872ec400156e4c0427c44fa82f8d6b5fb3ea6679a24160197ad0ab6 SHA512 ac0b1689a96baaea5509af5a7af30420871c27846d9672b103e2fcdebd0bd19b432657d3d0edda7785cc3bf50c56f3115bb7162318ff171f5f1de1455ab0568a -DIST gentoo-kernel-5.4.96-1.amd64.xpak 61082860 BLAKE2B 5521a3a4d5dccd127c91f35ffe8453d7b296f278c60d855133253f3752f47a74dc49bf19a110e5176762488e39697c35ad29658dfc70d0d58bd5fc8ce2f86fcf SHA512 9559c82e6980a8b2b32bb633d7957577544b2756f065fb66d688636919ba6532b82bb72ea6313c4d386317b45234a2c2226b7d78d52eb45667a10bee5d6b85d4 -DIST gentoo-kernel-5.4.96-1.x86.xpak 52902599 BLAKE2B e79d7ade352b071f57f4ffa4ec2407d835eb55e4926cec9212237a89d1a88780c5b91066bed8d42a839196278edc52658a08476926970ce9f9a8b5e864591f8d SHA512 5ba67830ef51d5918f2f4c08c2bbb78fc49cd0c37868e7a715c060a22a6220d2d1c1ac7db809021f3876b135c1ca5f8734817775234c02a524559b6602d806f6 DIST gentoo-kernel-5.4.97-1.amd64.xpak 61094072 BLAKE2B d0d79009d53fda887c79f2ec8fd9f3a22fd8fbdc93442635e626a7dd956cdfef89df930b907487b26fd7fc5e6230e19413939d2395515d441b9e7386b540ca1e SHA512 512b1616356a7b6f44695d4d34f25405134cdb84c2c98df34c477572643c9acb3e7740e763ce10b57c0fb0cf56bf5be14774ebde76cd90aa1f180ba756461abc +DIST gentoo-kernel-5.4.97-1.arm64.xpak 56299241 BLAKE2B 260c5a028f64fd7c73ec8bbe6207d20dfedd92eb510fb49ff50656114fb8f76758b10a0e11497520aca7b2002713345e0d3623c8177be97be7dc0fd90668ee0e SHA512 327b55f7ce9aa6b63798a35d623e92f461a31460b759f12624358e5fbdbdc3e521bd09d7efadd9b1e03c8d5f50eb961590586163ad81d6dc02bd0f88609f3b4d DIST gentoo-kernel-5.4.97-1.x86.xpak 52892614 BLAKE2B 7faee99492c9b319b3bbbf45180547bd4af6c732a084c522612c8774015e5ca3768fe5d25c23954821331effc0266d1462437f6d6d8870026ea96cc006b0ab90 SHA512 318d6481a75ebf60c0844269d1c1e67f26f45cde032d4c0597b49f97d733d5c44738e2e2839fa7d4ce06426bad2b35e77a601acefbfe645e8d654761b82ba683 +DIST gentoo-kernel-5.4.99-1.amd64.xpak 61077919 BLAKE2B 1d0bab84d8dba7b3c8495ef5fb2fde5cd5290579cad51e2e5c9714d02263b2b621f5c982d6c00285b469476595c540e7a93e2de8f6caf4a89b6a8e7cc123ad51 SHA512 74c92c49875e8d80e0afc2ea5198d613982d24afc300c9b9a4fdcb97689d1dd00fc5f9bdb795bc609dd12b8f1b671ddf4937860e4d94401da580e17090cd534a +DIST gentoo-kernel-5.4.99-1.arm64.xpak 56363608 BLAKE2B a082403950475a9b398c0f8fbadd371f81d2aa01160bc3656a104dfdd342f9a98979e3701ce5b7d6042c0a4ba7cf33b34de8c6bf7a98356694b33e78dd461bfe SHA512 562706e5f84240d631886ba677292aed84935deb13abbf8fd0ce023772008fffd0cdc9a965b61fc7c38fbd4235b8221c4d2af717ef7c690fbfec621d3c564134 +DIST gentoo-kernel-5.4.99-1.x86.xpak 52893402 BLAKE2B 9964fb97580c87e15248c81e48352a4efecb6b278a3a087e0752484103ca87ccdb16c360d0c1db34a6874c3234fc0dd6502e012d601d381cb4ec402f92bffd55 SHA512 94d985d0b20fd0903539888308cb543d21374b523c5b4d95eecf0589a5a3998ac139b667056975431043efa9691d61755b11c902e4b2f8e9e4cc063b82192129 diff --git a/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.10.14.ebuild b/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.10.14.ebuild deleted file mode 100644 index 31b6fee9f812..000000000000 --- a/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.10.14.ebuild +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright 2020-2021 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI=7 - -inherit kernel-install - -MY_P=${P/-bin/}-1 -DESCRIPTION="Pre-built Linux kernel with genpatches" -HOMEPAGE="https://www.kernel.org/" -SRC_URI+=" - amd64? ( - https://dev.gentoo.org/~mgorny/binpkg/amd64/kernel/sys-kernel/gentoo-kernel/${MY_P}.xpak - -> ${MY_P}.amd64.xpak - ) - x86? ( - https://dev.gentoo.org/~mgorny/binpkg/x86/kernel/sys-kernel/gentoo-kernel/${MY_P}.xpak - -> ${MY_P}.x86.xpak - )" -S=${WORKDIR} - -LICENSE="GPL-2" -KEYWORDS="~amd64 ~x86" - -RDEPEND=" - !sys-kernel/gentoo-kernel:${SLOT} - !sys-kernel/vanilla-kernel:${SLOT} - !sys-kernel/vanilla-kernel-bin:${SLOT}" -PDEPEND=" - >=virtual/dist-kernel-${PV}" - -QA_PREBUILT='*' - -src_unpack() { - ebegin "Unpacking ${MY_P}.${ARCH}.xpak" - tar -x < <(xz -c -d --single-stream "${DISTDIR}/${MY_P}.${ARCH}.xpak") - eend ${?} || die "Unpacking ${MY_P} failed" -} - -src_test() { - kernel-install_test "${PV}" \ - "${WORKDIR}/usr/src/linux-${PV}/$(dist-kernel_get_image_path)" \ - "lib/modules/${PV}" -} - -src_install() { - mv * "${ED}" || die -} diff --git a/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.10.15.ebuild b/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.10.15.ebuild deleted file mode 100644 index 31b6fee9f812..000000000000 --- a/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.10.15.ebuild +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright 2020-2021 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI=7 - -inherit kernel-install - -MY_P=${P/-bin/}-1 -DESCRIPTION="Pre-built Linux kernel with genpatches" -HOMEPAGE="https://www.kernel.org/" -SRC_URI+=" - amd64? ( - https://dev.gentoo.org/~mgorny/binpkg/amd64/kernel/sys-kernel/gentoo-kernel/${MY_P}.xpak - -> ${MY_P}.amd64.xpak - ) - x86? ( - https://dev.gentoo.org/~mgorny/binpkg/x86/kernel/sys-kernel/gentoo-kernel/${MY_P}.xpak - -> ${MY_P}.x86.xpak - )" -S=${WORKDIR} - -LICENSE="GPL-2" -KEYWORDS="~amd64 ~x86" - -RDEPEND=" - !sys-kernel/gentoo-kernel:${SLOT} - !sys-kernel/vanilla-kernel:${SLOT} - !sys-kernel/vanilla-kernel-bin:${SLOT}" -PDEPEND=" - >=virtual/dist-kernel-${PV}" - -QA_PREBUILT='*' - -src_unpack() { - ebegin "Unpacking ${MY_P}.${ARCH}.xpak" - tar -x < <(xz -c -d --single-stream "${DISTDIR}/${MY_P}.${ARCH}.xpak") - eend ${?} || die "Unpacking ${MY_P} failed" -} - -src_test() { - kernel-install_test "${PV}" \ - "${WORKDIR}/usr/src/linux-${PV}/$(dist-kernel_get_image_path)" \ - "lib/modules/${PV}" -} - -src_install() { - mv * "${ED}" || die -} diff --git a/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.10.10-r1.ebuild b/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.10.17-r1.ebuild index fa7357082db9..fa7357082db9 100644 --- a/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.10.10-r1.ebuild +++ b/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.10.17-r1.ebuild diff --git a/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.10.10.ebuild b/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.10.17.ebuild index 31b6fee9f812..31b6fee9f812 100644 --- a/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.10.10.ebuild +++ b/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.10.17.ebuild diff --git a/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.10.11-r1.ebuild b/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.10.18-r1.ebuild index fa7357082db9..fa7357082db9 100644 --- a/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.10.11-r1.ebuild +++ b/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.10.18-r1.ebuild diff --git a/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.10.11.ebuild b/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.10.18.ebuild index 31b6fee9f812..31b6fee9f812 100644 --- a/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.10.11.ebuild +++ b/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.10.18.ebuild diff --git a/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.10.12-r1.ebuild b/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.10.19-r1.ebuild index fa7357082db9..fa7357082db9 100644 --- a/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.10.12-r1.ebuild +++ b/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.10.19-r1.ebuild diff --git a/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.10.12.ebuild b/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.10.19.ebuild index 31b6fee9f812..31b6fee9f812 100644 --- a/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.10.12.ebuild +++ b/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.10.19.ebuild diff --git a/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.10.9.ebuild b/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.10.9.ebuild deleted file mode 100644 index 31b6fee9f812..000000000000 --- a/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.10.9.ebuild +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright 2020-2021 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI=7 - -inherit kernel-install - -MY_P=${P/-bin/}-1 -DESCRIPTION="Pre-built Linux kernel with genpatches" -HOMEPAGE="https://www.kernel.org/" -SRC_URI+=" - amd64? ( - https://dev.gentoo.org/~mgorny/binpkg/amd64/kernel/sys-kernel/gentoo-kernel/${MY_P}.xpak - -> ${MY_P}.amd64.xpak - ) - x86? ( - https://dev.gentoo.org/~mgorny/binpkg/x86/kernel/sys-kernel/gentoo-kernel/${MY_P}.xpak - -> ${MY_P}.x86.xpak - )" -S=${WORKDIR} - -LICENSE="GPL-2" -KEYWORDS="~amd64 ~x86" - -RDEPEND=" - !sys-kernel/gentoo-kernel:${SLOT} - !sys-kernel/vanilla-kernel:${SLOT} - !sys-kernel/vanilla-kernel-bin:${SLOT}" -PDEPEND=" - >=virtual/dist-kernel-${PV}" - -QA_PREBUILT='*' - -src_unpack() { - ebegin "Unpacking ${MY_P}.${ARCH}.xpak" - tar -x < <(xz -c -d --single-stream "${DISTDIR}/${MY_P}.${ARCH}.xpak") - eend ${?} || die "Unpacking ${MY_P} failed" -} - -src_test() { - kernel-install_test "${PV}" \ - "${WORKDIR}/usr/src/linux-${PV}/$(dist-kernel_get_image_path)" \ - "lib/modules/${PV}" -} - -src_install() { - mv * "${ED}" || die -} diff --git a/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.10.9-r1.ebuild b/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.11.2-r1.ebuild index fa7357082db9..4f6fd6df565a 100644 --- a/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.10.9-r1.ebuild +++ b/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.11.2-r1.ebuild @@ -11,7 +11,7 @@ HOMEPAGE="https://www.kernel.org/" SRC_URI+=" arm64? ( https://dev.gentoo.org/~sam/binpkg/arm64/kernel/sys-kernel/gentoo-kernel/${MY_P}.xpak - -> ${MY_P}.arm64.xpak + -> ${MY_P}.arm64.xpak )" S=${WORKDIR} diff --git a/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.10.13.ebuild b/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.11.2.ebuild index 31b6fee9f812..31b6fee9f812 100644 --- a/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.10.13.ebuild +++ b/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.11.2.ebuild diff --git a/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.4.91-r1.ebuild b/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.4.100-r1.ebuild index 8ec8fdea9936..8ec8fdea9936 100644 --- a/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.4.91-r1.ebuild +++ b/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.4.100-r1.ebuild diff --git a/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.4.91.ebuild b/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.4.100.ebuild index b8eb2c63573a..b8eb2c63573a 100644 --- a/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.4.91.ebuild +++ b/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.4.100.ebuild diff --git a/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.4.92-r1.ebuild b/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.4.101-r1.ebuild index 8ec8fdea9936..8ec8fdea9936 100644 --- a/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.4.92-r1.ebuild +++ b/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.4.101-r1.ebuild diff --git a/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.4.92.ebuild b/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.4.101.ebuild index b8eb2c63573a..b8eb2c63573a 100644 --- a/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.4.92.ebuild +++ b/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.4.101.ebuild diff --git a/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.4.80-r2.ebuild b/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.4.80-r2.ebuild deleted file mode 100644 index ed835559ae22..000000000000 --- a/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.4.80-r2.ebuild +++ /dev/null @@ -1,53 +0,0 @@ -# Copyright 2020-2021 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI=7 - -inherit kernel-install - -MY_P=${P/-bin/}-r1-1 -DESCRIPTION="Pre-built Linux kernel with genpatches" -HOMEPAGE="https://www.kernel.org/" -SRC_URI+=" - amd64? ( - https://dev.gentoo.org/~mgorny/binpkg/amd64/kernel/sys-kernel/gentoo-kernel/${MY_P}.xpak - -> ${MY_P}.amd64.xpak - ) - x86? ( - https://dev.gentoo.org/~mgorny/binpkg/x86/kernel/sys-kernel/gentoo-kernel/${MY_P}.xpak - -> ${MY_P}.x86.xpak - )" -S=${WORKDIR} - -LICENSE="GPL-2" -KEYWORDS="amd64 x86" - -RDEPEND=" - !sys-kernel/gentoo-kernel:${SLOT} - !sys-kernel/vanilla-kernel:${SLOT} - !sys-kernel/vanilla-kernel-bin:${SLOT}" - -QA_PREBUILT='*' - -pkg_pretend() { - ewarn "Starting with 5.4.52, Distribution Kernels are switching from Arch" - ewarn "Linux configs to Fedora. Please keep a backup kernel just in case." - - kernel-install_pkg_pretend -} - -src_unpack() { - ebegin "Unpacking ${MY_P}.${ARCH}.xpak" - tar -x < <(xz -c -d --single-stream "${DISTDIR}/${MY_P}.${ARCH}.xpak") - eend ${?} || die "Unpacking ${MY_P} failed" -} - -src_test() { - kernel-install_test "${PV}" \ - "${WORKDIR}/usr/src/linux-${PV}/$(dist-kernel_get_image_path)" \ - "lib/modules/${PV}" -} - -src_install() { - mv * "${ED}" || die -} diff --git a/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.4.83-r1.ebuild b/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.4.83-r1.ebuild deleted file mode 100644 index f507f70d33cb..000000000000 --- a/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.4.83-r1.ebuild +++ /dev/null @@ -1,57 +0,0 @@ -# Copyright 2020-2021 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI=7 - -inherit kernel-install - -MY_P=${P/-bin/}-1 -DESCRIPTION="Pre-built Linux kernel with genpatches" -HOMEPAGE="https://www.kernel.org/" -SRC_URI+=" - amd64? ( - https://dev.gentoo.org/~mgorny/binpkg/amd64/kernel/sys-kernel/gentoo-kernel/${MY_P}.xpak - -> ${MY_P}.amd64.xpak - ) - arm64? ( - https://dev.gentoo.org/~sam/binpkg/arm64/kernel/sys-kernel/gentoo-kernel/${MY_P}.xpak - -> ${MY_P}.arm64.xpak - ) - x86? ( - https://dev.gentoo.org/~mgorny/binpkg/x86/kernel/sys-kernel/gentoo-kernel/${MY_P}.xpak - -> ${MY_P}.x86.xpak - )" -S=${WORKDIR} - -LICENSE="GPL-2" -KEYWORDS="arm64" - -RDEPEND=" - !sys-kernel/gentoo-kernel:${SLOT} - !sys-kernel/vanilla-kernel:${SLOT} - !sys-kernel/vanilla-kernel-bin:${SLOT}" - -QA_PREBUILT='*' - -pkg_pretend() { - ewarn "Starting with 5.4.52, Distribution Kernels are switching from Arch" - ewarn "Linux configs to Fedora. Please keep a backup kernel just in case." - - kernel-install_pkg_pretend -} - -src_unpack() { - ebegin "Unpacking ${MY_P}.${ARCH}.xpak" - tar -x < <(xz -c -d --single-stream "${DISTDIR}/${MY_P}.${ARCH}.xpak") - eend ${?} || die "Unpacking ${MY_P} failed" -} - -src_test() { - kernel-install_test "${PV}" \ - "${WORKDIR}/usr/src/linux-${PV}/$(dist-kernel_get_image_path)" \ - "lib/modules/${PV}" -} - -src_install() { - mv * "${ED}" || die -} diff --git a/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.4.83.ebuild b/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.4.83.ebuild deleted file mode 100644 index 4a18c43a2642..000000000000 --- a/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.4.83.ebuild +++ /dev/null @@ -1,53 +0,0 @@ -# Copyright 2020-2021 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI=7 - -inherit kernel-install - -MY_P=${P/-bin/}-1 -DESCRIPTION="Pre-built Linux kernel with genpatches" -HOMEPAGE="https://www.kernel.org/" -SRC_URI+=" - amd64? ( - https://dev.gentoo.org/~mgorny/binpkg/amd64/kernel/sys-kernel/gentoo-kernel/${MY_P}.xpak - -> ${MY_P}.amd64.xpak - ) - x86? ( - https://dev.gentoo.org/~mgorny/binpkg/x86/kernel/sys-kernel/gentoo-kernel/${MY_P}.xpak - -> ${MY_P}.x86.xpak - )" -S=${WORKDIR} - -LICENSE="GPL-2" -KEYWORDS="amd64 ~x86" - -RDEPEND=" - !sys-kernel/gentoo-kernel:${SLOT} - !sys-kernel/vanilla-kernel:${SLOT} - !sys-kernel/vanilla-kernel-bin:${SLOT}" - -QA_PREBUILT='*' - -pkg_pretend() { - ewarn "Starting with 5.4.52, Distribution Kernels are switching from Arch" - ewarn "Linux configs to Fedora. Please keep a backup kernel just in case." - - kernel-install_pkg_pretend -} - -src_unpack() { - ebegin "Unpacking ${MY_P}.${ARCH}.xpak" - tar -x < <(xz -c -d --single-stream "${DISTDIR}/${MY_P}.${ARCH}.xpak") - eend ${?} || die "Unpacking ${MY_P} failed" -} - -src_test() { - kernel-install_test "${PV}" \ - "${WORKDIR}/usr/src/linux-${PV}/$(dist-kernel_get_image_path)" \ - "lib/modules/${PV}" -} - -src_install() { - mv * "${ED}" || die -} diff --git a/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.4.88.ebuild b/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.4.88.ebuild deleted file mode 100644 index b4fab44a5169..000000000000 --- a/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.4.88.ebuild +++ /dev/null @@ -1,55 +0,0 @@ -# Copyright 2020-2021 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI=7 - -inherit kernel-install - -MY_P=${P/-bin/}-1 -DESCRIPTION="Pre-built Linux kernel with genpatches" -HOMEPAGE="https://www.kernel.org/" -SRC_URI+=" - amd64? ( - https://dev.gentoo.org/~mgorny/binpkg/amd64/kernel/sys-kernel/gentoo-kernel/${MY_P}.xpak - -> ${MY_P}.amd64.xpak - ) - x86? ( - https://dev.gentoo.org/~mgorny/binpkg/x86/kernel/sys-kernel/gentoo-kernel/${MY_P}.xpak - -> ${MY_P}.x86.xpak - )" -S=${WORKDIR} - -LICENSE="GPL-2" -KEYWORDS="amd64 ~x86" - -RDEPEND=" - !sys-kernel/gentoo-kernel:${SLOT} - !sys-kernel/vanilla-kernel:${SLOT} - !sys-kernel/vanilla-kernel-bin:${SLOT}" -PDEPEND=" - >=virtual/dist-kernel-${PV}" - -QA_PREBUILT='*' - -pkg_pretend() { - ewarn "Starting with 5.4.52, Distribution Kernels are switching from Arch" - ewarn "Linux configs to Fedora. Please keep a backup kernel just in case." - - kernel-install_pkg_pretend -} - -src_unpack() { - ebegin "Unpacking ${MY_P}.${ARCH}.xpak" - tar -x < <(xz -c -d --single-stream "${DISTDIR}/${MY_P}.${ARCH}.xpak") - eend ${?} || die "Unpacking ${MY_P} failed" -} - -src_test() { - kernel-install_test "${PV}" \ - "${WORKDIR}/usr/src/linux-${PV}/$(dist-kernel_get_image_path)" \ - "lib/modules/${PV}" -} - -src_install() { - mv * "${ED}" || die -} diff --git a/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.4.94-r1.ebuild b/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.4.94-r1.ebuild index 8ec8fdea9936..1a05b19758a8 100644 --- a/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.4.94-r1.ebuild +++ b/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.4.94-r1.ebuild @@ -24,7 +24,7 @@ SRC_URI+=" S=${WORKDIR} LICENSE="GPL-2" -KEYWORDS="~arm64" +KEYWORDS="arm64" RDEPEND=" !sys-kernel/gentoo-kernel:${SLOT} diff --git a/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.4.94.ebuild b/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.4.94.ebuild index b8eb2c63573a..2e3ec53900e4 100644 --- a/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.4.94.ebuild +++ b/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.4.94.ebuild @@ -20,7 +20,7 @@ SRC_URI+=" S=${WORKDIR} LICENSE="GPL-2" -KEYWORDS="~amd64 ~x86" +KEYWORDS="amd64 x86" RDEPEND=" !sys-kernel/gentoo-kernel:${SLOT} diff --git a/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.4.95.ebuild b/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.4.95.ebuild deleted file mode 100644 index b8eb2c63573a..000000000000 --- a/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.4.95.ebuild +++ /dev/null @@ -1,55 +0,0 @@ -# Copyright 2020-2021 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI=7 - -inherit kernel-install - -MY_P=${P/-bin/}-1 -DESCRIPTION="Pre-built Linux kernel with genpatches" -HOMEPAGE="https://www.kernel.org/" -SRC_URI+=" - amd64? ( - https://dev.gentoo.org/~mgorny/binpkg/amd64/kernel/sys-kernel/gentoo-kernel/${MY_P}.xpak - -> ${MY_P}.amd64.xpak - ) - x86? ( - https://dev.gentoo.org/~mgorny/binpkg/x86/kernel/sys-kernel/gentoo-kernel/${MY_P}.xpak - -> ${MY_P}.x86.xpak - )" -S=${WORKDIR} - -LICENSE="GPL-2" -KEYWORDS="~amd64 ~x86" - -RDEPEND=" - !sys-kernel/gentoo-kernel:${SLOT} - !sys-kernel/vanilla-kernel:${SLOT} - !sys-kernel/vanilla-kernel-bin:${SLOT}" -PDEPEND=" - >=virtual/dist-kernel-${PV}" - -QA_PREBUILT='*' - -pkg_pretend() { - ewarn "Starting with 5.4.52, Distribution Kernels are switching from Arch" - ewarn "Linux configs to Fedora. Please keep a backup kernel just in case." - - kernel-install_pkg_pretend -} - -src_unpack() { - ebegin "Unpacking ${MY_P}.${ARCH}.xpak" - tar -x < <(xz -c -d --single-stream "${DISTDIR}/${MY_P}.${ARCH}.xpak") - eend ${?} || die "Unpacking ${MY_P} failed" -} - -src_test() { - kernel-install_test "${PV}" \ - "${WORKDIR}/usr/src/linux-${PV}/$(dist-kernel_get_image_path)" \ - "lib/modules/${PV}" -} - -src_install() { - mv * "${ED}" || die -} diff --git a/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.4.96.ebuild b/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.4.96.ebuild deleted file mode 100644 index b8eb2c63573a..000000000000 --- a/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.4.96.ebuild +++ /dev/null @@ -1,55 +0,0 @@ -# Copyright 2020-2021 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI=7 - -inherit kernel-install - -MY_P=${P/-bin/}-1 -DESCRIPTION="Pre-built Linux kernel with genpatches" -HOMEPAGE="https://www.kernel.org/" -SRC_URI+=" - amd64? ( - https://dev.gentoo.org/~mgorny/binpkg/amd64/kernel/sys-kernel/gentoo-kernel/${MY_P}.xpak - -> ${MY_P}.amd64.xpak - ) - x86? ( - https://dev.gentoo.org/~mgorny/binpkg/x86/kernel/sys-kernel/gentoo-kernel/${MY_P}.xpak - -> ${MY_P}.x86.xpak - )" -S=${WORKDIR} - -LICENSE="GPL-2" -KEYWORDS="~amd64 ~x86" - -RDEPEND=" - !sys-kernel/gentoo-kernel:${SLOT} - !sys-kernel/vanilla-kernel:${SLOT} - !sys-kernel/vanilla-kernel-bin:${SLOT}" -PDEPEND=" - >=virtual/dist-kernel-${PV}" - -QA_PREBUILT='*' - -pkg_pretend() { - ewarn "Starting with 5.4.52, Distribution Kernels are switching from Arch" - ewarn "Linux configs to Fedora. Please keep a backup kernel just in case." - - kernel-install_pkg_pretend -} - -src_unpack() { - ebegin "Unpacking ${MY_P}.${ARCH}.xpak" - tar -x < <(xz -c -d --single-stream "${DISTDIR}/${MY_P}.${ARCH}.xpak") - eend ${?} || die "Unpacking ${MY_P} failed" -} - -src_test() { - kernel-install_test "${PV}" \ - "${WORKDIR}/usr/src/linux-${PV}/$(dist-kernel_get_image_path)" \ - "lib/modules/${PV}" -} - -src_install() { - mv * "${ED}" || die -} diff --git a/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.4.93-r1.ebuild b/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.4.97-r1.ebuild index 8ec8fdea9936..8ec8fdea9936 100644 --- a/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.4.93-r1.ebuild +++ b/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.4.97-r1.ebuild diff --git a/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.4.97.ebuild b/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.4.97.ebuild index b8eb2c63573a..b4fab44a5169 100644 --- a/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.4.97.ebuild +++ b/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.4.97.ebuild @@ -20,7 +20,7 @@ SRC_URI+=" S=${WORKDIR} LICENSE="GPL-2" -KEYWORDS="~amd64 ~x86" +KEYWORDS="amd64 ~x86" RDEPEND=" !sys-kernel/gentoo-kernel:${SLOT} diff --git a/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.4.88-r1.ebuild b/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.4.99-r1.ebuild index 1a05b19758a8..8ec8fdea9936 100644 --- a/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.4.88-r1.ebuild +++ b/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.4.99-r1.ebuild @@ -24,7 +24,7 @@ SRC_URI+=" S=${WORKDIR} LICENSE="GPL-2" -KEYWORDS="arm64" +KEYWORDS="~arm64" RDEPEND=" !sys-kernel/gentoo-kernel:${SLOT} diff --git a/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.4.93.ebuild b/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.4.99.ebuild index b8eb2c63573a..b8eb2c63573a 100644 --- a/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.4.93.ebuild +++ b/sys-kernel/gentoo-kernel-bin/gentoo-kernel-bin-5.4.99.ebuild diff --git a/sys-kernel/gentoo-kernel-bin/metadata.xml b/sys-kernel/gentoo-kernel-bin/metadata.xml index b0b959adbe61..3eca39567e28 100644 --- a/sys-kernel/gentoo-kernel-bin/metadata.xml +++ b/sys-kernel/gentoo-kernel-bin/metadata.xml @@ -1,11 +1,13 @@ <?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE pkgmetadata SYSTEM "http://www.gentoo.org/dtd/metadata.dtd"> +<!DOCTYPE pkgmetadata SYSTEM "https://liguros.gitlab.io/dtd/metadata.dtd"> <pkgmetadata> - <maintainer type="project"> - <email>dist-kernel@gentoo.org</email> - <name>Distribution Kernel Project</name> - </maintainer> - <use> - <flag name='initramfs'>Build initramfs along with the kernel.</flag> - </use> -</pkgmetadata> + <maintainer type="project"> + <email>dist-kernel@gentoo.org</email> + <name>Distribution Kernel Project</name> + </maintainer> + + <use> + <flag name="initramfs">Build initramfs along with the kernel.</flag> + </use> + <origin>gentoo-staging</origin> +</pkgmetadata>
\ No newline at end of file diff --git a/sys-kernel/gentoo-kernel/Manifest b/sys-kernel/gentoo-kernel/Manifest index f5bdbf536b1f..3d34b5cf10d7 100644 --- a/sys-kernel/gentoo-kernel/Manifest +++ b/sys-kernel/gentoo-kernel/Manifest @@ -1,53 +1,36 @@ -DIST genpatches-5.10-11.base.tar.xz 343372 BLAKE2B d844a4ce292477da26bc02743916143cd6851b2ba85229ed37361213580b47b5386f260bde7cb77eb5842f3fd1022b6af64d47dcc3fcf2161be8157380e082bd SHA512 069efa3d348d8a7601c6bf37ec92e3efa692abe4a7ca5dc4bfe30fb76f1b7fe8daf1a0f237d60dcf66a0815e909ac77cb1cc189d46f6fb4884a260f30a4af48b -DIST genpatches-5.10-11.extras.tar.xz 1772 BLAKE2B 8d4c4b94e9bd7c585f56038900256b3ec1ae721b4ed7adb326f393094e5c8960575efdbe2cc14cd219ae0a69cdde5c626d6983741e3f13a39bed3e85f3eb7060 SHA512 90ce771ad84ffbeaeaff6a2827577fc9c9113930dc4fd394300e1a971cc205a1f4805404e1b356dc36b373bfcd9daa95de7a364144f0fbeb0f923209946635fe -DIST genpatches-5.10-12.base.tar.xz 354672 BLAKE2B 4c92a3c4d144e7abb130371a5d12e839d280789b2c44e97fced3a35d25fcc9b084c3e3e8832fc7670a4811da7026963a1c498a0cb2c44cd325ab13aa62a3d142 SHA512 7ee954e44305b4276717aa4a1198ea036fdd1f18e17c95fb0c5e8070acf390c1644dd0499d42ed1464fa7d9cef8d90abbeb6d0e0448c2fefd5a655834a5afa5b -DIST genpatches-5.10-12.extras.tar.xz 1772 BLAKE2B c219ce68835104664a93e78e57c5bce67a3d654666504ae38fc5058d6f8df67c9e37941f549d047b446061f54928230a384d813b4bde2508323facef6502bc16 SHA512 3b2b6ba233226f9c0d54d1dbcbd36133429dba1e0bc7a355fb0794389fd729e8ebcfd1789c4b79529ca4bf48dc50d7b07c1e167ff19d837d67296f36705e7db3 -DIST genpatches-5.10-13.base.tar.xz 407940 BLAKE2B 21566164ea821e5ee95e4b4583395625384347d0e8440b29fa71f4b63365c5481dbb683c84818a5379242a25a59fa85c3caf420be3e6cb8553a43834dcdbfb94 SHA512 0f4e5aa39cc8dd6f2cd62fe5293de1d9fa5a0f6e0dd6da9af52ad68ee8318f995d9095df65b93d6e15994227feb87b5bbcf0403ebe774141045b05bf239dab86 -DIST genpatches-5.10-13.extras.tar.xz 1772 BLAKE2B 29357a93bb6b4e34937e6655bb8cecc4f57edea8a7e7a903dd8196c6f075b27e2b1176a56a998777c850994c5131a2a57266a7fc579a25fc43db9c9aac4dd80b SHA512 e9ed41cc3b81ae7e76fce6bd6df271eb354110252da85e7e90c4d08816babd1262c5c8fbb62fe56dff1fde712abc35ee40c67f9f04e3541920eee78b32074928 -DIST genpatches-5.10-14.base.tar.xz 416468 BLAKE2B cfde628c2594a568c8f699ffb63bb1bfa5054fb810a0baf8cc08c87886d49a5e33725be6a6eb03ed0f8fa40521b9591ae0ac1253708a3ae72556e0cff7efe17c SHA512 84b815aad491aab1592c253da7c37d307b102fda9d08c741cbe5df9c5bd636a83eb8af0e96faf6b54c13bad77068d3ca1f632ab4c68211bbdfb8a9c1d233f06a -DIST genpatches-5.10-14.extras.tar.xz 1772 BLAKE2B 9694bc87e97e7899f2d47199c42082a666e775f35a49a3efb20f8b15cf35345b0905b5d36bd3845e4b62e0ae49260a7fb381f26c6cdcfeb20c3eda5672e81e29 SHA512 be9fbe10adae2acb813abf94f7008620ee9c5f1ca28053e4c387ecb814e3fa6b0e08b6c0404f1585049ceba4ed419dbcd524f9ce69f25dc12006b20d5db3dfc5 -DIST genpatches-5.10-15.base.tar.xz 455860 BLAKE2B cc02492f8f33e3b644df293231e9e6718007b4556f7e056256eb6040e0adaee076f1b25dd8086097d2ae1c50f1169488c2188e45756d0aa47e0b0d34f132715e SHA512 983f45356831d74a6b5001bfc68f4252d687f307cfc8ad2925c3a844f5e9c13e6407f6c591b49028d9cee599106b771078fdfe57137801ba0096552b99126666 -DIST genpatches-5.10-15.extras.tar.xz 1772 BLAKE2B b7cefe073d4c1c6b6f5b57e79faa95baadea2a79be973524876941275be05b60be2008ddcadb02ffab605d47dec4fa325609e70b58d7c59aba83d2075d7c3766 SHA512 ab18ecf108271a4a132ca5983a47985dd462e5b312bf0cbc356340713738c40888b59fe4fb2597c218b41098d6496594f2ad98638b6b14c435ba271b8f4b2882 -DIST genpatches-5.10-16.base.tar.xz 468704 BLAKE2B b7476d5db21c56f2b0e3082e47d643b12b163277e84aecd4b7df75e97f6b703ce8fbdea29aee0a7150f0f193a35ecd896766e9e6bef8dc47a4dac941f83b7f02 SHA512 9623b5fb47de8a93d036e301220031d5b6508e07ce87002193a5d52a34902a486811f133419c84c35cfd7f7bb6076fb5be87992d6934ed57b830d4c7542313df -DIST genpatches-5.10-16.extras.tar.xz 1772 BLAKE2B 5652ee641cc180d14e7a28d3dabecc46430bbe8daa5d5e0cba3090d8a2e28ee56b92073efa996bd9ec598897045c29f1a8c3fdb28f69d7ef94422d31275d7fc0 SHA512 90d245b44e33ca5f8356dac3d3ddf0d736530384ffc232fb230b88e799b362c8cf9b4a147f7b9fc5c32aaccf18cec4ebfa7b8c80bc530ac300b5444fb9263021 -DIST genpatches-5.10-17.base.tar.xz 502160 BLAKE2B e243f962bdb26797424cbf27eb64e37cc42a5d7297d8eac4dfdff556f641aa0d34461b9845df3c203dfc0df462e130089a83c1cb8fae4774df5e99cee27ed67f SHA512 d573c4f168fc65cacd01931d0cb52636ee4c739ec7a285f069cf8c0e487f606e2cab5a9524dbc020b830ede4a5660e2204a49d27596fc661ca96f3db26856c31 -DIST genpatches-5.10-17.extras.tar.xz 1772 BLAKE2B 14f5f5b8a2a70190f80376f20a83c2f7a70ca31b2a956c2cfd84fb2999436bc3cfad925ce9744d333c896f520df6dec5337ad820340d9b4dd007d91abc95b0c4 SHA512 2bf9b8444f8d53937a24e1d0304236f04ca220eb1a2bf4d4c47d7655149d752948a0050684d1d1f18065226e7b50501b3182b264b2ff009b6f9e45e6886037ae -DIST genpatches-5.4-81.base.tar.xz 2591356 BLAKE2B 63c0ef166e2691c6747a2b2a8317aeac286ddac1454ae1eba7a34035abeba67ea2627257d17f266fde57da0684f83cb102b465252a3b95075c1442123c2473e4 SHA512 88d4deb9002cfe6aa8a8045770cf5c7ffde8cf9bad324a72296b1a5202c94386807fad53460147420363b3c73613be424bb54000e5cade7baa4df254ef2c61ab -DIST genpatches-5.4-81.extras.tar.xz 1772 BLAKE2B 93bedfbb023ab9d3913751cd242a4221b204685751f57d0ac31494fa8f8caf8e5faeb3ae10eed5332016f9a40b20670a6af6c4198eeae1136b14a3b28174beb7 SHA512 8776735a73aad4672d4b857d750f985ff6681f8e565a906106e2cfcd4d7839fa518d8fa19b39a0ac948736a3384656be44aad239ce2516786c797303f492ce01 -DIST genpatches-5.4-82.base.tar.xz 2792480 BLAKE2B 39960646116f5f85ee657a29557d8fd9e809ae9bc60aac349c91e7680f2a0565800ba37a478573098dbad41b686336a058985d2925e5046fa68eeaea8df25477 SHA512 6a76eebd7178e2ccc522477f53c36f74e6fd691f87c547dffa2602a516ad9a6a01f05c953e12bbe6ba9aa2ce34b176a6a081a22da40c7d86855e5dfc34098059 -DIST genpatches-5.4-82.extras.tar.xz 1772 BLAKE2B 8eff7ca01490badd5dad15497f77bf43c268ccb494db9eb4c18f4f59219f1a5d79ef2a6f35caee87e3c423b0fff1ef94a6d6477e5074397f78e4bd23b9c40d95 SHA512 bdcc7eb08c1cdb599e69b254f55685f7beec83f256518d42c31d0df9a4e1c6376c184145ce47d28e0b688d2166e139445ef5f9f284e817ba9f37eaf812852a88 -DIST genpatches-5.4-85.base.tar.xz 2833404 BLAKE2B 56a8a49c1c61693ea344d26fedbb85c2682a16d55dfda57b5bbc5df65d2311c5d92b2d464c6b951b9ef58b04879038ee134e179c1dc4d692308b2eeb3eeb517d SHA512 fa277427a7e5c3c44a681e08ff1570587173a1471de8425013afde212a9aef6e6d68f8e707f52b21d76672a4cd0e6cfdb33c32b78d02908eaa55264517d3d4c1 -DIST genpatches-5.4-85.extras.tar.xz 1768 BLAKE2B 5a5e25a02014fd06b8742a2e505f9998d766c6c95d1a515f0c5a6f3b433163c97c1b8ec758be9bff0c017c947fe4c9c1210fd5fb9d1d838f8571ccd9178d251b SHA512 9ca5271fda3619765363f8fdc5e837b0c6bd218de7d956795e9ef01e9000c85d85f0b49479b8d20a33227008ecbb268d9353c622b37f81619329f358b2fcdff7 -DIST genpatches-5.4-90.base.tar.xz 2956112 BLAKE2B e0ba7a4fed329f452cb754ee4fcd2578a544dbcd7fed57a66cd6a825c4dafcd70d23c4d9571a7ac8de14794ba505816226e5a2b06b8df5d220d4243926edd800 SHA512 bd7fff0edf1635b2de08893a3e1ca5147a86574d87c33c3869c506e232b8c53add688357f7ef2a790185c2df73366610ee5ddd46fe1d88db16c3fb9f43c0a6ca -DIST genpatches-5.4-90.extras.tar.xz 1772 BLAKE2B 557c305f86b0b6d5a93c1ca2da7751362f55d385cb4f57df12f15258d5cdcb1a0ad2c99c9ce53ba89b6c27abe761d5033ce54fa97ca6eaacbd845244d6b20d8b SHA512 eb2fc3f76099bd504f8e0cdf3c0aca60aa083b5c055e06fa2560e895278aa7d32f518ab2e671f9d0182e713ec6807552843448a38d633a4051b926ae4fd2adc4 -DIST genpatches-5.4-93.base.tar.xz 3001024 BLAKE2B d5f3020aae1a920a076457cf28ae640e8ab7387652a61db3d631a3494c5cb0e8706d92debb6356768fea992679aefd4bda6d212a9918a714740439811dd3ef6d SHA512 420512b65e20f00fcabf4d122cf5fd166a6cc196a77451f8a06b333ca2cdc189c38654333e565cc555b1f3e9745e9c4b188b98648cd57ccb395ca1259675e4d2 -DIST genpatches-5.4-93.extras.tar.xz 1772 BLAKE2B 0ad1eff5f82120235a1f326176beeaefcf7aa547eecc94ad103a5be1701dd922ae0309431a10233c0df5bf63c5ba970bdec32e6ca782965e369be2fa5a4577dc SHA512 b5415fe59ba41d60a46e0c123abcee0bb72b5a7d7358789947627ae086c7391c09f116a16c32b2475c278ea14d7275932046d686aa4a849942cbf64440506c92 -DIST genpatches-5.4-94.base.tar.xz 3006280 BLAKE2B a8130e4be0b40fd0c82d9da6c3f42d3e45dc0119b7a981a62b0577e16cb73ae7edb76b407ecdaaf0bd53a118164208529d9bde3958c9592cedb3ef04815e64e9 SHA512 bf4b59da586a4f5f4a03b40273cbb6d5e9e49273c9c15fa2d3dd7eb002c0c24db895fa3987c93268c1dbfb1402197192f2f2c42b22f443a50089ce26d0f721a2 -DIST genpatches-5.4-94.extras.tar.xz 1772 BLAKE2B d7f9cbdd2739ff180d7fa1de7ae24f9d0beeed259b00b0a67e6a3e9dfeb7a2e7136c0682af7e50491fa9010ea3e3e03a37cb8eac96047a4d4e58177d64caf72d SHA512 eee973e296444e301a6d9f59e82e39b2d2b1aa6605fe62c54a3710f300bad9e3b3a13c14f16f357a6c8775c50b47d390f537f15030c4fb08a6d81e5ba4008f1d -DIST genpatches-5.4-95.base.tar.xz 3022876 BLAKE2B e935ec5e2cacf478fd8ac2f343d0e582cceddf811ea4d87d5518b946b8b0501e7aff29d406407d3f0d276ea32a616f022789ee1318b282c6fd77b3aaf0d64631 SHA512 4e87014b78683372d525d6409c5c038429423371a1369f2c3b1455e53f5360290dd323ccc24aaeeb4a9e66452e9c87dba439c75192b77e4fc7bc888bc1c4cdac -DIST genpatches-5.4-95.extras.tar.xz 1772 BLAKE2B 29c822d815b565e99441f122bb978db211288f69ec3e3795e2555aa58cc3d2911debaeddcf202ce7be335771310589548a9de82d0500982894b621d0f773d7a3 SHA512 860978d98d7715b1359e0f3e47a0369ee6ef9e1cc4fd4201ad879dcab0aac644f6a951875643ccb70d31b6dad8b23d0b4ca7b32e50739bd87499760829949749 +DIST genpatches-5.10-19.base.tar.xz 543060 BLAKE2B 9219d5463c51bc574984ab37795a2150deaecf861c0b2ec3c7c91eebacbd6d5e045da40acb09ac01a56e33e5329401e80d8804d1227869d5a856e8c11e2da70d SHA512 795e38b25e6c11a936e8366a3081a5f9d170bdb807296e3c0c58545b43b937ecd47e4a66fff521a0a554ff4142aaf4b4b5543427437f1458f672e57016de1f58 +DIST genpatches-5.10-19.extras.tar.xz 1768 BLAKE2B 8579ab3ab97f6bc906a8e16d90e8bfde74bc6782323a0defc86e0099593431d54bc4457c2cf3bc64bcc623bfde74ba6387ca33af58e367062cc23b78057d0ec8 SHA512 7b658d488dfe372a5cd799042c9e6227fa35bf8cbd56ef505bf25344b052c2fa2db137bfb315d9a65b844c475a052e8845ba9d3b30e57fc6417aaab7c3886176 +DIST genpatches-5.10-20.base.tar.xz 551256 BLAKE2B fc2db45cc49ae771f3c87cd97ba3643c6ae35ebee7104a3e6cea50b5fa444871f069480c73e63ad5ca41903f4c180be34e905cd7701dbf3f49590cd98d255873 SHA512 c176101a167fec0df6dd60a366daa0d5b2ca96b2610ea3de8ba0bd5887037ddb989eed5febdd40ec2fbfc1473837160713b331e37c370c992c95b3db9bfddfd9 +DIST genpatches-5.10-20.extras.tar.xz 1768 BLAKE2B e69295002cda9c81df01d0e20a6ae691f3d584dc91ae7bfe3cae777fae430829b6b4450c5f38f91a2aa42fcd9b6adfb89bc85642f30e8caf7cb34cd301f5261e SHA512 1bfce3155025596db1c1e90c4119812a83d1574519d16805574c84e0b8f5936b5e3a2e5400e92b59c2844b903b9517eb2b9d220054ebd3912af23a4b6914db7f +DIST genpatches-5.10-22.base.tar.xz 554876 BLAKE2B 18d2a41fea4a8a95983a71185248f9fd27d2f4e8863419eaae66cf826ecd74218e0563804262368f3d23bee1f835b18869644af734f0baa8d1266a37ff495061 SHA512 7fca3a5fcd35425b0d6aa37cd0eb1146c6fec8ae5f4a462f058180057e956a4316a26a0c0600780014ffe2f632cf64f135f8d0b337ca6642a949c3654783a4c0 +DIST genpatches-5.10-22.extras.tar.xz 1772 BLAKE2B 3a72d1838aca6ca79985e06d9efc44a10bc3e766431c2ebca64b773c96be52cf27f121331585030e334d2eb7d1415deb34f42c265619b16186fb406baa12bd23 SHA512 81559580dda2d4ecbe693eb25d9d537f0d3dc3a01c1a863f17eff3b0e890a2850bdbb7ed5e856bf6b9c7dde944dd771710a8b64812391b5a3c214cc0e2c8538f +DIST genpatches-5.11-3.base.tar.xz 11280 BLAKE2B 83a975b07b3e04e19b008e5a5c4f08fa551b3558b68afb800cb3c886f782a21950d5ea1029b631a6caa2658f02e7ae819e8d8c137a076470120d94deab99e524 SHA512 0a8b19f888af853e6a12aff9d6675f7a9977fef92efa19e69c79a6325fc1626efe7aa9fec8c42ee65ba29f0757b166567679a54d0351f19ea502183e92a63ac5 +DIST genpatches-5.11-3.extras.tar.xz 1772 BLAKE2B 165d5928e6afc65544392186737efd1df9e1179591ef7edd85a1868971ea76016161a38a615e9e692c4515fe7fc19424a0cfd01420b5ec57a60c8d1d2d223cb7 SHA512 c74015c4e1b824c61db9e9deca6b30a839ae9a8fb5747cb6c46e2af99a9221f11bb971099554107bbfc58ea5389d96e810f9cf8e55d0bcc16a093eef941c6ec8 +DIST genpatches-5.4-101.base.tar.xz 3089116 BLAKE2B c6e716ab8d0e98d3b3b4c492d6a516ada65f5e77d375cb9164a080aabd94311c50a222135499eef9dcad3f80b29b831a3fe015c3006178651c2136620f9079c5 SHA512 1bdd6f8f23a6151298e2e2fec493c9a2e95a1a65f4a4b6ff95598f45d4fad783da2a596c05b5582ec3d82ed8d8aaf654706da768a1b248bdae37fb08481b3dc3 +DIST genpatches-5.4-101.extras.tar.xz 1768 BLAKE2B 44b92b9c288f4f10f499e5b6d2179b44ee3418890905341703901a71b703ff99e992d6e7424521e67d3b1f80e41286c2357187c66e9b1ae7c1feef430f0ed74a SHA512 e397f970bc3b68b91f059e4b4f2d6163f8416340096b16b040eed8a5242a001db37b0fe8c1fd2a54c73bf6121aa55efa1c362b7837e930b758bc3bd33f8dce09 +DIST genpatches-5.4-102.base.tar.xz 3090460 BLAKE2B fa17228e7cfebb2c128b73682cc97f9e96a1a3c4936f98b021ae3f21a1f6a1167c357db2570902ca554b6facf27d507a0d258c4a9e9898cacde502762306c2ca SHA512 e3b7b0826115a7f7c92f5509eafe25803ea943733a8be8404a333d54ac93c607704f742ab20576517a7ac6e5467a7dfc9c2a54205a10f3fcf4af9b2557a5da0d +DIST genpatches-5.4-102.extras.tar.xz 1768 BLAKE2B e9bdc3e77e4cd6feb17c3b84b0b573f60b399262cfb5cf5893444afcda38b3017f41c5e00313fc5af30108d60fef2603dd3ce32cfd36b0e3644f85b782da0206 SHA512 bf88c37717a240a62f64cb7a04af13244ea3c5e531b160c649d39243184266de8e61e7c84f092b4b931760fa786dbe40523a0ed55eabc65824f63f0b330604d1 +DIST genpatches-5.4-104.base.tar.xz 3093716 BLAKE2B da8a9f572f4a22eb101a477ed2b2a81b0adaed65f1913c163b58dc958de661707733fb1e0d06e49ec342666ca0c212313d3a5fbca60c79779009b91361e23f42 SHA512 2ef214d2e4ea982c6702991519aaa183d6731f882fa59db5cc2d7832c7fcaf8de57dc2173f4a59922e5d90da2d046753b3eed609513c84c784c13d5be747303b +DIST genpatches-5.4-104.extras.tar.xz 1768 BLAKE2B 7f335d61bd5f44cfa74ce2082259a48791ed90c21da4d05ff13c191adf1f658e68634c4cf9779274e6f775409695634ca40187754b0f9d50b406c26df26adbc4 SHA512 a8080605c59079063065d9bebc9d846ab8aab73f2f192f6c5becea2b51304a1e4d91e20d9aacd61f2cfa5b967bb8e30d620ddd60592017f308ad2f65ab7287a5 DIST genpatches-5.4-96.base.tar.xz 3031600 BLAKE2B 9ba35f7958842a1fd4c9a7e7d3666ea1339ee5fadde6b771b78f67a8bb27c07e8dad8498e9b85fa0bcfd641f5aef9641793a02061b03becd372ea86245820895 SHA512 3edea8a4fc2a29e0f989089633256b270589ad77a225f3cef6e414c5877de1be8a4d5d9da28bfa4fba848f33ee322c4f01befcdf384c9271c97c90e2e2d3ad39 DIST genpatches-5.4-96.extras.tar.xz 1772 BLAKE2B f33c734139f65245694d3cb98712733a901e89c79d05fab03de42d82d6e45ed3ec41ab4e17f2cd20be2ec31d469cf02a5efc7bad93832c67d3ad0bbf147b07e6 SHA512 8b7d6d058906b9c9afb7addba0c3072d70758bd75ea2989787beab5a3a83725541b4084c34cbb1e90b6cc8bb323a002dfca7065cc88fc834891f04397caa645c -DIST genpatches-5.4-97.base.tar.xz 3041620 BLAKE2B 4b738b0b9dc990d47577b44c4d1931c28727b461891a673eaa82e3add22f56f57494548c76ce6f63872f62d2b58c2c4e1fbdb84d5b4233f1a9df326fe29de60a SHA512 34adda6c55d8fd491c8c667c9ed71deb6afd4f92fcb26999baec619088dd3483be0b665a76bcf72f1f52abfb6b0bb8a0909c2cb549220ec130afdaa0ea482c84 -DIST genpatches-5.4-97.extras.tar.xz 1772 BLAKE2B 5c0ed8ac19c10d0e95ff270bb7c2fd559405218f836290df7bdcd5c07ac3cb7e06221d05e40906d97242807ece263c1aa226cba583e5a822d55328608c765d1c SHA512 08cbda97510319fc497b806238c76eb60ad12b35ec7e075ee10ae3cbc6db61b1b3ea061c9c7b3a11f21125fb0d9e111a6a717eed6c3f885a7244d9e63e02c697 -DIST genpatches-5.4-98.base.tar.xz 3049548 BLAKE2B 38d6f3b3c7121721667ae183683e7e2fb9e3edb66d5caccb7a802429c4f6ee68b2cbda5503464064268efbc8f7f3d7fb5c66164f08c815f228c439fc3d55adb4 SHA512 174247357b558834635b90b79346c7c5005a84fd17c0d20cbe09d2405a7d32b0d7e3f14a8683e26f1c12058d510f2827ed0cab5fbb12cb829679a10c317e25bd -DIST genpatches-5.4-98.extras.tar.xz 1772 BLAKE2B 620bd1c1f60762806ecf90c391f97864567d8ebbf41279bf3a10e1a98de636cefa9616907bdb4922e7ae8c202ef5f3d68a5f551d83af54e70f5252431172730b SHA512 a1c5f239564745bbf1347831995699d52011d856d0965d020cb6f082bb5ca9031f8f9e6fa7d692f04042bbfdcd9aea7e20721198a961021ffa62bd5fcce666a1 DIST genpatches-5.4-99.base.tar.xz 3064716 BLAKE2B f71d76c88a9932d3b0e1b45d065fa0946f36a3100e3b59c5ce4c373519119066973067e4bb74d094cd5b79e689affa4615faf40da75a730b62df2259d3361c43 SHA512 833a83d7aecb1a216783fdf57e0fda342fd481c74166d976326a8333dfb2a13bd61f1b20b749f17b3498756b6134f8538a971507427f4e955bc9128742a3be5f DIST genpatches-5.4-99.extras.tar.xz 1772 BLAKE2B 6ffe84c928fc61b306d3e9a096470c090b79bfe99c90981b64e324d40157e818b50c0aebbaf342f51eeba29867b8cf8a6e91394dd594c1ecdb4f2a64f8d76e00 SHA512 7f2db3353809e7922951e1e884d7fe4a426556750bf4e38619278185fb09d519b30a972f4b5aeda3f7aca335fc95372edcc5dadd0881febbf43403c4d5c1c497 +DIST gentoo-kernel-config-5.10.18.tar.gz 1219 BLAKE2B 55ec8c66a9b090e590e23574b54edde0fefb575f25e6848b1c84834847304e30e52fc0810b8fd219cfb23c097bb8f7444e0b010bde44209f0c4811f99db7e0aa SHA512 ee137c85e94fe5989646cb19a72aca62ddd4795813f7bbf15d66262b0e72d90d84d5d17a31bae7980c061e0576e3f3254dca53ba6e547cf12cb7ab08771e3900 DIST gentoo-kernel-config-5.10.7.tar.gz 1146 BLAKE2B f755581e9f3be3122e5f6e6fc133d3e5c3116d4580b53f95ff5b2cee5150233fe82be5cd45637a9792ae4612be5d2cb4dd954506f97fe82c9e96cb8b772cb342 SHA512 8c64768e83d2552e69a29c6c3f958ef6a1e5a767acd04b3bfcd0cd49453ab5d0aa54fcfee76a8c9d07f72abdbf70380b070e3d1584e7b7d05a6daa3399892f51 -DIST gentoo-kernel-config-5.4.77-r1.tar.gz 1289 BLAKE2B 6612741cfbf458f4bd8915b476aac3aa6934e8bbab344da877fa4ad52b6133e01f5d44bf0e5d048e79e56c1a351774135ee55f1aa839b230e2418db7c5d9b123 SHA512 2a09dd85af37447b278847aeaad114ef47470726cec015ed5ee1b54b3080f4b2c48de8b2f7b817eeb4e27c753579cf0820053e22caa762cb1552116d8d69eba0 DIST gentoo-kernel-config-5.4.89.tar.gz 1240 BLAKE2B 50bd2e64eb1a62d2f0d67e02b78da56cb507fd7a5993d663b880c94ecd535898285ed01e00d5d07fc1ba0d044657e776456736d8fdcacecf7ca464979a8a1d06 SHA512 ad31f9895b9dd45edd7f8715516edfc303c23600f243f3ca122c7c554c9fdbe3c3aa62970a24ef7291d7937e04c63c0258f6348e796686902a011c055c1bed01 DIST kernel-aarch64-fedora.config.5.10.12 223184 BLAKE2B a0246dac2f7a4ad6a55b611538d24382ac87a8960077811a859c9595ac67f961b4bccb7e139a89abc7c0e26e80832da5c94211fc658082f2e7dde984f14dd29d SHA512 7d803b347b136331db1ad6e22e0445fe0224c3e26cd7c034cbe9794915d457b492e05f77664865079874ec001351553652646e2e08d0fee31e30b841b0008f52 -DIST kernel-aarch64-fedora.config.5.10.7 223162 BLAKE2B 23d78fadc509edd2219ba263266e4a865f98d6aef87ee2e299b81ba86ac36eff580e5c7bdccb0d4a8593afad07136e06171c79e0dd0e072c892a523e6e352933 SHA512 9791c26368173da444ca5ed281effdd5e20f3968f0a65eb607c2741f114443db2bf260d033a28a7f826963b59a8893a1311befcb3eb3609f9b85472e95234bcd +DIST kernel-aarch64-fedora.config.5.11.1 225847 BLAKE2B 50e3db29a9afc3db3c35e3af173e89e2e8d3b573dd8af7c35584e3d0152211cbd5e6ddb749acb3d6d2caa54392a3f51e52b5394a5d032d43ed35861230b277d0 SHA512 6d0594658e205767599453d4d8695c37eabc065d6c17362c3775dd745f6ca62131d7c15126ec41a17e757d3ae2a0569cea6621a7ada4666a8f90e4414391b3dc DIST kernel-aarch64.config.5.4.21 199104 BLAKE2B 578ad451a76204df2a9bbbe34b5cb27051d2ac5e2c33967f562b01338c43f35da6dc33a4c2cc67ea6c3b32b155729360d3748ec28dcaa750f18449245b2e8a09 SHA512 66e9a437beb350fdc59512c17b8f72c5b5bfacf2b35070d810d77e66f49cf7929026cc28ad44b04a016d61e65d9fb4a10af6996ba09b604bf97e9c467d08f8ff DIST kernel-i686-fedora.config.5.10.12 205412 BLAKE2B 92c715b7e2cd7dd74da7970c05981f520597d3e403ce82c8cf4eee31c9f1f50b638792a6bdb256ef5bfdc99f1bcd594e819e8f44dc6febb2ad9a854bad817f2b SHA512 69d8db11723ae1b40fdedfaace74d15bb63198cdb0485e0a1e5eba95b31217110c93a93e39cc7370cf45f1d3a8bc7f75ec096d6db5ea9ecb28ac6b56702ebb10 -DIST kernel-i686-fedora.config.5.10.7 205390 BLAKE2B 103131caa856ae9b062b39cb88ad8616a8ebd7aa53b7562399d72ba998a4049a22ab251927bf43a4936127246455c2cdeeee3b7e349e12bb94af8f6dc242d8ea SHA512 58279d0076f7551569e48db45909263c5c494c4349afaff4087682d7dd0ecadc22dde56482b521ce2eec39b1e6110f5c370206e0c8f7045d4419bb164da7e2ec +DIST kernel-i686-fedora.config.5.11.1 208027 BLAKE2B b4183e8d1121aa8b3f65d0a4542b8ba0f507430ab4cf0004dd0e8b1e24b3be1783316b8bf6becb2002f7fbacc8236b640f533fc2e9dc5696e84d1627c3b0e9c4 SHA512 5b107e376ddef783ee6852ef67143a94340b37ab764ef3ee3c6642401883d314809c959c2025d976336923c115d21d6b39332aa1699c0f884d1faad1d9c3fa32 DIST kernel-i686.config.5.4.21 183910 BLAKE2B 185126ffb85718bb73761d01683def80b6f002d7a7a6eddd8e858a30d8eadc863fb378d83a1cd2ed82b3540337fa66ae44475e31fb41ebc46d77005b6f54e5c0 SHA512 6307afc2295902e44fe65b1cccaa7a0260b295a5f21f1d67ec66197bd972bd3f5675b624f08d9da8b224cb3ec987d5c21cbd743599aeab9ac6214bc651f43476 DIST kernel-ppc64le-fedora.config.5.10.12 192105 BLAKE2B 889141debb0656a358a3381bae14b5216b982acdfce0bc758f9445c16647807a68a788fb290199c2a1a23627bda1ef4c9405b3f5ac2a4176d1d2b55c71fb7db9 SHA512 3ab0f1401d9f50a61477c71369dede438f575d9d2c3a2f5c2cf36d624c2b59a938efca9c981b075511b3860c983eaaf5e5a9f877d659277f09ceba45edd43770 -DIST kernel-ppc64le-fedora.config.5.10.7 192083 BLAKE2B 71c97c04629a05ac8cb4f4cf1740c60e8a25c71a5c9184cf53f13088073b04b269887ee6e57ff83c8caff61ccbfd6845809e6e3057f1fdfc13d9b913b032c653 SHA512 732f4e93b3074180e86bed865e0b6d487857d5eefcb2436e7c24706be0e41c813b27b2292e6995df2d63e9a9f7721c2d566a50ba06675bfa862ca1fc91dc2af5 +DIST kernel-ppc64le-fedora.config.5.11.1 194870 BLAKE2B df6e5a0a789dc6d0c2fbec45820f5e19ec455388f02f04d88d7b3dd5081d2f11e89cfd0159b7a3885aaa029470e916743d59ec3f86756ff4182aa56552aa8476 SHA512 e170912e76e8980435df2a1387792d616490ededda4df681a90312f7fc8ce4065f1c9fd7559d746d8edc0fccfbd35b20fd5db294774f9db7f4635d898cd0dab1 DIST kernel-ppc64le.config.5.4.21 172003 BLAKE2B b53887cb44f7c378cb3866780f8e556e19fdb02130d3b0df01d97698d2a91f7d90a200012559f288e962935742c3fdb67dfb6711876fad37862fe55cdca5b5f6 SHA512 82df8d0be47e9eb20bd7db570539bb061d0b6e2101dc78a54596cf4d0b4e0c536041449304ff9240b051ee09b342ea336c5645e9a3b66a5dfb96d7778ff86008 DIST kernel-x86_64-fedora.config.5.10.12 206357 BLAKE2B 0eda9d4f3f973336cabd67c1ac78f100aabde926354743e8dcb7ff84496f0de49210d45f99bc850a2096078b0b4687aa7fd965d999248559506004f2b29dac0c SHA512 b12f43d3c1a52a4915cd73db98874ce9ae6c425672c0f1c19ed1b1101341c868ebf1c9620bef5449752ec0d7342c1ce38fb77779d0f89b9267096a605ebf7a26 -DIST kernel-x86_64-fedora.config.5.10.7 206335 BLAKE2B 1133bf0f58f8073578d048c5905cc4a539f63a01b57fceb225046c4678172861de20419d8cbf42b0f4655c27a6366ddee41343458d577a2685f3d96b2fd444c6 SHA512 8c5d0de931526d3315793e0a1af4c9c2493c09573c4f2233aaa85f0413a912190c14fa8427593fc3956fff61d89c795f7c9b0509bb30936cc8b9976deafeda66 +DIST kernel-x86_64-fedora.config.5.11.1 208870 BLAKE2B 86e075a95cbc5d6c3cdecb0caf67e18f671ed663aee94b7d0688e25f111dfdf12d890e1f409df04446d18057b6fad8e0fc67adcde34ed581266d458d9c9cabbd SHA512 ab39c8b107471bdd492e6f9c2e181e85e44134b4a2934fedd2f454b9766a32aa2cef2cbf7ed83111e82ffd7794d4bf20f81d98b238751d505c13077abff2b543 DIST kernel-x86_64.config.5.4.21 184907 BLAKE2B 0eb2b07c14cea7545350fcdf3a94f2a531f0137c502ebda9299cacf44da5385686e2049b480b28bc153c9d413d453cfe682b9655eefe70428cb720f57c7bd200 SHA512 f3b3ee6841555ac3a9cc11536a7d44e1a5a8df2bab14ba341fda7df1ceb0de45cf1c799a1d54a64f2858fd1272d348bb52cf269ffa396878c5402baf2730237f DIST linux-5.10.tar.xz 116606704 BLAKE2B b923d7b66309224f42f35f8a5fa219421b0a9362d2adacdadd8d96251f61f7230878ea297a269a7f3b3c56830f0b177e068691e1d7f88501a05653b0a13274d1 SHA512 95bc137d0cf9148da6a9d1f1a878698dc27b40f68e22c597544010a6c591ce1b256f083489d3ff45ff77753289b535135590194d88ef9f007d0ddab3d74de70e +DIST linux-5.11.tar.xz 117619104 BLAKE2B 81300c27bd5476387a83123aaeb4163c73eb61e9245806c23660cb5e6a4fa88ffc9def027031335fa0270fc4080506cd415990014364e3a98b9d2e8c58a29524 SHA512 a567ec133018bb5ec00c60281479b466c26e02137a93a9c690e83997947df02b6fd94e76e8df748f6d70ceb58a19bacc3b1467de10b7a1fad2763db32b3f1330 DIST linux-5.4.tar.xz 109441440 BLAKE2B 193bc4a3147e147d5529956164ec4912fad5d5c6fb07f909ff1056e57235834173194afc686993ccd785c1ff15804de0961b625f3008cca0e27493efc8f27b13 SHA512 9f60f77e8ab972b9438ac648bed17551c8491d6585a5e85f694b2eaa4c623fbc61eb18419b2656b6795eac5deec0edaa04547fc6723fbda52256bd7f3486898f diff --git a/sys-kernel/gentoo-kernel/gentoo-kernel-5.10.11.ebuild b/sys-kernel/gentoo-kernel/gentoo-kernel-5.10.11.ebuild deleted file mode 100644 index 57b838f8aba7..000000000000 --- a/sys-kernel/gentoo-kernel/gentoo-kernel-5.10.11.ebuild +++ /dev/null @@ -1,89 +0,0 @@ -# Copyright 2020-2021 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI=7 - -inherit kernel-build - -MY_P=linux-${PV%.*} -GENPATCHES_P=genpatches-${PV%.*}-$(( ${PV##*.} + 2 )) -# https://koji.fedoraproject.org/koji/packageinfo?packageID=8 -CONFIG_VER=5.10.7 -CONFIG_HASH=b238267df7cd80dc3aa6b5b654cbe145367383df -GENTOO_CONFIG_VER=5.10.7 - -DESCRIPTION="Linux kernel built with Gentoo patches" -HOMEPAGE="https://www.kernel.org/" -SRC_URI+=" https://cdn.kernel.org/pub/linux/kernel/v$(ver_cut 1).x/${MY_P}.tar.xz - https://dev.gentoo.org/~mpagano/dist/genpatches/${GENPATCHES_P}.base.tar.xz - https://dev.gentoo.org/~mpagano/dist/genpatches/${GENPATCHES_P}.extras.tar.xz - https://github.com/mgorny/gentoo-kernel-config/archive/v${GENTOO_CONFIG_VER}.tar.gz - -> gentoo-kernel-config-${GENTOO_CONFIG_VER}.tar.gz - amd64? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-x86_64-fedora.config - -> kernel-x86_64-fedora.config.${CONFIG_VER} - ) - arm64? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-aarch64-fedora.config - -> kernel-aarch64-fedora.config.${CONFIG_VER} - ) - ppc64? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-ppc64le-fedora.config - -> kernel-ppc64le-fedora.config.${CONFIG_VER} - ) - x86? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-i686-fedora.config - -> kernel-i686-fedora.config.${CONFIG_VER} - )" -S=${WORKDIR}/${MY_P} - -LICENSE="GPL-2" -KEYWORDS="~amd64 ~arm ~arm64 ~ppc64 ~x86" -IUSE="debug" -REQUIRED_USE="arm? ( savedconfig )" - -RDEPEND=" - !sys-kernel/vanilla-kernel:${SLOT} - !sys-kernel/vanilla-kernel-bin:${SLOT}" -BDEPEND=" - debug? ( dev-util/dwarves )" -PDEPEND=" - >=virtual/dist-kernel-${PV}" - -src_prepare() { - local PATCHES=( - # meh, genpatches have no directory - "${WORKDIR}"/*.patch - ) - default - - # prepare the default config - case ${ARCH} in - amd64) - cp "${DISTDIR}/kernel-x86_64-fedora.config.${CONFIG_VER}" .config || die - ;; - arm) - return - ;; - arm64) - cp "${DISTDIR}/kernel-aarch64-fedora.config.${CONFIG_VER}" .config || die - ;; - ppc64) - cp "${DISTDIR}/kernel-ppc64le-fedora.config.${CONFIG_VER}" .config || die - ;; - x86) - cp "${DISTDIR}/kernel-i686-fedora.config.${CONFIG_VER}" .config || die - ;; - *) - die "Unsupported arch ${ARCH}" - ;; - esac - - local merge_configs=( - "${WORKDIR}/gentoo-kernel-config-${GENTOO_CONFIG_VER}"/base.config - ) - use debug || merge_configs+=( - "${WORKDIR}/gentoo-kernel-config-${GENTOO_CONFIG_VER}"/no-debug.config - ) - kernel-build_merge_configs "${merge_configs[@]}" -} diff --git a/sys-kernel/gentoo-kernel/gentoo-kernel-5.10.14.ebuild b/sys-kernel/gentoo-kernel/gentoo-kernel-5.10.14.ebuild deleted file mode 100644 index 1eef3068fb9b..000000000000 --- a/sys-kernel/gentoo-kernel/gentoo-kernel-5.10.14.ebuild +++ /dev/null @@ -1,89 +0,0 @@ -# Copyright 2020-2021 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI=7 - -inherit kernel-build - -MY_P=linux-${PV%.*} -GENPATCHES_P=genpatches-${PV%.*}-$(( ${PV##*.} + 2 )) -# https://koji.fedoraproject.org/koji/packageinfo?packageID=8 -CONFIG_VER=5.10.12 -CONFIG_HASH=836165dd2dff34e4f2c47ca8f9c803002c1e6530 -GENTOO_CONFIG_VER=5.10.7 - -DESCRIPTION="Linux kernel built with Gentoo patches" -HOMEPAGE="https://www.kernel.org/" -SRC_URI+=" https://cdn.kernel.org/pub/linux/kernel/v$(ver_cut 1).x/${MY_P}.tar.xz - https://dev.gentoo.org/~alicef/dist/genpatches/${GENPATCHES_P}.base.tar.xz - https://dev.gentoo.org/~alicef/dist/genpatches/${GENPATCHES_P}.extras.tar.xz - https://github.com/mgorny/gentoo-kernel-config/archive/v${GENTOO_CONFIG_VER}.tar.gz - -> gentoo-kernel-config-${GENTOO_CONFIG_VER}.tar.gz - amd64? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-x86_64-fedora.config - -> kernel-x86_64-fedora.config.${CONFIG_VER} - ) - arm64? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-aarch64-fedora.config - -> kernel-aarch64-fedora.config.${CONFIG_VER} - ) - ppc64? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-ppc64le-fedora.config - -> kernel-ppc64le-fedora.config.${CONFIG_VER} - ) - x86? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-i686-fedora.config - -> kernel-i686-fedora.config.${CONFIG_VER} - )" -S=${WORKDIR}/${MY_P} - -LICENSE="GPL-2" -KEYWORDS="~amd64 ~arm ~arm64 ~ppc64 ~x86" -IUSE="debug" -REQUIRED_USE="arm? ( savedconfig )" - -RDEPEND=" - !sys-kernel/vanilla-kernel:${SLOT} - !sys-kernel/vanilla-kernel-bin:${SLOT}" -BDEPEND=" - debug? ( dev-util/dwarves )" -PDEPEND=" - >=virtual/dist-kernel-${PV}" - -src_prepare() { - local PATCHES=( - # meh, genpatches have no directory - "${WORKDIR}"/*.patch - ) - default - - # prepare the default config - case ${ARCH} in - amd64) - cp "${DISTDIR}/kernel-x86_64-fedora.config.${CONFIG_VER}" .config || die - ;; - arm) - return - ;; - arm64) - cp "${DISTDIR}/kernel-aarch64-fedora.config.${CONFIG_VER}" .config || die - ;; - ppc64) - cp "${DISTDIR}/kernel-ppc64le-fedora.config.${CONFIG_VER}" .config || die - ;; - x86) - cp "${DISTDIR}/kernel-i686-fedora.config.${CONFIG_VER}" .config || die - ;; - *) - die "Unsupported arch ${ARCH}" - ;; - esac - - local merge_configs=( - "${WORKDIR}/gentoo-kernel-config-${GENTOO_CONFIG_VER}"/base.config - ) - use debug || merge_configs+=( - "${WORKDIR}/gentoo-kernel-config-${GENTOO_CONFIG_VER}"/no-debug.config - ) - kernel-build_merge_configs "${merge_configs[@]}" -} diff --git a/sys-kernel/gentoo-kernel/gentoo-kernel-5.10.15.ebuild b/sys-kernel/gentoo-kernel/gentoo-kernel-5.10.15.ebuild deleted file mode 100644 index 1eef3068fb9b..000000000000 --- a/sys-kernel/gentoo-kernel/gentoo-kernel-5.10.15.ebuild +++ /dev/null @@ -1,89 +0,0 @@ -# Copyright 2020-2021 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI=7 - -inherit kernel-build - -MY_P=linux-${PV%.*} -GENPATCHES_P=genpatches-${PV%.*}-$(( ${PV##*.} + 2 )) -# https://koji.fedoraproject.org/koji/packageinfo?packageID=8 -CONFIG_VER=5.10.12 -CONFIG_HASH=836165dd2dff34e4f2c47ca8f9c803002c1e6530 -GENTOO_CONFIG_VER=5.10.7 - -DESCRIPTION="Linux kernel built with Gentoo patches" -HOMEPAGE="https://www.kernel.org/" -SRC_URI+=" https://cdn.kernel.org/pub/linux/kernel/v$(ver_cut 1).x/${MY_P}.tar.xz - https://dev.gentoo.org/~alicef/dist/genpatches/${GENPATCHES_P}.base.tar.xz - https://dev.gentoo.org/~alicef/dist/genpatches/${GENPATCHES_P}.extras.tar.xz - https://github.com/mgorny/gentoo-kernel-config/archive/v${GENTOO_CONFIG_VER}.tar.gz - -> gentoo-kernel-config-${GENTOO_CONFIG_VER}.tar.gz - amd64? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-x86_64-fedora.config - -> kernel-x86_64-fedora.config.${CONFIG_VER} - ) - arm64? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-aarch64-fedora.config - -> kernel-aarch64-fedora.config.${CONFIG_VER} - ) - ppc64? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-ppc64le-fedora.config - -> kernel-ppc64le-fedora.config.${CONFIG_VER} - ) - x86? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-i686-fedora.config - -> kernel-i686-fedora.config.${CONFIG_VER} - )" -S=${WORKDIR}/${MY_P} - -LICENSE="GPL-2" -KEYWORDS="~amd64 ~arm ~arm64 ~ppc64 ~x86" -IUSE="debug" -REQUIRED_USE="arm? ( savedconfig )" - -RDEPEND=" - !sys-kernel/vanilla-kernel:${SLOT} - !sys-kernel/vanilla-kernel-bin:${SLOT}" -BDEPEND=" - debug? ( dev-util/dwarves )" -PDEPEND=" - >=virtual/dist-kernel-${PV}" - -src_prepare() { - local PATCHES=( - # meh, genpatches have no directory - "${WORKDIR}"/*.patch - ) - default - - # prepare the default config - case ${ARCH} in - amd64) - cp "${DISTDIR}/kernel-x86_64-fedora.config.${CONFIG_VER}" .config || die - ;; - arm) - return - ;; - arm64) - cp "${DISTDIR}/kernel-aarch64-fedora.config.${CONFIG_VER}" .config || die - ;; - ppc64) - cp "${DISTDIR}/kernel-ppc64le-fedora.config.${CONFIG_VER}" .config || die - ;; - x86) - cp "${DISTDIR}/kernel-i686-fedora.config.${CONFIG_VER}" .config || die - ;; - *) - die "Unsupported arch ${ARCH}" - ;; - esac - - local merge_configs=( - "${WORKDIR}/gentoo-kernel-config-${GENTOO_CONFIG_VER}"/base.config - ) - use debug || merge_configs+=( - "${WORKDIR}/gentoo-kernel-config-${GENTOO_CONFIG_VER}"/no-debug.config - ) - kernel-build_merge_configs "${merge_configs[@]}" -} diff --git a/sys-kernel/gentoo-kernel/gentoo-kernel-5.10.13.ebuild b/sys-kernel/gentoo-kernel/gentoo-kernel-5.10.17.ebuild index 1eef3068fb9b..1eef3068fb9b 100644 --- a/sys-kernel/gentoo-kernel/gentoo-kernel-5.10.13.ebuild +++ b/sys-kernel/gentoo-kernel/gentoo-kernel-5.10.17.ebuild diff --git a/sys-kernel/gentoo-kernel/gentoo-kernel-5.10.9.ebuild b/sys-kernel/gentoo-kernel/gentoo-kernel-5.10.18.ebuild index 57b838f8aba7..76a99b1b3ead 100644 --- a/sys-kernel/gentoo-kernel/gentoo-kernel-5.10.9.ebuild +++ b/sys-kernel/gentoo-kernel/gentoo-kernel-5.10.18.ebuild @@ -8,9 +8,9 @@ inherit kernel-build MY_P=linux-${PV%.*} GENPATCHES_P=genpatches-${PV%.*}-$(( ${PV##*.} + 2 )) # https://koji.fedoraproject.org/koji/packageinfo?packageID=8 -CONFIG_VER=5.10.7 -CONFIG_HASH=b238267df7cd80dc3aa6b5b654cbe145367383df -GENTOO_CONFIG_VER=5.10.7 +CONFIG_VER=5.10.12 +CONFIG_HASH=836165dd2dff34e4f2c47ca8f9c803002c1e6530 +GENTOO_CONFIG_VER=5.10.18 DESCRIPTION="Linux kernel built with Gentoo patches" HOMEPAGE="https://www.kernel.org/" diff --git a/sys-kernel/gentoo-kernel/gentoo-kernel-5.10.10.ebuild b/sys-kernel/gentoo-kernel/gentoo-kernel-5.10.19.ebuild index 57b838f8aba7..76bcba59d2bd 100644 --- a/sys-kernel/gentoo-kernel/gentoo-kernel-5.10.10.ebuild +++ b/sys-kernel/gentoo-kernel/gentoo-kernel-5.10.19.ebuild @@ -6,11 +6,11 @@ EAPI=7 inherit kernel-build MY_P=linux-${PV%.*} -GENPATCHES_P=genpatches-${PV%.*}-$(( ${PV##*.} + 2 )) +GENPATCHES_P=genpatches-${PV%.*}-$(( ${PV##*.} + 3 )) # https://koji.fedoraproject.org/koji/packageinfo?packageID=8 -CONFIG_VER=5.10.7 -CONFIG_HASH=b238267df7cd80dc3aa6b5b654cbe145367383df -GENTOO_CONFIG_VER=5.10.7 +CONFIG_VER=5.10.12 +CONFIG_HASH=836165dd2dff34e4f2c47ca8f9c803002c1e6530 +GENTOO_CONFIG_VER=5.10.18 DESCRIPTION="Linux kernel built with Gentoo patches" HOMEPAGE="https://www.kernel.org/" diff --git a/sys-kernel/gentoo-kernel/gentoo-kernel-5.10.12.ebuild b/sys-kernel/gentoo-kernel/gentoo-kernel-5.11.2.ebuild index b34a35880d65..498040ab71be 100644 --- a/sys-kernel/gentoo-kernel/gentoo-kernel-5.10.12.ebuild +++ b/sys-kernel/gentoo-kernel/gentoo-kernel-5.11.2.ebuild @@ -6,11 +6,11 @@ EAPI=7 inherit kernel-build MY_P=linux-${PV%.*} -GENPATCHES_P=genpatches-${PV%.*}-$(( ${PV##*.} + 2 )) +GENPATCHES_P=genpatches-${PV%.*}-$(( ${PV##*.} + 1 )) # https://koji.fedoraproject.org/koji/packageinfo?packageID=8 -CONFIG_VER=5.10.7 -CONFIG_HASH=b238267df7cd80dc3aa6b5b654cbe145367383df -GENTOO_CONFIG_VER=5.10.7 +CONFIG_VER=5.11.1 +CONFIG_HASH=07992209452cd7ba529ffdbdd83d01d44cd8ae14 +GENTOO_CONFIG_VER=5.10.18 DESCRIPTION="Linux kernel built with Gentoo patches" HOMEPAGE="https://www.kernel.org/" diff --git a/sys-kernel/gentoo-kernel/gentoo-kernel-5.4.91.ebuild b/sys-kernel/gentoo-kernel/gentoo-kernel-5.4.100.ebuild index e8748c9098fd..e8748c9098fd 100644 --- a/sys-kernel/gentoo-kernel/gentoo-kernel-5.4.91.ebuild +++ b/sys-kernel/gentoo-kernel/gentoo-kernel-5.4.100.ebuild diff --git a/sys-kernel/gentoo-kernel/gentoo-kernel-5.4.92.ebuild b/sys-kernel/gentoo-kernel/gentoo-kernel-5.4.101.ebuild index e8748c9098fd..7c3266150716 100644 --- a/sys-kernel/gentoo-kernel/gentoo-kernel-5.4.92.ebuild +++ b/sys-kernel/gentoo-kernel/gentoo-kernel-5.4.101.ebuild @@ -6,7 +6,7 @@ EAPI=7 inherit kernel-build MY_P=linux-${PV%.*} -GENPATCHES_P=genpatches-${PV%.*}-$(( ${PV##*.} + 2 )) +GENPATCHES_P=genpatches-${PV%.*}-$(( ${PV##*.} + 3 )) # https://koji.fedoraproject.org/koji/packageinfo?packageID=8 CONFIG_VER=5.4.21 CONFIG_HASH=2809b7faa6a8cb232cd825096c146b7bdc1e08ea @@ -15,8 +15,8 @@ GENTOO_CONFIG_VER=5.4.89 DESCRIPTION="Linux kernel built with Gentoo patches" HOMEPAGE="https://www.kernel.org/" SRC_URI+=" https://cdn.kernel.org/pub/linux/kernel/v$(ver_cut 1).x/${MY_P}.tar.xz - https://dev.gentoo.org/~mpagano/dist/genpatches/${GENPATCHES_P}.base.tar.xz - https://dev.gentoo.org/~mpagano/dist/genpatches/${GENPATCHES_P}.extras.tar.xz + https://dev.gentoo.org/~alicef/dist/genpatches/${GENPATCHES_P}.base.tar.xz + https://dev.gentoo.org/~alicef/dist/genpatches/${GENPATCHES_P}.extras.tar.xz https://github.com/mgorny/gentoo-kernel-config/archive/v${GENTOO_CONFIG_VER}.tar.gz -> gentoo-kernel-config-${GENTOO_CONFIG_VER}.tar.gz amd64? ( diff --git a/sys-kernel/gentoo-kernel/gentoo-kernel-5.4.80-r1.ebuild b/sys-kernel/gentoo-kernel/gentoo-kernel-5.4.80-r1.ebuild deleted file mode 100644 index a9746567969a..000000000000 --- a/sys-kernel/gentoo-kernel/gentoo-kernel-5.4.80-r1.ebuild +++ /dev/null @@ -1,94 +0,0 @@ -# Copyright 2020 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI=7 - -inherit kernel-build - -MY_P=linux-${PV%.*} -GENPATCHES_P=genpatches-${PV%.*}-$(( ${PV##*.} + 2 )) -# https://koji.fedoraproject.org/koji/packageinfo?packageID=8 -CONFIG_VER=5.4.21 -CONFIG_HASH=2809b7faa6a8cb232cd825096c146b7bdc1e08ea -GENTOO_CONFIG_VER=5.4.77-r1 - -DESCRIPTION="Linux kernel built with Gentoo patches" -HOMEPAGE="https://www.kernel.org/" -SRC_URI+=" https://cdn.kernel.org/pub/linux/kernel/v$(ver_cut 1).x/${MY_P}.tar.xz - https://dev.gentoo.org/~mpagano/dist/genpatches/${GENPATCHES_P}.base.tar.xz - https://dev.gentoo.org/~mpagano/dist/genpatches/${GENPATCHES_P}.extras.tar.xz - https://github.com/mgorny/gentoo-kernel-config/archive/v${GENTOO_CONFIG_VER}.tar.gz - -> gentoo-kernel-config-${GENTOO_CONFIG_VER}.tar.gz - amd64? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-x86_64.config - -> kernel-x86_64.config.${CONFIG_VER} - ) - arm64? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-aarch64.config - -> kernel-aarch64.config.${CONFIG_VER} - ) - ppc64? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-ppc64le.config - -> kernel-ppc64le.config.${CONFIG_VER} - ) - x86? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-i686.config - -> kernel-i686.config.${CONFIG_VER} - )" -S=${WORKDIR}/${MY_P} - -LICENSE="GPL-2" -KEYWORDS="amd64 ~arm64 ~ppc64 x86" -IUSE="debug" - -RDEPEND=" - !sys-kernel/vanilla-kernel:${SLOT} - !sys-kernel/vanilla-kernel-bin:${SLOT}" -BDEPEND=" - debug? ( dev-util/dwarves )" - -pkg_pretend() { - ewarn "Starting with 5.4.52, Distribution Kernels are switching from Arch" - ewarn "Linux configs to Fedora. Please keep a backup kernel just in case." - - kernel-install_pkg_pretend -} - -src_prepare() { - local PATCHES=( - # meh, genpatches have no directory - "${WORKDIR}"/*.patch - ) - default - - # prepare the default config - case ${ARCH} in - amd64) - cp "${DISTDIR}/kernel-x86_64.config.${CONFIG_VER}" .config || die - ;; - arm64) - cp "${DISTDIR}/kernel-aarch64.config.${CONFIG_VER}" .config || die - ;; - ppc64) - cp "${DISTDIR}/kernel-ppc64le.config.${CONFIG_VER}" .config || die - ;; - x86) - cp "${DISTDIR}/kernel-i686.config.${CONFIG_VER}" .config || die - ;; - *) - die "Unsupported arch ${ARCH}" - ;; - esac - - local merge_configs=( - "${WORKDIR}/gentoo-kernel-config-${GENTOO_CONFIG_VER}"/base.config - ) - use debug || merge_configs+=( - "${WORKDIR}/gentoo-kernel-config-${GENTOO_CONFIG_VER}"/no-debug.config - ) - [[ ${ARCH} == x86 ]] && merge_configs+=( - "${WORKDIR}/gentoo-kernel-config-${GENTOO_CONFIG_VER}"/32-bit.config - ) - - kernel-build_merge_configs "${merge_configs[@]}" -} diff --git a/sys-kernel/gentoo-kernel/gentoo-kernel-5.4.80.ebuild b/sys-kernel/gentoo-kernel/gentoo-kernel-5.4.80.ebuild deleted file mode 100644 index 348823c20ed5..000000000000 --- a/sys-kernel/gentoo-kernel/gentoo-kernel-5.4.80.ebuild +++ /dev/null @@ -1,94 +0,0 @@ -# Copyright 2020 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI=7 - -inherit kernel-build - -MY_P=linux-${PV%.*} -GENPATCHES_P=genpatches-${PV%.*}-$(( ${PV##*.} + 1 )) -# https://koji.fedoraproject.org/koji/packageinfo?packageID=8 -CONFIG_VER=5.4.21 -CONFIG_HASH=2809b7faa6a8cb232cd825096c146b7bdc1e08ea -GENTOO_CONFIG_VER=5.4.77-r1 - -DESCRIPTION="Linux kernel built with Gentoo patches" -HOMEPAGE="https://www.kernel.org/" -SRC_URI+=" https://cdn.kernel.org/pub/linux/kernel/v$(ver_cut 1).x/${MY_P}.tar.xz - https://dev.gentoo.org/~mpagano/dist/genpatches/${GENPATCHES_P}.base.tar.xz - https://dev.gentoo.org/~mpagano/dist/genpatches/${GENPATCHES_P}.extras.tar.xz - https://github.com/mgorny/gentoo-kernel-config/archive/v${GENTOO_CONFIG_VER}.tar.gz - -> gentoo-kernel-config-${GENTOO_CONFIG_VER}.tar.gz - amd64? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-x86_64.config - -> kernel-x86_64.config.${CONFIG_VER} - ) - arm64? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-aarch64.config - -> kernel-aarch64.config.${CONFIG_VER} - ) - ppc64? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-ppc64le.config - -> kernel-ppc64le.config.${CONFIG_VER} - ) - x86? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-i686.config - -> kernel-i686.config.${CONFIG_VER} - )" -S=${WORKDIR}/${MY_P} - -LICENSE="GPL-2" -KEYWORDS="~amd64 arm64 ppc64 ~x86" -IUSE="debug" - -RDEPEND=" - !sys-kernel/vanilla-kernel:${SLOT} - !sys-kernel/vanilla-kernel-bin:${SLOT}" -BDEPEND=" - debug? ( dev-util/dwarves )" - -pkg_pretend() { - ewarn "Starting with 5.4.52, Distribution Kernels are switching from Arch" - ewarn "Linux configs to Fedora. Please keep a backup kernel just in case." - - kernel-install_pkg_pretend -} - -src_prepare() { - local PATCHES=( - # meh, genpatches have no directory - "${WORKDIR}"/*.patch - ) - default - - # prepare the default config - case ${ARCH} in - amd64) - cp "${DISTDIR}/kernel-x86_64.config.${CONFIG_VER}" .config || die - ;; - arm64) - cp "${DISTDIR}/kernel-aarch64.config.${CONFIG_VER}" .config || die - ;; - ppc64) - cp "${DISTDIR}/kernel-ppc64le.config.${CONFIG_VER}" .config || die - ;; - x86) - cp "${DISTDIR}/kernel-i686.config.${CONFIG_VER}" .config || die - ;; - *) - die "Unsupported arch ${ARCH}" - ;; - esac - - local merge_configs=( - "${WORKDIR}/gentoo-kernel-config-${GENTOO_CONFIG_VER}"/base.config - ) - use debug || merge_configs+=( - "${WORKDIR}/gentoo-kernel-config-${GENTOO_CONFIG_VER}"/no-debug.config - ) - [[ ${ARCH} == x86 ]] && merge_configs+=( - "${WORKDIR}/gentoo-kernel-config-${GENTOO_CONFIG_VER}"/32-bit.config - ) - - kernel-build_merge_configs "${merge_configs[@]}" -} diff --git a/sys-kernel/gentoo-kernel/gentoo-kernel-5.4.83.ebuild b/sys-kernel/gentoo-kernel/gentoo-kernel-5.4.83.ebuild deleted file mode 100644 index 37b2c84e06d5..000000000000 --- a/sys-kernel/gentoo-kernel/gentoo-kernel-5.4.83.ebuild +++ /dev/null @@ -1,94 +0,0 @@ -# Copyright 2020 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI=7 - -inherit kernel-build - -MY_P=linux-${PV%.*} -GENPATCHES_P=genpatches-${PV%.*}-$(( ${PV##*.} + 2 )) -# https://koji.fedoraproject.org/koji/packageinfo?packageID=8 -CONFIG_VER=5.4.21 -CONFIG_HASH=2809b7faa6a8cb232cd825096c146b7bdc1e08ea -GENTOO_CONFIG_VER=5.4.77-r1 - -DESCRIPTION="Linux kernel built with Gentoo patches" -HOMEPAGE="https://www.kernel.org/" -SRC_URI+=" https://cdn.kernel.org/pub/linux/kernel/v$(ver_cut 1).x/${MY_P}.tar.xz - https://dev.gentoo.org/~mpagano/dist/genpatches/${GENPATCHES_P}.base.tar.xz - https://dev.gentoo.org/~mpagano/dist/genpatches/${GENPATCHES_P}.extras.tar.xz - https://github.com/mgorny/gentoo-kernel-config/archive/v${GENTOO_CONFIG_VER}.tar.gz - -> gentoo-kernel-config-${GENTOO_CONFIG_VER}.tar.gz - amd64? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-x86_64.config - -> kernel-x86_64.config.${CONFIG_VER} - ) - arm64? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-aarch64.config - -> kernel-aarch64.config.${CONFIG_VER} - ) - ppc64? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-ppc64le.config - -> kernel-ppc64le.config.${CONFIG_VER} - ) - x86? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-i686.config - -> kernel-i686.config.${CONFIG_VER} - )" -S=${WORKDIR}/${MY_P} - -LICENSE="GPL-2" -KEYWORDS="amd64 arm64 ~ppc64 ~x86" -IUSE="debug" - -RDEPEND=" - !sys-kernel/vanilla-kernel:${SLOT} - !sys-kernel/vanilla-kernel-bin:${SLOT}" -BDEPEND=" - debug? ( dev-util/dwarves )" - -pkg_pretend() { - ewarn "Starting with 5.4.52, Distribution Kernels are switching from Arch" - ewarn "Linux configs to Fedora. Please keep a backup kernel just in case." - - kernel-install_pkg_pretend -} - -src_prepare() { - local PATCHES=( - # meh, genpatches have no directory - "${WORKDIR}"/*.patch - ) - default - - # prepare the default config - case ${ARCH} in - amd64) - cp "${DISTDIR}/kernel-x86_64.config.${CONFIG_VER}" .config || die - ;; - arm64) - cp "${DISTDIR}/kernel-aarch64.config.${CONFIG_VER}" .config || die - ;; - ppc64) - cp "${DISTDIR}/kernel-ppc64le.config.${CONFIG_VER}" .config || die - ;; - x86) - cp "${DISTDIR}/kernel-i686.config.${CONFIG_VER}" .config || die - ;; - *) - die "Unsupported arch ${ARCH}" - ;; - esac - - local merge_configs=( - "${WORKDIR}/gentoo-kernel-config-${GENTOO_CONFIG_VER}"/base.config - ) - use debug || merge_configs+=( - "${WORKDIR}/gentoo-kernel-config-${GENTOO_CONFIG_VER}"/no-debug.config - ) - [[ ${ARCH} == x86 ]] && merge_configs+=( - "${WORKDIR}/gentoo-kernel-config-${GENTOO_CONFIG_VER}"/32-bit.config - ) - - kernel-build_merge_configs "${merge_configs[@]}" -} diff --git a/sys-kernel/gentoo-kernel/gentoo-kernel-5.4.88.ebuild b/sys-kernel/gentoo-kernel/gentoo-kernel-5.4.88.ebuild deleted file mode 100644 index e86c0b79240f..000000000000 --- a/sys-kernel/gentoo-kernel/gentoo-kernel-5.4.88.ebuild +++ /dev/null @@ -1,96 +0,0 @@ -# Copyright 2020-2021 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI=7 - -inherit kernel-build - -MY_P=linux-${PV%.*} -GENPATCHES_P=genpatches-${PV%.*}-$(( ${PV##*.} + 2 )) -# https://koji.fedoraproject.org/koji/packageinfo?packageID=8 -CONFIG_VER=5.4.21 -CONFIG_HASH=2809b7faa6a8cb232cd825096c146b7bdc1e08ea -GENTOO_CONFIG_VER=5.4.77-r1 - -DESCRIPTION="Linux kernel built with Gentoo patches" -HOMEPAGE="https://www.kernel.org/" -SRC_URI+=" https://cdn.kernel.org/pub/linux/kernel/v$(ver_cut 1).x/${MY_P}.tar.xz - https://dev.gentoo.org/~mpagano/dist/genpatches/${GENPATCHES_P}.base.tar.xz - https://dev.gentoo.org/~mpagano/dist/genpatches/${GENPATCHES_P}.extras.tar.xz - https://github.com/mgorny/gentoo-kernel-config/archive/v${GENTOO_CONFIG_VER}.tar.gz - -> gentoo-kernel-config-${GENTOO_CONFIG_VER}.tar.gz - amd64? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-x86_64.config - -> kernel-x86_64.config.${CONFIG_VER} - ) - arm64? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-aarch64.config - -> kernel-aarch64.config.${CONFIG_VER} - ) - ppc64? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-ppc64le.config - -> kernel-ppc64le.config.${CONFIG_VER} - ) - x86? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-i686.config - -> kernel-i686.config.${CONFIG_VER} - )" -S=${WORKDIR}/${MY_P} - -LICENSE="GPL-2" -KEYWORDS="amd64 arm64 ~ppc64 ~x86" -IUSE="debug" - -RDEPEND=" - !sys-kernel/vanilla-kernel:${SLOT} - !sys-kernel/vanilla-kernel-bin:${SLOT}" -BDEPEND=" - debug? ( dev-util/dwarves )" -PDEPEND=" - >=virtual/dist-kernel-${PV}" - -pkg_pretend() { - ewarn "Starting with 5.4.52, Distribution Kernels are switching from Arch" - ewarn "Linux configs to Fedora. Please keep a backup kernel just in case." - - kernel-install_pkg_pretend -} - -src_prepare() { - local PATCHES=( - # meh, genpatches have no directory - "${WORKDIR}"/*.patch - ) - default - - # prepare the default config - case ${ARCH} in - amd64) - cp "${DISTDIR}/kernel-x86_64.config.${CONFIG_VER}" .config || die - ;; - arm64) - cp "${DISTDIR}/kernel-aarch64.config.${CONFIG_VER}" .config || die - ;; - ppc64) - cp "${DISTDIR}/kernel-ppc64le.config.${CONFIG_VER}" .config || die - ;; - x86) - cp "${DISTDIR}/kernel-i686.config.${CONFIG_VER}" .config || die - ;; - *) - die "Unsupported arch ${ARCH}" - ;; - esac - - local merge_configs=( - "${WORKDIR}/gentoo-kernel-config-${GENTOO_CONFIG_VER}"/base.config - ) - use debug || merge_configs+=( - "${WORKDIR}/gentoo-kernel-config-${GENTOO_CONFIG_VER}"/no-debug.config - ) - [[ ${ARCH} == x86 ]] && merge_configs+=( - "${WORKDIR}/gentoo-kernel-config-${GENTOO_CONFIG_VER}"/32-bit.config - ) - - kernel-build_merge_configs "${merge_configs[@]}" -} diff --git a/sys-kernel/gentoo-kernel/gentoo-kernel-5.4.93.ebuild b/sys-kernel/gentoo-kernel/gentoo-kernel-5.4.93.ebuild deleted file mode 100644 index e8748c9098fd..000000000000 --- a/sys-kernel/gentoo-kernel/gentoo-kernel-5.4.93.ebuild +++ /dev/null @@ -1,96 +0,0 @@ -# Copyright 2020-2021 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI=7 - -inherit kernel-build - -MY_P=linux-${PV%.*} -GENPATCHES_P=genpatches-${PV%.*}-$(( ${PV##*.} + 2 )) -# https://koji.fedoraproject.org/koji/packageinfo?packageID=8 -CONFIG_VER=5.4.21 -CONFIG_HASH=2809b7faa6a8cb232cd825096c146b7bdc1e08ea -GENTOO_CONFIG_VER=5.4.89 - -DESCRIPTION="Linux kernel built with Gentoo patches" -HOMEPAGE="https://www.kernel.org/" -SRC_URI+=" https://cdn.kernel.org/pub/linux/kernel/v$(ver_cut 1).x/${MY_P}.tar.xz - https://dev.gentoo.org/~mpagano/dist/genpatches/${GENPATCHES_P}.base.tar.xz - https://dev.gentoo.org/~mpagano/dist/genpatches/${GENPATCHES_P}.extras.tar.xz - https://github.com/mgorny/gentoo-kernel-config/archive/v${GENTOO_CONFIG_VER}.tar.gz - -> gentoo-kernel-config-${GENTOO_CONFIG_VER}.tar.gz - amd64? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-x86_64.config - -> kernel-x86_64.config.${CONFIG_VER} - ) - arm64? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-aarch64.config - -> kernel-aarch64.config.${CONFIG_VER} - ) - ppc64? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-ppc64le.config - -> kernel-ppc64le.config.${CONFIG_VER} - ) - x86? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-i686.config - -> kernel-i686.config.${CONFIG_VER} - )" -S=${WORKDIR}/${MY_P} - -LICENSE="GPL-2" -KEYWORDS="~amd64 ~arm64 ~ppc64 ~x86" -IUSE="debug" - -RDEPEND=" - !sys-kernel/vanilla-kernel:${SLOT} - !sys-kernel/vanilla-kernel-bin:${SLOT}" -BDEPEND=" - debug? ( dev-util/dwarves )" -PDEPEND=" - >=virtual/dist-kernel-${PV}" - -pkg_pretend() { - ewarn "Starting with 5.4.52, Distribution Kernels are switching from Arch" - ewarn "Linux configs to Fedora. Please keep a backup kernel just in case." - - kernel-install_pkg_pretend -} - -src_prepare() { - local PATCHES=( - # meh, genpatches have no directory - "${WORKDIR}"/*.patch - ) - default - - # prepare the default config - case ${ARCH} in - amd64) - cp "${DISTDIR}/kernel-x86_64.config.${CONFIG_VER}" .config || die - ;; - arm64) - cp "${DISTDIR}/kernel-aarch64.config.${CONFIG_VER}" .config || die - ;; - ppc64) - cp "${DISTDIR}/kernel-ppc64le.config.${CONFIG_VER}" .config || die - ;; - x86) - cp "${DISTDIR}/kernel-i686.config.${CONFIG_VER}" .config || die - ;; - *) - die "Unsupported arch ${ARCH}" - ;; - esac - - local merge_configs=( - "${WORKDIR}/gentoo-kernel-config-${GENTOO_CONFIG_VER}"/base.config - ) - use debug || merge_configs+=( - "${WORKDIR}/gentoo-kernel-config-${GENTOO_CONFIG_VER}"/no-debug.config - ) - [[ ${ARCH} == x86 ]] && merge_configs+=( - "${WORKDIR}/gentoo-kernel-config-${GENTOO_CONFIG_VER}"/32-bit.config - ) - - kernel-build_merge_configs "${merge_configs[@]}" -} diff --git a/sys-kernel/gentoo-kernel/gentoo-kernel-5.4.94.ebuild b/sys-kernel/gentoo-kernel/gentoo-kernel-5.4.94.ebuild index f26abd9fdf78..789220f8e3e7 100644 --- a/sys-kernel/gentoo-kernel/gentoo-kernel-5.4.94.ebuild +++ b/sys-kernel/gentoo-kernel/gentoo-kernel-5.4.94.ebuild @@ -38,7 +38,7 @@ SRC_URI+=" https://cdn.kernel.org/pub/linux/kernel/v$(ver_cut 1).x/${MY_P}.tar.x S=${WORKDIR}/${MY_P} LICENSE="GPL-2" -KEYWORDS="~amd64 ~arm64 ~ppc64 ~x86" +KEYWORDS="amd64 arm64 ppc64 x86" IUSE="debug" RDEPEND=" diff --git a/sys-kernel/gentoo-kernel/gentoo-kernel-5.4.95.ebuild b/sys-kernel/gentoo-kernel/gentoo-kernel-5.4.95.ebuild deleted file mode 100644 index e8748c9098fd..000000000000 --- a/sys-kernel/gentoo-kernel/gentoo-kernel-5.4.95.ebuild +++ /dev/null @@ -1,96 +0,0 @@ -# Copyright 2020-2021 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI=7 - -inherit kernel-build - -MY_P=linux-${PV%.*} -GENPATCHES_P=genpatches-${PV%.*}-$(( ${PV##*.} + 2 )) -# https://koji.fedoraproject.org/koji/packageinfo?packageID=8 -CONFIG_VER=5.4.21 -CONFIG_HASH=2809b7faa6a8cb232cd825096c146b7bdc1e08ea -GENTOO_CONFIG_VER=5.4.89 - -DESCRIPTION="Linux kernel built with Gentoo patches" -HOMEPAGE="https://www.kernel.org/" -SRC_URI+=" https://cdn.kernel.org/pub/linux/kernel/v$(ver_cut 1).x/${MY_P}.tar.xz - https://dev.gentoo.org/~mpagano/dist/genpatches/${GENPATCHES_P}.base.tar.xz - https://dev.gentoo.org/~mpagano/dist/genpatches/${GENPATCHES_P}.extras.tar.xz - https://github.com/mgorny/gentoo-kernel-config/archive/v${GENTOO_CONFIG_VER}.tar.gz - -> gentoo-kernel-config-${GENTOO_CONFIG_VER}.tar.gz - amd64? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-x86_64.config - -> kernel-x86_64.config.${CONFIG_VER} - ) - arm64? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-aarch64.config - -> kernel-aarch64.config.${CONFIG_VER} - ) - ppc64? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-ppc64le.config - -> kernel-ppc64le.config.${CONFIG_VER} - ) - x86? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-i686.config - -> kernel-i686.config.${CONFIG_VER} - )" -S=${WORKDIR}/${MY_P} - -LICENSE="GPL-2" -KEYWORDS="~amd64 ~arm64 ~ppc64 ~x86" -IUSE="debug" - -RDEPEND=" - !sys-kernel/vanilla-kernel:${SLOT} - !sys-kernel/vanilla-kernel-bin:${SLOT}" -BDEPEND=" - debug? ( dev-util/dwarves )" -PDEPEND=" - >=virtual/dist-kernel-${PV}" - -pkg_pretend() { - ewarn "Starting with 5.4.52, Distribution Kernels are switching from Arch" - ewarn "Linux configs to Fedora. Please keep a backup kernel just in case." - - kernel-install_pkg_pretend -} - -src_prepare() { - local PATCHES=( - # meh, genpatches have no directory - "${WORKDIR}"/*.patch - ) - default - - # prepare the default config - case ${ARCH} in - amd64) - cp "${DISTDIR}/kernel-x86_64.config.${CONFIG_VER}" .config || die - ;; - arm64) - cp "${DISTDIR}/kernel-aarch64.config.${CONFIG_VER}" .config || die - ;; - ppc64) - cp "${DISTDIR}/kernel-ppc64le.config.${CONFIG_VER}" .config || die - ;; - x86) - cp "${DISTDIR}/kernel-i686.config.${CONFIG_VER}" .config || die - ;; - *) - die "Unsupported arch ${ARCH}" - ;; - esac - - local merge_configs=( - "${WORKDIR}/gentoo-kernel-config-${GENTOO_CONFIG_VER}"/base.config - ) - use debug || merge_configs+=( - "${WORKDIR}/gentoo-kernel-config-${GENTOO_CONFIG_VER}"/no-debug.config - ) - [[ ${ARCH} == x86 ]] && merge_configs+=( - "${WORKDIR}/gentoo-kernel-config-${GENTOO_CONFIG_VER}"/32-bit.config - ) - - kernel-build_merge_configs "${merge_configs[@]}" -} diff --git a/sys-kernel/gentoo-kernel/gentoo-kernel-5.4.97.ebuild b/sys-kernel/gentoo-kernel/gentoo-kernel-5.4.97.ebuild index f26abd9fdf78..ebd06b8aecfd 100644 --- a/sys-kernel/gentoo-kernel/gentoo-kernel-5.4.97.ebuild +++ b/sys-kernel/gentoo-kernel/gentoo-kernel-5.4.97.ebuild @@ -38,7 +38,7 @@ SRC_URI+=" https://cdn.kernel.org/pub/linux/kernel/v$(ver_cut 1).x/${MY_P}.tar.x S=${WORKDIR}/${MY_P} LICENSE="GPL-2" -KEYWORDS="~amd64 ~arm64 ~ppc64 ~x86" +KEYWORDS="amd64 ~arm64 ppc64 ~x86" IUSE="debug" RDEPEND=" diff --git a/sys-kernel/gentoo-kernel/gentoo-kernel-5.4.96.ebuild b/sys-kernel/gentoo-kernel/gentoo-kernel-5.4.99.ebuild index f26abd9fdf78..f26abd9fdf78 100644 --- a/sys-kernel/gentoo-kernel/gentoo-kernel-5.4.96.ebuild +++ b/sys-kernel/gentoo-kernel/gentoo-kernel-5.4.99.ebuild diff --git a/sys-kernel/gentoo-kernel/metadata.xml b/sys-kernel/gentoo-kernel/metadata.xml index b0b959adbe61..3eca39567e28 100644 --- a/sys-kernel/gentoo-kernel/metadata.xml +++ b/sys-kernel/gentoo-kernel/metadata.xml @@ -1,11 +1,13 @@ <?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE pkgmetadata SYSTEM "http://www.gentoo.org/dtd/metadata.dtd"> +<!DOCTYPE pkgmetadata SYSTEM "https://liguros.gitlab.io/dtd/metadata.dtd"> <pkgmetadata> - <maintainer type="project"> - <email>dist-kernel@gentoo.org</email> - <name>Distribution Kernel Project</name> - </maintainer> - <use> - <flag name='initramfs'>Build initramfs along with the kernel.</flag> - </use> -</pkgmetadata> + <maintainer type="project"> + <email>dist-kernel@gentoo.org</email> + <name>Distribution Kernel Project</name> + </maintainer> + + <use> + <flag name="initramfs">Build initramfs along with the kernel.</flag> + </use> + <origin>gentoo-staging</origin> +</pkgmetadata>
\ No newline at end of file diff --git a/sys-kernel/gentoo-sources/Manifest b/sys-kernel/gentoo-sources/Manifest index d1ccc8e09d35..25e010b238f6 100644 --- a/sys-kernel/gentoo-sources/Manifest +++ b/sys-kernel/gentoo-sources/Manifest @@ -1,18 +1,6 @@ DIST genpatches-4.14-219.base.tar.xz 4733352 BLAKE2B 3a2c41bcdee77395ae2b19ee4a9e53771795d2b21a9a31c821d20853521f911ceb6f49219fd9c2e65fe0088251aa6cdee2a139e5d3f23f5cd665001e48154822 SHA512 a0837de333740e20a870324638b81708133420e7c9152bb194ef5623f29a38df6b8211686fb13f9b6f3785be8071c1dc3cbc989cae8cecda79db97aaf85d1868 DIST genpatches-4.14-219.experimental.tar.xz 6092 BLAKE2B 7df1ac766e4bda252718f06751aae3181af7bbf68e609562db059577c8d123e816fde728a049a9d1ea3baa4148d9433c5c698c79e61097ec2de2389ea781216f SHA512 1dbee51c8021a3103c64e79684ed810de436d88f3f1883c4d53b1898a55274600da07f452910eece720b0cee1f6a6d32af68760a468a42759bd9b0b15e28eea4 DIST genpatches-4.14-219.extras.tar.xz 3340 BLAKE2B 2a7077ff685b93d393f8c1ef3e7d02fcc3aa69ec209d88cc19339e4a5bf64e29e456f88cd1d49826e4a81537622365cd390884d6a621e358525179c0f97f343e SHA512 e2e32ebb01afdeb67c4556982c9a9abaa26f0fb46d251c07513e191b03429d9c238193345fb4c6b08de315e67d89b28f675da4ef942c30ec4d9ba31d8466a913 -DIST genpatches-4.14-225.base.tar.xz 4819872 BLAKE2B f5bf3d4870b155bd88ca80e0b2fa58d85d5b29abbf35ed7d9c9f5032c3c023f0fb50a398896a7159d0c7b2c6a1a2f4305d08f684a64bef9d6c4d5ffaf9805ee7 SHA512 3a96311f51ed2958174b369f549d7e2f705ba5d01fccc28211e4ee915fdbf44c9aac2136ce5ac44cf01be342dadcdc32438d9be3eef53b31c77eba2c64a01938 -DIST genpatches-4.14-225.experimental.tar.xz 6084 BLAKE2B 7367e447e62008580611d138e88175965b19bdb698a68c7320d49357e95e15cd2ee031a37085455c7cd544d7b60ea25c712bdf4bf3428b8b3231631a7c897de2 SHA512 4212233753d8dae8124536f0710acd3250975be78bcbd697bf42aea2623f00359201767da334ddfbabb554ad26eafdbafca65cb3f326e5ef8162084104208290 -DIST genpatches-4.14-225.extras.tar.xz 3336 BLAKE2B 3f151cbd04ed1b4767e648433997750dc9e1a511736418abad915c48922af37f80907aa968ab2566ad7a307f332e6dee5619d29173a70e6acf2ffaf59c40b73c SHA512 cd05474af1809daeb4e2198fa2415e29f336fb61c8e2b65c93c520dcd47f225b26daf577529c4673efe6aba17070e626a80ce5d0e298e896888ef16a56aa59be -DIST genpatches-4.14-226.base.tar.xz 4824692 BLAKE2B 06e014464e4e9b394cf2122f25cfffae949d97698f211e25c029826efe36f696d134f3c0cba0f80d2599fb1dab675f5f004b737785f98a654802b7e28856a5fd SHA512 e10fde32e50f151543ab4739a3e19aa168193fccbd1d91c02946ecf56abfe45e99a442ee060cd16ea7f11e65c1181441c5f61a9c38a633589c754e32d10f4994 -DIST genpatches-4.14-226.experimental.tar.xz 6088 BLAKE2B 85ee64c4fba94e2e3a5633af8abc931ee0969de8ab414194b58f80c509847ec6e8b836a193512e73deabdbcef4da0e034b32760b907ea41d7c5fc06154969815 SHA512 fb1e7b6bc51729c987bf346f968354d6a7155a2322a989a3f9ab411f53e5408918e6dd02c4b0a3b6ee18089f4e19f548a3b23faebe65fb063175edd824133399 -DIST genpatches-4.14-226.extras.tar.xz 3340 BLAKE2B c427ad8d18fb57bb6c0d47a920bd903f26f5ac0b6c8358640e07d00ef33f54a45523087eed8cd6ef474f2907be9d5ed74e6c0f46994678daeccc2495696432a5 SHA512 311ee330b643ffc3832e45f20f0e762b157645747f85105034a15d4c775e8ba7f67b985d49da55d04f7046f70e0f923957703efcc0aaabe9c658c6debb5f2c4f -DIST genpatches-4.14-227.base.tar.xz 4831676 BLAKE2B 052c6f13209c589fa53a9c57fe39e1b8b6a12070ad075a4d2fee99b22becab8e8642466c1d01f17e5d5492e1a25b804910c77de78e57ec99deba43af13151c3a SHA512 38a5dfb3e870a52821a99e7bc11f10cf549c86fce2d80767e21e5e7f470d3f4fde8ec8dba107224cef351ad0095520c50d640e6741cc81b96b77d3fc4e418fa8 -DIST genpatches-4.14-227.experimental.tar.xz 6084 BLAKE2B abb57683a3f22bdde5e8c4b6cbd9ae239a10ef59d099c5e2ad6006b9bc7139e7b9f8ebfa892b8675cf7a62cc4dc879cf4b9f21a51bebbd32b30ac7989826d24a SHA512 87503496543f94d5b79f71da4c73deba7e771b47af813e4b9023e120b6f356b15655e84e3ab30be06a694245f12dae33e80a8b67da35f784fd6909dbce8f219b -DIST genpatches-4.14-227.extras.tar.xz 3340 BLAKE2B 7921c02980b16c19b19807f776f5f0513619f24621580240065fc119008c92fe16ec4eb7e2b08991e5390559a0ac9a0c2c7a22f77ebaeed362ad6f2b06fbe2c8 SHA512 a02fe59fac681b177fed6a28b9bf1e5d4ba5c7401ec4d783ffc5169037f23fb8d2a5fdc439e3d4eb2c0d8807080c69b470027bbbe1eecb671608d512c83f5364 -DIST genpatches-4.14-228.base.tar.xz 4842300 BLAKE2B 9fbcaeecc9913e8f3e959201aee3575321f065e971d7db606ba86bfef225ce78e7c72e7be700bb0ee5501d8cf9e8b00576f6b43a3106b3d7ad0f02a9c2968d33 SHA512 08abf23ac36704d0cefea99449c9fa425051f0cea60c6c090c0d92f9159f587f90813a471337d553e361efa3346f5205eb6d8c7bed572d0e066986849343c39b -DIST genpatches-4.14-228.experimental.tar.xz 6088 BLAKE2B 5d4770913b9269743abbf9051ae66c1569a4c7aa04286609a39a22258c3fe876964a5596737d7a755d1fd543eca249e8986949c66e47f4ab51d91781f42168eb SHA512 0ed1fefe93a5c0c3324946901ee8b4ea59717d1ef30efd39df83b834df8b30a40856128fbe811c6b66d14d7f826b024e195cdf697453a708c846a314053bdedb -DIST genpatches-4.14-228.extras.tar.xz 3344 BLAKE2B 1e89184144c4640f821dda2b58e898f6992a5ae2844b39da40ed06cf0e8b3e9a0ce74c9e7d8ecca5bfb35be8a2ab799cff8581d9927b4f108389c1a65922364e SHA512 ef2f7dbcfd199d1f5410c9014ab3b15c1501c1b3c14e19a6d905848a64844bbcf1e9c369c520d9965aa086a84f96a33eef7fba8e163a7613fa6720f657cce2cf DIST genpatches-4.14-229.base.tar.xz 4847632 BLAKE2B 2455fa20f83a0867c80cedd06df645ff99452cabbe03121489dfa99c3bb26db792b40d88989fbdfb8eb1a9607bdaaaba6bbabdc6852594715f26903d54c58415 SHA512 8b6043c69277ad0b48249b2c888a660df31cc9edb3c52d68bfc4a9d62b81ff4c60618932a115d7fb4e01b09b68890e7bd5f9970ce674b1e45699d3f46c85af4a DIST genpatches-4.14-229.experimental.tar.xz 6088 BLAKE2B 4508ad523cda5e0f9760ad5fd26ee24d90aab18cbfecc714303b3804545e3457375f33cee87f9f709bec0bdc4a3aba7a53b25cf37535c532dc9376f1d2289a01 SHA512 dd07b6362de2d587ef809f9601c503d6e984d78ba2b635fab475feed16933d000d0fe943dc6d8798943debaefeeb387490c26aa0c520744153c6aa23d1355d21 DIST genpatches-4.14-229.extras.tar.xz 3340 BLAKE2B 6fc4b2789946d350f28b00b800bf78e85a2f882a746ff9da3ebae89e788db195a166b9b4907251db04594e0f3592089d0a189ddc75a0cf45db3dcb97df57cf00 SHA512 772fea4386df287a8d6ddad9508dc95427e911c7bac7ceb9b70bc32db44701548951f3ea783e12f82219e45c6abce12f81a59664009ab92ce8c52eb63dac202a @@ -22,24 +10,12 @@ DIST genpatches-4.14-230.extras.tar.xz 3340 BLAKE2B 0d4d5873573cfbb9c38dff979278 DIST genpatches-4.14-231.base.tar.xz 4857832 BLAKE2B ce145e696b67a55b69ac7cb20cf1aea9066ad9b58b1863fe5251243253d4e4a01bbddf0e1cce99c6e776a46326137f7269edf306cc10c9d9555d3844306a9cb8 SHA512 a738e62171e8c797ce1640456e0dc019486fa58ad347bbc6dae2b29de65a9442217052906671961369507c7e15d9d6ab545a776b309d86e41b654eaddae2f503 DIST genpatches-4.14-231.experimental.tar.xz 6088 BLAKE2B 1c75abeeb62811ede6d3b51c6a24ed898d92874a9251b7b022e6ef9cca24074b29a22b72a5557b68012e5f68025589268973d9bcae2729c68aebef78bea9078f SHA512 867c66268e0a182af0425e54d517df5305264d4c761ce1114b61dfe71f9d802bfc53d941e2f4b766f73c8278fbeb29cbe8e4c5ca2b0165bce5cb0869c6488422 DIST genpatches-4.14-231.extras.tar.xz 3340 BLAKE2B 51570d6a9b361247a5bc9518a9ee29c54b855c7fc3ff17cf3f823b6626795e7b421b2161280c730c54c1524fd1dbdb6c6bf1b328dc6ca4844674b9842f3e596b SHA512 4282d7d2d45f1eb436d29f57f8dcd42afcccc68fba56847859571b384cdb343972aa6f610f90a609edf543bf21241fec3d4e8a7847c635f1db1d39e9a67e23e1 +DIST genpatches-4.14-232.base.tar.xz 4871276 BLAKE2B 0d9110a6eb0e8b66fbced93b0a2247c61efc987d13a72d136be4a28124a8c573ff2425718d1af8dfe8eb4ffb5ee107438739e6ff4febb21187de823fed0b6fb4 SHA512 13c2fe3f012d8f06f3945f7a250b3c067889c32d43386f745f3c642d9ee88c3e7b15bd5d92d823ea7546f5d3f6e20ffe202be1f99c66378169894533163b8409 +DIST genpatches-4.14-232.experimental.tar.xz 6084 BLAKE2B b8739a3ef24628a61094771edc108a0a1858c9dc8a3e0757f11eee62a5be14b3974e7ba32d9672e4cbddaac8ef1442448aabcbf5df4ccab27059b5e2e40cf00e SHA512 bf771a2b9069fb928597c517ee92952ea8912369bf9bf4284eaf338a6c8d2e17418398faeef73574f75046b048e4f9ed8e59371fe56eb48ae6925bc7f1a98d56 +DIST genpatches-4.14-232.extras.tar.xz 3340 BLAKE2B cead12b5fc48d232dae9bfab7bcbaf1317760d618638783448531b9dcfe3d26f66e650104f2a4104dd2cc2547efbdd8dbfb46a2e9f4b652dc68f038e8bcacd03 SHA512 cbeabf270ae02ddc6eeab74796e7eecc846e78f3008a17980189f04714e6fca255aff2470015d7daf177d97bb0de3ad92248433a9198427f121ad7425f9f0081 DIST genpatches-4.19-159.base.tar.xz 4174792 BLAKE2B 1381a2531b6297e1f76af70107c08a3b7b304177b14a1407ffc41a5851a4249ec4adf5ed00539542c97a0c8dc0cffdb20c3681b9da17409cd9d4ac711b353dd8 SHA512 e75991fde39f093c77b4e7f16aca7b24be47e1e438df7a60a97e0db7aa14ae6c0ed868685da0979c10ce9064839adca84c76a6ec87c1fbe41eed7a20788ca776 DIST genpatches-4.19-159.experimental.tar.xz 6980 BLAKE2B 62605b1fe8ad86233bdfb183df2019dc4d6c74243678f5aad08167ae67b8e0dc45be7a33cae59a9c30678c986c9066722dd32ff18ee572d9ee5f7f2f51caae20 SHA512 240ecdaecca79bf417b080f6ea3dd2cad113694d2f49ae7a9910e26250f381721dcac0804b3e983272a5ea66cc1455cf94c668442e98ce5938868fea1913050e DIST genpatches-4.19-159.extras.tar.xz 3312 BLAKE2B 480dfb15464c46ff0cad7447476ec66535c6b32ea9ca822ef7f8911b4db7d389c6bb1d1b80811107afb77e290fd4c887ac1786a95729c58673180324246d655e SHA512 8d55a3f9e1516e32e95719a5c9d5c1018bbcdd8f2412b138a46da1419252d9e088d2f1071a5c44dea969bbf4d93461c58edd17ca1b9ef835addb9bd065eda259 -DIST genpatches-4.19-167.base.tar.xz 4302532 BLAKE2B f43c9e993395762203cff0846b91bf475e5d9c72dbede62a6cc6c545f5ecef8369788f0813e3eb052fe66d9adeaa62c9e7f9666e4140bc9aa54c4a364c5a18d5 SHA512 6d9dd2b1d10c2c81f495f8c3ceb3dd365b1649cc63200fa9bf407ac1afbdf8895dad0855d050384fd427132c1827c3be10697c401824460189a6ae2bb0a937cb -DIST genpatches-4.19-167.experimental.tar.xz 6972 BLAKE2B 4e70a4784b6c485517cfe2b75418ccf7df3f3d40e501ce11edd978b6c1593426b39a7a2241f50c4a7ae63158e7d939f62da57b4c18197675ae05ead5a379d87b SHA512 258bd39888c4156dab864539e7438c7abf7b4ae8113815d1b115a76d13821c3d761c5632f23f8a317bf67cd13e0ee8bb888ee94f98a7799a16484424c2c034db -DIST genpatches-4.19-167.extras.tar.xz 3316 BLAKE2B bed1495c2beb33aed0814d93a739663b35c3d7012c185ed81c0af44e2e4a8024923b4ad47228a59103e1bff397314695ed975e740f85afbd8304549234cc7de7 SHA512 53e245d970b92c01cf74f72918e386cabd1214b9531734a7656709e50ee7c900b5b428ced4085306fdae72d56eebe162b945da3e4094cd41ef2eb7daca3ed157 -DIST genpatches-4.19-168.base.tar.xz 4309240 BLAKE2B 5940bc82e8139091bf61c8062d110700a394cf3bcd212de7235e17767db47e7f6665498477c956e59c91d67160ba15d1cf5ff1a2e23c5aecb4374e1872522eb2 SHA512 4e60c57d7fb9f5e2a0396d7818521c914e8d5d24cf796f0f10e3e0bc9ab33712780d05a1c86f1e538cc08d67164ac9c5041d000108442bd22ea737dcdf8898ce -DIST genpatches-4.19-168.experimental.tar.xz 6980 BLAKE2B 47e764768bdbcfd53f6eeb0c33b50a2f2d5d83ecbb32e2ab9fc0e941bcc9dceb4dfe682d5027f83d79ba0cede9c9dcfddc3f2e763241fd8aac1ad129cd6d12fa SHA512 aa0d945be8881d2808a64077bccb4386a6945418f41375bed11bfe0bf37d7de7a67c45eaaabf957b2025bd0a10cf0680c58c745fa511e73e6e3b954ee9aa570c -DIST genpatches-4.19-168.extras.tar.xz 3316 BLAKE2B 015a2122b25ee086b371dfe7d5e5c7846c52cb2778491c79ec9b556dea0dbe317dcddc2b614c3cab92fd341e77c994fbe9ce61adaa1f4c416d44e8f09c2c1e5d SHA512 693dddac91c2300f0f27da0a686997b30350b3ddee590c2be2e9cb92e6fe14cdbf3428bdd421df84838c26f714c9a05888b097ba5380a8b8fd3f334a28d12199 -DIST genpatches-4.19-169.base.tar.xz 4312680 BLAKE2B 3f93e38654ac3afe57e8ca74e66e7f8b9730bdaf4b668c4f38a117a3dfed84fe537755f108c4e23762683a5e64b5fe8fc96a647100c9b7b6ce9909dc11b73580 SHA512 e8dc17c522d36109da6fe647965616f7c75dc964afd4f0d0be38630bd95f43dcb388ac22cf499c48a16feb755d4e9bee9bfeb9424b85b65eba10fb2fbf64cb37 -DIST genpatches-4.19-169.experimental.tar.xz 6980 BLAKE2B fd8b3a34a804ce8c1619422a347d1c8fc9118701b7e03066cbe58062da6b4dfee37067fe1f9094e77724eec2efc7cf99d08f0f327d4306fe9f387274918aeb9f SHA512 400563053492ef87e6301b771636162611285a8b44174dc84a5c988c797cf6bc4615ce5348f75487139f4c03b189bf3a8f2c0327ea81dac904bfe406b119bf61 -DIST genpatches-4.19-169.extras.tar.xz 3316 BLAKE2B 79436bc140d54d68128d2f356fcd26e136127d8e985ef4922c39834cebe1faf270342df8cb466f2af21582afa989e2ee1ca17894e6c81c233722557009ca9a9a SHA512 3444295b661f66745a9d994b17df20d14c01b7c00b9e00afbf5f7e97569ebfa5103998265426bfb3b0af815eb107beb6fa36e5726d36a65447082e20a1d5e919 -DIST genpatches-4.19-170.base.tar.xz 4322008 BLAKE2B f4502ea57b9beab77b856a94d0221d8fa8100d1b5abced54a192d78b50acee203631ee6906b07d42b615bd278055851ced8056ff8ce6b4e5afedabfcd0361c16 SHA512 3c9147279be62e673337e8767f58bba40a452f7b00e9985f061f29bc5207a712504625b54758882c30f23325f7d8100bcf18a931bd046e4fcb23dd2ded87a502 -DIST genpatches-4.19-170.experimental.tar.xz 6972 BLAKE2B 7ee5acfd2c193e5d7fd251790862fb0f9e331a90f37117f55d11c10e0eb82023581be067196ca6a3246977261edbd064210e5f486acc8cde423c011e9b4dd8d3 SHA512 8e4da47d10a58e86dd592310d420015471ab345727e2ade9bc37bf5f16a648ff0b6a58dd3aacadb2d55fc559b912eba1f94dd72f8604b888588e77ec3f502d73 -DIST genpatches-4.19-170.extras.tar.xz 3316 BLAKE2B 9710f67fbca0ad2561a40a6f3ba9b3f650c5e05e2763cc50c3ef60b5893e76901b9386e01209e25b76099accdc510c6d23cd908f59e5c9f4550cdfebbe0589d8 SHA512 907eca914fe2b381d800f1f45b342084c7277d9f5051134117971ff6d7a4ac40a054079f163bf83a1e330b4cca33fec73665beccf70303c20fc6a3c6065d5eca -DIST genpatches-4.19-171.base.tar.xz 4332136 BLAKE2B be08f1eb6edcb2f6c86c088b4585324a0b1049374d8d4783a813b25f1f845996602c016fb20e1dbe5ac222a3d4308a49fa9c9eea8524d797e0b9e29f90cb8cdc SHA512 b3f5a081b597d910970c853458ef930050704fe84b3f1bf147e30f0ab3a30240b4806f4dcff84079ef0dd25d813cbb30ed4d5c43037031421a7e8357334fc46b -DIST genpatches-4.19-171.experimental.tar.xz 6980 BLAKE2B b4f9c82e260a389065aee0c5365321dbba39b914e5e7f47aeb24cc35be91338ea3535c358a090fcdd76affd044dbfe0046ff6308876387d19592bf5a548da8db SHA512 0d1b93f7fadd9c646b2956c957db80246223b0d0d7783e8b27e29413ebcb449af23bbe96bb6387bb1ad29d8d97170a0270edf607a1b660efd3524e63b1b515c2 -DIST genpatches-4.19-171.extras.tar.xz 3316 BLAKE2B a60f4523d9ae382d99ef55e2a2f4eea7d583f187d9a4a0a8ff6cd6c6c9dce8cdb321f0f12b62195e430f353bc243dc6e2e407818493fe0400100b2ccc8786fa2 SHA512 1717a6d74da1b6a1de1a509d5710a84dd73a1fa86ddd61871f4027b2416a1b1e5226cb1d3b0b157f464c2b14865dfc97c677a3054f02f52592dc9927dfc1d305 DIST genpatches-4.19-172.base.tar.xz 4338112 BLAKE2B 9598c528008e9e827b0a03f4ff7bf406e04c17622a5704fbed8bd2b0ee774374eaff93aa6b18b507b45482f08cc49668fbb001c0a69180b6e851cc40eafd77d3 SHA512 f654e57a87cfc00dc068b1f43b47d11fd51f15c7041ffea9402a15b222f82048444ccdeb4bf19628b974b21ed8a853fec54f83cb62e51bb8e4d69172b5c599a2 DIST genpatches-4.19-172.experimental.tar.xz 6976 BLAKE2B e968e3c35ad00a07cdf6f563f159d47d70571f16acac7033a9f45d70e60abf24b5544b6f2cd35f9f7af4f0c886c1e7e7fade7d3e49068ca3db4eb5b71cf5d3b8 SHA512 714359313a32b99d13db158093571a725eaf05b985f821d049c96aac0a24af8c2600914632a2c556740adb9f0d5b667f836de8a8ba019fee6e696fc320842056 DIST genpatches-4.19-172.extras.tar.xz 3316 BLAKE2B 6bd3f8d3653722f3550a604451cd11babb18af1858deacee74a9bb6b6e99eb7c1c1ed33007fba5a599381b45a32507eb188647baa7e11374a8c02a90646367ab SHA512 7d077c8acf9e963d6605a74cabe75658b72a8ed98bc011102ac0729af4a4628790124a9d53bab5eb10b38f30fac85c8df5930a6ac4fa69766509836bd1edb96d @@ -49,21 +25,15 @@ DIST genpatches-4.19-173.extras.tar.xz 3316 BLAKE2B f3c95da98341cde3929bf471d755 DIST genpatches-4.19-174.base.tar.xz 4351748 BLAKE2B bd4838c6f6a0fa7b681d961c6d0e159f7ae2df805618b514175ec35bf634620962e74dbe3a02541c3a7b90c5d72d2b5ac21d098f6eeaffbeb41c618683bf6372 SHA512 a316e1d60668f86b40547d72aca498c9280da98490369687a1f182d957aa8997e416fcf8464bf7d569cf9c4e3c245b4257958f8623f4b6eca769271fd16eef2f DIST genpatches-4.19-174.experimental.tar.xz 6980 BLAKE2B 372def848bc5394179e6b0dcdf047ad4adeea472a094b573f8b430ce4fa0c45a015a2e423194c8c12909c83b71a80e2c4cee40eb2edb2c87f06f9662e8381301 SHA512 b06b976ecede2ff415303cba109a8cce240ba7110c2f7947f083d06d9b31ee9f28b0e7653acfa87e05579586ad073596a08b1024df65b4ec93f568da0c2485d3 DIST genpatches-4.19-174.extras.tar.xz 3312 BLAKE2B 3bffb0f36d9a383b5ef2b556fa4026c4d9046b58174f683e4c6f1e8c7f64460e8d5f0f97f8892218a6922674a31d41a2b7f04d3bb886ec4f4fa6d05d552e02f2 SHA512 178b929b5a193b9b8272c50ba9b6213cec4b73dcc7110a83231a89f778b90af098d19eba215d8b42557668f5e43c696fbb090f856c35278eaec8f804c94faa1e +DIST genpatches-4.19-175.base.tar.xz 4359896 BLAKE2B ffc8654f8834a5c561903b4703e77fde83595cb039b840f7092c13c4676ffe5dac7e53b6d0dd6a24c2c94731b0bfbb3c062baf7feab2b2fd0a86e8e26b7e9d8f SHA512 a38d029c6767731e3d32e085e5bb1f5fabf1308818d9bca798b7c4416bf9034a608d6e8f0516e916e7381bf3164e4a13d2429c4d885f62456cd013d75741e9e6 +DIST genpatches-4.19-175.experimental.tar.xz 6976 BLAKE2B 5ed6602506e84f236245a66500900f8302469f18e46b04398c422cebf9ee99baee91c49cb8d1d2467ebdec670da6820ccaacdde7651e62d9f391b87d84110950 SHA512 c0c429a33227b19f91ff986a07db7dffd06eef888391e2be98c53d60c247f43fde27a3edac8fb1635e37aa62b959ece9291823a0dc3bfccd69ce3c17bce2ffd5 +DIST genpatches-4.19-175.extras.tar.xz 3320 BLAKE2B e44b1dbf9ef89900a1a557190861513ba2ac023df3a44a6ba2e7dada82469d6ef1e95cf61ae5ee46174883257c9124d7c8abf28c01be55a54af06a2b8ceb8fe5 SHA512 56b8cafcaf18e77f198a6fa6a8701a3ba3e02bdc4f78e94402a8282ee38269a9f193cb341344666aaa474a9ca7241fd6e1c35d557bf408003c841f937229e778 +DIST genpatches-4.19-176.base.tar.xz 4369596 BLAKE2B a6f8ff5a906cdd8d969307044c0a40f1f8ccf7db15359574322bb5860e6b4aac7be783d121d779c6e5f0301b5c8ca9d5fbe420f92c90fa429ff864a8976827e7 SHA512 b610a2ca7f2f29631f04858c3ad98dc6176afbfcc271e7c62875a0c71cdccd5e3f669321a19dff7df271d9d4f510f4e4e8c916887940a9ca7cc5044aa74f5a4a +DIST genpatches-4.19-176.experimental.tar.xz 6980 BLAKE2B 86f92cde5c96fb053bb5fe826207226336ad27595477fb6d000e1a7686c868cdd6a1623763d125aac8e545bd945f7a24c7aa1002852b4c42b9a24d4267fd6ae3 SHA512 e75f382c21799a79933a5974724db8020cdc6ec915963488d0a18dbcc4cdad109f270a52d2fd3f3ab760821d11ba37fbeb18a18398db74f9acca983fcb7a2a05 +DIST genpatches-4.19-176.extras.tar.xz 3316 BLAKE2B e7cc9aca5dd8a686db5ffa43e6f903adcc94208bf2c168ef5d3fb7d31d9349e0178da73fc083e28941872892ebbe9085c670804e9c29925e656044acfbc4d758 SHA512 a34c02a3f1ab5f04e427c04d7c8e0c96217f62644e873172e9e71923caff2d43d3d6eba543a831232b1308a5e71212346dfd22457e0ead006674cbcc0083faa4 DIST genpatches-4.4-248.base.tar.xz 3950896 BLAKE2B 86c1c74e41d3b450079492d26ffb773e9c78bd69e128869ad90938adb35e00efdc55f6ae2eaf5d163fbfbc592f6556d4cabcfdb83b7c874203fa02698986632f SHA512 266467cd2a82e51ba8d388540b260e86c058de48761c083e6a6c3dd37f7e2c6b2d4a3901b030e69d0eb7a5b13b323e141764ea79a9d5637d7a3568c6672218b6 DIST genpatches-4.4-248.experimental.tar.xz 83320 BLAKE2B 1f30185954ad3247e5cded8074f4a28350116d3ce1006b717de63842d9cd5cbef8241ce29e3ec52aaeb0fcd08082502a722ad2b618a26778d2553d9999530c72 SHA512 e5b5401e6a47c34a5eb495f317f4db9aac2c43676e07798d385b947db179e41e6e462fa0ef577100ed21a8a7491e7387df77a8c1e7250ce45e887e65a9d1bcf0 DIST genpatches-4.4-248.extras.tar.xz 1788 BLAKE2B 3526b5cc83cb4c9fef68c4613d23c44acdfe84e89b46a3d50df90b91536077ce76973993eb6469947150faa2302ac1739ee9824264903a80edf8c24f763b7553 SHA512 e7e63456442b7fc51b3f3c1aec0512e0598d6e85cf5e0a2ca2c2046e86f754932900dd59b4f5510cec2a782f4c806c5b979cea8b13ae2fe455604efb478ac985 -DIST genpatches-4.4-253.base.tar.xz 3995836 BLAKE2B 018bb03a58335d66b28d1405d25c17e83a624e7a192560016ca799c616e031031464f5a58d1beb874ef54e4993814ca316b1f3cce747baad92c605906cc1cc47 SHA512 0b3f164ae34618dd3b7f800dd3ec1258de20ce2705294f86f34d2af49d3329f1d095fb027918e2530ccd06f14c0d08011afc56104db9837e65122a23d4397c21 -DIST genpatches-4.4-253.experimental.tar.xz 83260 BLAKE2B b5a198ce4b5a4803a64beba8e76227da1b11fe9b3eb289e132171c5b70eb78a845f3c915ec09f4feac66fcf7059dbf2d94f5fe6d3c91ab3d1292b5897ee15167 SHA512 367205bd834081fc5869dc38a607fc63b804c9a8d80093099753a6987ffcf0cdde16826560cc06841d4f23e03279cd1559d76a619f38b4dfbcdf4e7fc077f62f -DIST genpatches-4.4-253.extras.tar.xz 1792 BLAKE2B 38044d9cee57fa820ee618e96f99ffe6e66addc43b795e582e05a168c51fde20057930889fb317c7571b79d3a2f50de63e1169969723572707e056568848888c SHA512 7ddfa7cf2f498c9128d22c1dbd71e65e36d41738a395c83bc310e2efe547e537934b25e70609e4a119904adea09828b5b721faecaef69210e4bba09f89dc38b8 -DIST genpatches-4.4-254.base.tar.xz 4000472 BLAKE2B 544bb06a81bfea361f55aafe8d94c02724e09ba248197249a0dee8415cc60bd12ee43ea88a9d17b00dca66523af56aef8ec473631fb8c4e38f6d3d3c615c7f90 SHA512 911c851bf913dd2e35b29bd2454b8653fdc7ce20b859fb76d78d7e1b25946c5945091a52c208653982e19650c8fe58c24a62bcde64d1a6b1a4491eb1f3ad34bd -DIST genpatches-4.4-254.experimental.tar.xz 83284 BLAKE2B 7df0f3fff7bcde301f456ef547a9bb2c306c1a17ca90f700a1f4f9da490ca708a981eae8c0ed8825905eaacfda8366c423d72ee33989fe51ec288f8b6d407bd0 SHA512 81aa1792931e3fbff146f8e089721ad01e4a2696ecbcd6b8e0788607f1ff273767b25494635ac79b4d5dc8a2f4edd1103315c79526fd545e4c4f8a0585488b04 -DIST genpatches-4.4-254.extras.tar.xz 1792 BLAKE2B 981fb3ea47b9f5642552688a61efe7533453ad61d88e239e64d117850c91d4f5d6a30fd9d29db163010bac34abdfd80e457765db6c1034f85d8f5c2a202a1ff1 SHA512 9d20cb140ab7fde7410b4e908289053f88988f626c8a5a70b59d1a66b95849d07b80da9d6a5e08e5a8819a394ea61a7369a57ec3b2b382044481858f7a4e7d54 -DIST genpatches-4.4-255.base.tar.xz 4005524 BLAKE2B 9c938bf3c93fc4261723717f866a46d2ae6db068642ad510c5a3dfa3d4800b307b50586e8301bef53fe2b41b248a6ab3b6f7c72490c5ce8de05a8d7b43001135 SHA512 3b2474c3fa5a017fc68ddc32e8540b1b8d39cee68919d4d9e603ee804e8f0a4e35d22822c156fab7470fe5b0ca7367840cc4869fcdf1c400db46789187803c3a -DIST genpatches-4.4-255.experimental.tar.xz 83296 BLAKE2B 41a4d270b0a97849c792e48b6fb00e53504d42ed783fdf82e031c3dc012a3f6717a308dece8e1d8e0707ea6aa75141065c5fe2dc14cc823e8d345c69299984f8 SHA512 0ea4ac981a70e1f56eb8b59e5496e13f218a4d471a407572da50e4f015ddb7358a015c8106a9685b511da6245f70ead4be29a2aa1d339c6ff62bce9b2cbce31d -DIST genpatches-4.4-255.extras.tar.xz 1788 BLAKE2B 4bef240656562de76e2b22a5975dd3ed27dc57168eba30f78e34191ef06351cd6406a5c849b0a4f534577183d7b3945eec4dbdce3ad5a496ef7d783d1a3eb369 SHA512 56fb66fae36ac32efca12a7c28b9dbb24afc37f2ae389f4c64f107e962c005c8c8a5f7413fa87743d7a2bbaf98c0d6ab055b8038f8a4823441fa116cb40c1bd5 -DIST genpatches-4.4-256.base.tar.xz 4008644 BLAKE2B 05529f58067f723e767cc3b9d11bd64c01213febd2061d238280cdddf60776a21067595f5d4f65c0b1e742d95a847e7801e3ce5a6d19e8b14f7d77b42abaa3c4 SHA512 4e1ccfba6b7dd355fbf54eec89d59e30cd3ccbfcc9a3a507756f6d3d3fc4e90308ff9d99962097f98358a72e68dff744948438c1d9e91b7847ea961ead758890 -DIST genpatches-4.4-256.experimental.tar.xz 83268 BLAKE2B b2e6b2d97093ff14b67858e0bf175981bcefbbda59c4ecee91b45096de487be29c47b1c0d1d3283bf82740c42ae6f6c01c416c58a282bbe83527a24fd0cd3fac SHA512 0f60033d305c9c112d250fd99ba32bc148a067400fe7cbc089a90b67012f8b9d3ab62c1a49e334965790ce3144d5a0c068700bc6c839e9ca6264e4e4f8113aa7 -DIST genpatches-4.4-256.extras.tar.xz 1788 BLAKE2B 6655c4250b5d63fdb41ecc5b443df968977a6453bce5e9d98ba26ce5fae9957cd8050b3ba12cea31f20cba3b790bc2394026a42d4f72d557b463e5d87ef6a56b SHA512 b2c66d6315e8184f90dbe2461943dd70ba67cb571587f479770cfa89bbf0789c74db4c8b05fd8b794afa5c93be4ddbb1f5f4beab5034849698af48a011a862e1 DIST genpatches-4.4-257.base.tar.xz 4017812 BLAKE2B fa2338100efdf5180823e6491ff5e0fccb284c2b15e60a1991c93cd315e1fa6c8a16546f3d2fb7090b631ecc8b448ce58f43a36b6267f16d36550a33f6e063a1 SHA512 73d694b286d8bc3e3305de0f8901bd23805796a33f0df77835f6f8d0fd8d5b0b44c457cec9a5444c1df5bb37d9ecf13f167ff9263d0148fd1e3eda257abc3eb0 DIST genpatches-4.4-257.experimental.tar.xz 83332 BLAKE2B 6e11b135b7a5de7bff5681f026dc0bc981cc59a6211a91ca8b66ae6e114757522ed98a0e97ee4fc38606c42679c2728d4b027c629ca4dc2f9691c05542f31b48 SHA512 df47db5a3fc308b605f0ef47143e676f7a999e8e70623840b6a0df9ab502e931a222fad135e6c04865440a5e1ea11349b915f089b09113f2acdd06f3029a8654 DIST genpatches-4.4-257.extras.tar.xz 1788 BLAKE2B a6cd780c720bc523469c3be72ec1845fe49bd97e8f79cca3ed6e816a54f1e4d792a30a1f18f9fcf7dec70945934334cfa2880d6cee02cbcca0fc0511041d55ff SHA512 70a5f8a0ebed2a36c7b003227613f289f4c4f9d125dd3573b4815b4f48685f3236d57cc1a195aa7fbcb990583a15405820e9bcf8b2b2d46824664d3ec21c3286 @@ -73,21 +43,12 @@ DIST genpatches-4.4-258.extras.tar.xz 1788 BLAKE2B e1815cc3bafee3590b062704e3fcd DIST genpatches-4.4-259.base.tar.xz 4028152 BLAKE2B c01f5acc3523aea23b3d0d20e714db1a91b70b51b1ffe9bd57738882b28823ef8ef2fb2aa3766a050dd5efb597c1605d34be2584d83f170d4efa741ef49043c3 SHA512 8dc0bed820643799007068a1a00287c7cd55cc0df1c2b83a945c1ae7cb75fdbbf41a7f6df1cd3853079746dbd2b7e6c9ab21a531457ae1f71a4b03aafc8c23a5 DIST genpatches-4.4-259.experimental.tar.xz 83312 BLAKE2B 998cc7fbe38a981251691026abba9fdcb17bdd388ed92d7aa61745a772c3072ad630be7e8cebda4ca1c64642e94ca6ba5e46452641f306c65a04908f58c47659 SHA512 9944a0bc502db83edd04c683ebcd15552f02edbe34e19b5687b04830786f2dcc7baaaa2b613bbcb568cca6abcee73da830e1bc4bcb9248aae80bfe15eda0222c DIST genpatches-4.4-259.extras.tar.xz 1788 BLAKE2B 4512f1496b02147d6237c970b9330af46511bab342645467687cd7f7d0417ba2373a1ae07361e4b0020caa878665f3c76a3763cd92edc07d3d677661a50226e7 SHA512 464129ea698d8515a6d3d2cd8603adf0b3c9bc8a3c5436c10ce1e43ffc7ca4b8ac1def12d20356705707cf3d25d10c79ff714ecea842ce1fe4f439cdbe3427fc +DIST genpatches-4.4-260.base.tar.xz 4037716 BLAKE2B d2ce0f0711f27b2ac8f88585f1b2013b290c511d7a52e384f47ef3f0d60432c3e877cb84ec91ea31ddafdc9cf1eacc99c1ee836878c2e9e45d87dbc2056d9db3 SHA512 5f8136861ab7eed3c46472af1f090528331b0628bf3061c7e9b022a87102c34577fe34e0f8ad0f1df49438fac3db03b6e7f7c2b2d9f96e5c558b5b4a350fccfc +DIST genpatches-4.4-260.experimental.tar.xz 83304 BLAKE2B ab611f5b88f4526409f4bf5b50a2c9ebac10d986ac36a75decc15386bdf0f2dc20d5a1efc85563eec4e820a6441fe8f8404f02a727f19f064dee8c42e3d8f0f0 SHA512 c07e67534af3549b2e81b378cb4e6ef22c87d527808b846038d7c45df73a5d8ebcaa3eb9539a9432e6578d94273798ed6f51d6d711d16c8a3f3a6cb73ac50385 +DIST genpatches-4.4-260.extras.tar.xz 1788 BLAKE2B 0ffa226d157811b6870f68d610f25feb71e82472f692cec3420c896bb59b9c33879a31d0e1e898d9e51f5bda2d5389706b931e01ebc847c932095e4325dfadc5 SHA512 1ba0e11603bd0d1c24caec3a2e0f2c51c79ce5f6052bdba9ce79ef86d40150fd87d0e0587c59738e3c3965d22e031a5de4791e1ac3199849bac4189391e7ebae DIST genpatches-4.9-250.base.tar.xz 4423652 BLAKE2B 028223b668bc00d1bfbd4bcdd5dd201f9fab0c9a4ce68f5e107c1de83320c88865826eca0f38b5aaf25c96e2d66a76f0d305b73bd659197898818515275d48f5 SHA512 f10dc4626b1863177d1dbc5e1283c8848b84e6ab10b3208291a0679a3023c5f7d34cfbcc6091f7fcdb71e34f02afba3e7685e24b1f38730c88197c621e41fe08 DIST genpatches-4.9-250.experimental.tar.xz 106372 BLAKE2B 409a0fdfc2246e57f461abfea86f76694ee835215e0ed816e1c445c2e5bb3439ccd47414315f81e9cc791f7206b12ce45c9f46892e9152341194e15d0a44a090 SHA512 63f8d3e6dd777fbb8ed0dad1b67e0405926fdb0c1e40d3c9bae63494de87a3cdba37e41f20cbd7ed109eba6a933125bc6354814f5539c20c377be449cfac3b48 DIST genpatches-4.9-250.extras.tar.xz 3340 BLAKE2B 14cb6c6993c772cc8fd2a4a63f7fce94d850a926c74ac954aebf66e3bbb5db1c20001c264056a8f49561d21e754048963464226d56a0c10eb03cb59384420487 SHA512 a1eac658ade3bc0ecd6c98d1e0fc82f006e75ad4147ba0f2facc58e647bef731098527ff77d1d817f7605c0acdf3dd3f536464953fa2af27c32eba2863065db5 -DIST genpatches-4.9-255.base.tar.xz 4486212 BLAKE2B 78f14a525a2bafa11408ae34fd30af4c93459875e41905070133d413377247a2405f5c83c04fdbe18f5044a6f2b450a8cfbecc0dfd9496bd26f2b8b350cb4d38 SHA512 a235dedd73c6102dbe6fcd2c6dd1737647de991eed2c92a385c3b79bc6719e0078219ed04403b09d36d3152058210e2a1209f9c1f856599aa616f0e846ea99fa -DIST genpatches-4.9-255.experimental.tar.xz 106392 BLAKE2B 96ea1a34e5edf9866c47cb9dd190442062ce94cd2cd0723e37a746b10aff6143d88e6a8afb4b8f458f92a03f20f94ce98f4fdd2557dce76c5a1af5b0da9c3e99 SHA512 86f1b6960489e3d7977f79d8c826441a81587d21f3534383d0e6cabe6e1ec8fd6ed0449dc9b58f60e74b427179bc139983699be4b3df7deb7dc44c1adcb18de6 -DIST genpatches-4.9-255.extras.tar.xz 3336 BLAKE2B 896f9f51ba73a601c6d2b7c16398c9c475147b03712429223d4998f36dddcc24f06cd6903f1a469ed9092b99cc1dc00a5b5ca611931816b838aa33f913a7cbe6 SHA512 dd99c9e2e5d9f6c4b17d395223d395da1688e62afa021f7c5ce0959011dbbc7bb71a8ca5f3c8766568da73fd5a82371554ab92277d79baa0454b1d069ad50c7d -DIST genpatches-4.9-256.base.tar.xz 4492036 BLAKE2B 651238a0ab334f295e5bbc80b306529b4d0e90294e673376a52ad3ee6d0ea391440c4d22d71935c6d19a861e7d7b1792a6e4a96a0f906ae4eda566d8765fc9d2 SHA512 acbc6bdf424514821a695118492bd9a5fa2accae7ef387acf50363d56763f1e14cd4ab3427450bed804ad86a15b3412f6615a7f215410cdcd67bcd00beb91719 -DIST genpatches-4.9-256.experimental.tar.xz 106372 BLAKE2B e0de68aa4f0e98f2ac59b4cb379e737eaa8c6055673dfcc1f197b2ca30fbda257b035adfe27cddac5d8c57b0f42c46a9166b4c4eb8c0305b86212d253ee0d223 SHA512 c76f7c490a8f97c312d09a480adebe049c8553fa43b26ae1508bb1c491d507cd2741b7a590c90a6f11f1536523719c8a6c0a7c2d4fc60d647779a64d3db54542 -DIST genpatches-4.9-256.extras.tar.xz 3336 BLAKE2B d760dd5d8b5985fb0d26b4ebc3b7f98f16e876ec1bee39fe207d5dc4ca6d8750a9d6e5626c3f0ed9305955b16c5b78c610ea2120d5b742a73b9849196b64090c SHA512 c96add4e4b9285844fe3b7a8cd4cd9b59f07326699e84a5d3c9df19e023f0bc3cd156d8448d233743f57f851a7a1bde4855e8cc275df41131e402baf22903f4b -DIST genpatches-4.9-257.base.tar.xz 4497684 BLAKE2B c18c0545a739235dbc4e31714b820b6131ebc1bf2db05956d41210af724799f1d0ee8daa4e3acfe5a3378f9ebea017403e33ae86521243f54abee054bf01b75e SHA512 76b34da6c80be68bc3626800126797b09d6ae2272abe2687f8f30c87d9fc83e7739e8b664cd2304f89f8bc4d18fb72fb4db5a79b38ec75613fdd367f6ebab2e8 -DIST genpatches-4.9-257.experimental.tar.xz 106376 BLAKE2B a2ea68bb783a4e8b63faa6cc4e5c67179748202a680e28c47287e80a9476db4b3094dea772a3252ab5939a3168687ac782a84a8d57840758fc58b75ed206c256 SHA512 542a0a8d62e26c8852a56b32c6e949c38b25a93ddb7f968f4ee79c5e4abd28d6ecbcab0341da89d988657dce8f9f526710063daac0306abff8eebdee9a8806ee -DIST genpatches-4.9-257.extras.tar.xz 3340 BLAKE2B 81e5d485d49dec56444164cecdc5fd2b2449e140366871a488bc944c216eae5aac720a311609a63c91bd7f861515acb468bafd74e217269221bf403e01260e3c SHA512 3941a439ddb67ed6e824fa60da0cf4568b8d01511ec3fa3d12e80fb9be5c33e1087d0b3ba0a8e39cf92e512dbee6b1f5d51e402a86f826b0956d8acf0c0b6b48 -DIST genpatches-4.9-258.base.tar.xz 4502052 BLAKE2B d91fc14684832f56dbdba84a6ba9052f6529bc8598b87b7eecd71387d85197f8e779074a66b7da475cbce58d43456d83f98ec9527aafb4f38255839e1db8fde6 SHA512 3556f603f941d64365ea0da1e4c76675c0d44bf13bbebf0f2345be36abd761b8477588bce9bb3060d44a4949ba94811bbcabe9a2686ac94956ed4553bb4d1fb1 -DIST genpatches-4.9-258.experimental.tar.xz 106408 BLAKE2B 70b721d56490d11d4b869141ca2635a2c304bc4967c1f7bf7a436c8b1d45a373768d6763661975fef24788683cd5d6c33b48dab31162441997ab11132d7709fb SHA512 c2596e0f051c0f6ceab3564342ae862703bf6c5498aed6e8bf467ea6ac297deba394b38fbad5b504fd7cd0673d2d80578026415a63c40f698a2444f87b6c3b6d -DIST genpatches-4.9-258.extras.tar.xz 3340 BLAKE2B 8b242afbed3d5b2e0b2bc1d2790c81393048c94b3457dff981f64562978f3e1d19a9e3eff243c8ed480be5f3b47acc2f437b326cff401f92824ea8a8d8a636b2 SHA512 37bd31f746d9863ef382383238dd1b164eb718e132227df54d0a7bf013a92be261d467c7cdc505faca5af9e9fe7faaee98ff6b0e3375cafb936eb9b0d35e4aa0 DIST genpatches-4.9-259.base.tar.xz 4511348 BLAKE2B a2ec1e9d0020098f75f3756cac378608654c13ae8ce97bdb1f9b8909d527a8a8e1deaeb512a6333a8597b049373332463180c8ae8d6a9a4f0946965e43f560cf SHA512 3b2636e0c8a8535759af0678e04dafdc8bb764b948145ed00ca7c4848a53ab5b7dd1aa4efb668a2539ea4d8dfedcd24c5dd02a9590ae99907b5a8a918644f22e DIST genpatches-4.9-259.experimental.tar.xz 106368 BLAKE2B f3ea97ede99e5661c31a623d65f9546c9f63e27857a2883f81c21e9abc916c1111ddb4cfaee101266797edbf4c11ef60118df54102413facbf469d50801fd8f5 SHA512 f32940476b3f4996a67b8c646c95a882d325ca54fe0e67208ca47a89b93a803f3a7c5b3f030c01f510125fac5632aeb6a37ab1b28f6451aefca3749ff2f9d382 DIST genpatches-4.9-259.extras.tar.xz 3340 BLAKE2B 757e880e6c4cbde23208c1d720d13ba46ebc050634a15d9146f80f066f320238e65aa37ff836dcba21ff3562d63432c8cbde3661c63730b22fcdf189aa4cab73 SHA512 fcd1aace4eb35aee67a49a0128c165bfd36a7a8599ec99d0506e199f8828647938cf066bd535dbe72aca07d4870fbd70ff5d5d676c402f7a5486e36a9083ba61 @@ -97,54 +58,51 @@ DIST genpatches-4.9-260.extras.tar.xz 3340 BLAKE2B a382bbb0cffe55cc8b07a8e39e8e3 DIST genpatches-4.9-261.base.tar.xz 4523340 BLAKE2B db59ac0593896867e8499c2f261cf86c51dad7072e4ede8d36f112f3f7571aa9e0e7f4da6de03b2222af4c2e6aa6464426c16dc1ee46629808fb5835865c4218 SHA512 a98c3891178a831ab7cfb2d2185d6dc5439a958ec7331f2a42cda0d59a9b1b19a04537271016c1183a5c69db1601462641bf2d90dcffbcbc5632c79cdbd23a07 DIST genpatches-4.9-261.experimental.tar.xz 106412 BLAKE2B ef9d97961ee9d92a73d026d6663827d8c1fcd4f6e5c5b88011d5a2648e0e9c2041089d443d5b5ffbef47ef5fcb21c79373293d5fe074d2ca5622cc7a4293960e SHA512 a9eabf021afddc52f08123a7fee8566bd102f5ce4dd484301c4626c8a97c514fb015ccd814441039e96e7415669d88333c82aa4415b397dcf9adf4978824e232 DIST genpatches-4.9-261.extras.tar.xz 3340 BLAKE2B 832c4297efd20a6699892a938867cd47c34fbcb77e1a993092ca4dca4d9113372b2362059295f0419db923da953713f7987e90bcff5c2771593166f77eaf1688 SHA512 950dad68d92c802fd844853cf0136db90b46dfff2ef26eac633b80f9a36610c03b9ea0dbbf20f1af80c43d1def26ee7492d040072c8c799ac22c9487cefade16 -DIST genpatches-5.10-10.base.tar.xz 303380 BLAKE2B 61d1378cbde5f4df5ee41d2a3391705279e647410125350a2329c6448357617cc93e1acb7f8af4cb43869ff11b6759caa3652242b52feeb8ce2aa2c36c26260a SHA512 9d9bd200682a6cd92e067024e42bdb80347e7083a698d2aa135de34998a80454130ac82ab49018e538197d35f48fdfb0e60827a219e2d6844e221450b86b9ada -DIST genpatches-5.10-10.experimental.tar.xz 17524 BLAKE2B e0d44619d202267e4d999b0066e1475661534ca0e0a4b50bab7f3cfc7959210b6830b13e03b534553be1f80adb4e5f53c0bc7bfe181839982821670be8827176 SHA512 61114072025d7a3af31a07f7000b125c410c3431f88cf43f92244dd9af4d33d090bcce7a675df220a3215b6e68e219ed8a186f49b4e9caf49717cdf67c100cc8 -DIST genpatches-5.10-10.extras.tar.xz 1768 BLAKE2B cabeb1ebfbd545382a8bd7fe89ca78d58665848b86a5b25519c2d018720d04253847824d4059308b80edfe137383d26c89491c15be8efe86b95dcc184d3f35e0 SHA512 1e7c37441d3324c961d8d55eda3e43afed64cdbb45f2080673ab888b65b3b93c5f74495d8a3a53197b17f9d07f01cfc84a0b1719e5f3cd93652a512b9be536e4 -DIST genpatches-5.10-11.base.tar.xz 343372 BLAKE2B d844a4ce292477da26bc02743916143cd6851b2ba85229ed37361213580b47b5386f260bde7cb77eb5842f3fd1022b6af64d47dcc3fcf2161be8157380e082bd SHA512 069efa3d348d8a7601c6bf37ec92e3efa692abe4a7ca5dc4bfe30fb76f1b7fe8daf1a0f237d60dcf66a0815e909ac77cb1cc189d46f6fb4884a260f30a4af48b -DIST genpatches-5.10-11.experimental.tar.xz 17520 BLAKE2B 657af869b0c897695834caf87dd99ff4b95358a081b08dba7b3c4c7dcd61f6d1f7fb9038e4ff093bfa26373dfbc81cfb69a674752d067acc043dea05d3d8b820 SHA512 57ac770e33f1f56f66daa1a6c1d2b8fb6104642d3ab21abacfca8bdb92c945d2aea64a3d383d72a19813621ea086e6c0f1b3aae4b918a9d9f1d21581a4fcc7e2 -DIST genpatches-5.10-11.extras.tar.xz 1772 BLAKE2B 8d4c4b94e9bd7c585f56038900256b3ec1ae721b4ed7adb326f393094e5c8960575efdbe2cc14cd219ae0a69cdde5c626d6983741e3f13a39bed3e85f3eb7060 SHA512 90ce771ad84ffbeaeaff6a2827577fc9c9113930dc4fd394300e1a971cc205a1f4805404e1b356dc36b373bfcd9daa95de7a364144f0fbeb0f923209946635fe -DIST genpatches-5.10-12.base.tar.xz 354672 BLAKE2B 4c92a3c4d144e7abb130371a5d12e839d280789b2c44e97fced3a35d25fcc9b084c3e3e8832fc7670a4811da7026963a1c498a0cb2c44cd325ab13aa62a3d142 SHA512 7ee954e44305b4276717aa4a1198ea036fdd1f18e17c95fb0c5e8070acf390c1644dd0499d42ed1464fa7d9cef8d90abbeb6d0e0448c2fefd5a655834a5afa5b -DIST genpatches-5.10-12.experimental.tar.xz 17520 BLAKE2B a67d4e2049278f677004813fc1cc144e4e84ae58e6a52bc41534a7794a2a52bbffcaefd91665a6c91cdf47c445971e756063833792c0fcaaf6516c61c3f1b93b SHA512 8b79c3056dc5015bb7219d7eefc13ebdea1a70f8d970f16a5eaa3b32d63ac25575fdadc9da627be92f457f23824e0a2be8560a8dd1bb69cca692c4f69be10d84 -DIST genpatches-5.10-12.extras.tar.xz 1772 BLAKE2B c219ce68835104664a93e78e57c5bce67a3d654666504ae38fc5058d6f8df67c9e37941f549d047b446061f54928230a384d813b4bde2508323facef6502bc16 SHA512 3b2b6ba233226f9c0d54d1dbcbd36133429dba1e0bc7a355fb0794389fd729e8ebcfd1789c4b79529ca4bf48dc50d7b07c1e167ff19d837d67296f36705e7db3 -DIST genpatches-5.10-13.base.tar.xz 407940 BLAKE2B 21566164ea821e5ee95e4b4583395625384347d0e8440b29fa71f4b63365c5481dbb683c84818a5379242a25a59fa85c3caf420be3e6cb8553a43834dcdbfb94 SHA512 0f4e5aa39cc8dd6f2cd62fe5293de1d9fa5a0f6e0dd6da9af52ad68ee8318f995d9095df65b93d6e15994227feb87b5bbcf0403ebe774141045b05bf239dab86 -DIST genpatches-5.10-13.experimental.tar.xz 17520 BLAKE2B 0f3241b311dd4c58e707f313395b56030a1c4f5b5912daef903de47172757167c53dad2236cbc69598d9549fc369d6575508e7a0553d1ed3d9581b5ddd020007 SHA512 383cbe2fad5a4453ff603e41f10fd7ba4b68b7529e92eebb7977888d9d822133815f1bcba7ae5902f7ff70cdc2997e3a1a023f07847fe6604ee386ef0b09602f -DIST genpatches-5.10-13.extras.tar.xz 1772 BLAKE2B 29357a93bb6b4e34937e6655bb8cecc4f57edea8a7e7a903dd8196c6f075b27e2b1176a56a998777c850994c5131a2a57266a7fc579a25fc43db9c9aac4dd80b SHA512 e9ed41cc3b81ae7e76fce6bd6df271eb354110252da85e7e90c4d08816babd1262c5c8fbb62fe56dff1fde712abc35ee40c67f9f04e3541920eee78b32074928 -DIST genpatches-5.10-14.base.tar.xz 416468 BLAKE2B cfde628c2594a568c8f699ffb63bb1bfa5054fb810a0baf8cc08c87886d49a5e33725be6a6eb03ed0f8fa40521b9591ae0ac1253708a3ae72556e0cff7efe17c SHA512 84b815aad491aab1592c253da7c37d307b102fda9d08c741cbe5df9c5bd636a83eb8af0e96faf6b54c13bad77068d3ca1f632ab4c68211bbdfb8a9c1d233f06a -DIST genpatches-5.10-14.experimental.tar.xz 17524 BLAKE2B f81ff677340b959011dd1895f28d12a084ce9817e8e0e3fb1a7bf93d8cb900a8cc5557ee3cd18da6c4d81b5394c57ef94508d3529d10a37cca9f72c04ed8fdbe SHA512 bb7310d697c9c1f1d862b56c0b13b7d835ba8311fc628a2f5829d07a4a651696bfa6be6de0e268973ea59e19fcf99de4bbb175d519681d0113fd4f8ba0d41aa5 -DIST genpatches-5.10-14.extras.tar.xz 1772 BLAKE2B 9694bc87e97e7899f2d47199c42082a666e775f35a49a3efb20f8b15cf35345b0905b5d36bd3845e4b62e0ae49260a7fb381f26c6cdcfeb20c3eda5672e81e29 SHA512 be9fbe10adae2acb813abf94f7008620ee9c5f1ca28053e4c387ecb814e3fa6b0e08b6c0404f1585049ceba4ed419dbcd524f9ce69f25dc12006b20d5db3dfc5 -DIST genpatches-5.10-15.base.tar.xz 455860 BLAKE2B cc02492f8f33e3b644df293231e9e6718007b4556f7e056256eb6040e0adaee076f1b25dd8086097d2ae1c50f1169488c2188e45756d0aa47e0b0d34f132715e SHA512 983f45356831d74a6b5001bfc68f4252d687f307cfc8ad2925c3a844f5e9c13e6407f6c591b49028d9cee599106b771078fdfe57137801ba0096552b99126666 -DIST genpatches-5.10-15.experimental.tar.xz 17516 BLAKE2B c4b3fa7014724fda6be3e7f530f0f78a9caa3cb531469b11ca5cd4962b545c6a9d7bb5e6b8db35d98c2f84321808ecad5ba307effde8f6beb3c0761647a94d9e SHA512 3a0ebd497561682e4bb23ca70737f67b73b59d5053284b1df17ca602b2be9fc71718b59b86774479e1c455df86ae240ac5abb2c847db20e05e4e4e503ef9d5af -DIST genpatches-5.10-15.extras.tar.xz 1772 BLAKE2B b7cefe073d4c1c6b6f5b57e79faa95baadea2a79be973524876941275be05b60be2008ddcadb02ffab605d47dec4fa325609e70b58d7c59aba83d2075d7c3766 SHA512 ab18ecf108271a4a132ca5983a47985dd462e5b312bf0cbc356340713738c40888b59fe4fb2597c218b41098d6496594f2ad98638b6b14c435ba271b8f4b2882 +DIST genpatches-4.9-262.base.tar.xz 4538164 BLAKE2B fcafb64156ae72f214414128b5a915d4dddb037907d48b954df0235b235ba39d4fe45ef9b30211fa267b722f4b7970f7c617747ddf5eef3d9ddccb0825d5c73a SHA512 725ad4ff484578dff30748ab264f37368a05a9999243116200a828b5592eed3fc8a8bac670ac70d94cb6caadd830f6c90e8c349a05f81bb3e4369c5cb892447a +DIST genpatches-4.9-262.experimental.tar.xz 106396 BLAKE2B dc7f47f983fb5365dbb6974fac91508af8150f237d7686f7f6d705d39e07f3036e3929f0a8032acf95c47add09239c32c627d4da1ed1f5cc27bb5e80bdd8b35f SHA512 17848ce6c9a6333f41ed878a39d33c55f98ce0ff628b2d4074866753b2ba44afd27af1d79a52b3c11c50964c565cc5f8376d6019ca9996b29b128e2cdd8386c7 +DIST genpatches-4.9-262.extras.tar.xz 3340 BLAKE2B a53ca6066598904e4ea023ad132905d594b30af5a1a8478e4ef2d942b6139770eb6724808a0655a87e5bb1465345a5a47e7c691730488d8f19ef174817986255 SHA512 10c6c315c27919f0eb0aff5504ec73064b57feaef7621c2545849ae16ee8f3de139f53757ed4f3997fad033889ba3e27a1bdebaa6e422db5f6530908deb26022 DIST genpatches-5.10-16.base.tar.xz 468704 BLAKE2B b7476d5db21c56f2b0e3082e47d643b12b163277e84aecd4b7df75e97f6b703ce8fbdea29aee0a7150f0f193a35ecd896766e9e6bef8dc47a4dac941f83b7f02 SHA512 9623b5fb47de8a93d036e301220031d5b6508e07ce87002193a5d52a34902a486811f133419c84c35cfd7f7bb6076fb5be87992d6934ed57b830d4c7542313df DIST genpatches-5.10-16.experimental.tar.xz 17528 BLAKE2B d70fc8326e57ce729c7a097f64cf8e049821034498644cc9f6246b93c1184b9fb3700c7802e28dcb353c7db8c399f916e7f4f99f5d2bca153005223bf9aacc78 SHA512 cec35f59ede000682ef5cac7a5382c6de7444bc6c78c84b54eb5e5b10c3b06afbe00b4b86cf986f635e0842b6e767c3728651525b1deeb294228044747d57001 DIST genpatches-5.10-16.extras.tar.xz 1772 BLAKE2B 5652ee641cc180d14e7a28d3dabecc46430bbe8daa5d5e0cba3090d8a2e28ee56b92073efa996bd9ec598897045c29f1a8c3fdb28f69d7ef94422d31275d7fc0 SHA512 90d245b44e33ca5f8356dac3d3ddf0d736530384ffc232fb230b88e799b362c8cf9b4a147f7b9fc5c32aaccf18cec4ebfa7b8c80bc530ac300b5444fb9263021 DIST genpatches-5.10-17.base.tar.xz 502160 BLAKE2B e243f962bdb26797424cbf27eb64e37cc42a5d7297d8eac4dfdff556f641aa0d34461b9845df3c203dfc0df462e130089a83c1cb8fae4774df5e99cee27ed67f SHA512 d573c4f168fc65cacd01931d0cb52636ee4c739ec7a285f069cf8c0e487f606e2cab5a9524dbc020b830ede4a5660e2204a49d27596fc661ca96f3db26856c31 DIST genpatches-5.10-17.experimental.tar.xz 17532 BLAKE2B f808e5529fb6535c78ea10222faf02a3d09661546565f61a2456530291d635073ece4db20c800f97132c29403d17e6e6699cfc424e4f85d9b08c86c6f3e562de SHA512 3c830f9364954713e4598fb19336bd6636a3bb2f28de2b9e2ed37bb8d24df129a77be1dedfb7272d422f5f2470885eed7fa629f059dff35aa19f9d512eb830f4 DIST genpatches-5.10-17.extras.tar.xz 1772 BLAKE2B 14f5f5b8a2a70190f80376f20a83c2f7a70ca31b2a956c2cfd84fb2999436bc3cfad925ce9744d333c896f520df6dec5337ad820340d9b4dd007d91abc95b0c4 SHA512 2bf9b8444f8d53937a24e1d0304236f04ca220eb1a2bf4d4c47d7655149d752948a0050684d1d1f18065226e7b50501b3182b264b2ff009b6f9e45e6886037ae +DIST genpatches-5.10-18.base.tar.xz 515540 BLAKE2B 245520300cb9ea1a0803dd4497b3f98bad3ddd29851f8f1273e3b51a3479c03a4915f601f1df216593a36b6f7593ba852dbbb7f106a40260c14b4590201b8fb9 SHA512 baa107fdd1c893ba977391cc429542b90de96d0cf4e6a671e392ef8e0f795d5ce1e4d2e74c214a907c9bf35fbdcfcec220785a4e66322b6191f097eabadeb567 +DIST genpatches-5.10-18.experimental.tar.xz 17520 BLAKE2B 73543b9a749d3c675e0d625a32167cada138e6481fd1c66529a35a193e61fecd1cd1183c33cdecc4023abfc96052e70a90735ecb7bc6b2129445ff9d4b42b7c7 SHA512 e68fc65e40f87be37a5637c25f34710ae5f9ead0151e7435d943882e8e262bf7d835602d55153372cba8535945889f7ff44dd52450e8f5db4ac5161f9ae6db94 +DIST genpatches-5.10-18.extras.tar.xz 1772 BLAKE2B e4c9b0ccfcdade38239cbf0e8db14e46b394b3da9a08c2538f81c602e9c8f52ffaeac0b441831ac771e6a19314a8a7d61b5411e1762c7705c555bea5a478dd68 SHA512 59290f7ea30bebb5137829a1d69b22b2170ff06a794e06b334f03312174e31ed9be9c8372396b482a936283a79e557f813755b5fed77a5485b2144d1d4b0e52a +DIST genpatches-5.10-19.base.tar.xz 543060 BLAKE2B 9219d5463c51bc574984ab37795a2150deaecf861c0b2ec3c7c91eebacbd6d5e045da40acb09ac01a56e33e5329401e80d8804d1227869d5a856e8c11e2da70d SHA512 795e38b25e6c11a936e8366a3081a5f9d170bdb807296e3c0c58545b43b937ecd47e4a66fff521a0a554ff4142aaf4b4b5543427437f1458f672e57016de1f58 +DIST genpatches-5.10-19.experimental.tar.xz 17520 BLAKE2B 447e90a11bb69a5dd41ee28fa28aaa5bf9e80e9b880b05aeb5f217913e8279ab670eb3a79bb9ad01578bd7f8541c4d89353f368ad8cb6f72286d9879c4091bb9 SHA512 8299745ceb5f888da5560b22ed013d73f339f52bf479f646602235d248b9a869b0b6643e758012602cf43dbe0f8bfdc854a9b3a0888047d72f63437933bf3964 +DIST genpatches-5.10-19.extras.tar.xz 1768 BLAKE2B 8579ab3ab97f6bc906a8e16d90e8bfde74bc6782323a0defc86e0099593431d54bc4457c2cf3bc64bcc623bfde74ba6387ca33af58e367062cc23b78057d0ec8 SHA512 7b658d488dfe372a5cd799042c9e6227fa35bf8cbd56ef505bf25344b052c2fa2db137bfb315d9a65b844c475a052e8845ba9d3b30e57fc6417aaab7c3886176 +DIST genpatches-5.10-21.base.tar.xz 551256 BLAKE2B fc2db45cc49ae771f3c87cd97ba3643c6ae35ebee7104a3e6cea50b5fa444871f069480c73e63ad5ca41903f4c180be34e905cd7701dbf3f49590cd98d255873 SHA512 c176101a167fec0df6dd60a366daa0d5b2ca96b2610ea3de8ba0bd5887037ddb989eed5febdd40ec2fbfc1473837160713b331e37c370c992c95b3db9bfddfd9 +DIST genpatches-5.10-21.experimental.tar.xz 17820 BLAKE2B a33240a66d452b4409611cf6ab508099dc82f0e9bee456312b25d75aa584ab78bdf53c189d4bd522e57e9211fa77b2c65a8d96de8644d45ca8371a7f9991c207 SHA512 b8add41cf51c7e2802d9073db4e3240fb91a67edffd5d5eff75963d3861f40584df5a970bde8c3fa807696984f209fb9d7bf7c62f62886ca44e2d648b0637758 +DIST genpatches-5.10-21.extras.tar.xz 1768 BLAKE2B e69295002cda9c81df01d0e20a6ae691f3d584dc91ae7bfe3cae777fae430829b6b4450c5f38f91a2aa42fcd9b6adfb89bc85642f30e8caf7cb34cd301f5261e SHA512 1bfce3155025596db1c1e90c4119812a83d1574519d16805574c84e0b8f5936b5e3a2e5400e92b59c2844b903b9517eb2b9d220054ebd3912af23a4b6914db7f +DIST genpatches-5.10-22.base.tar.xz 554876 BLAKE2B 18d2a41fea4a8a95983a71185248f9fd27d2f4e8863419eaae66cf826ecd74218e0563804262368f3d23bee1f835b18869644af734f0baa8d1266a37ff495061 SHA512 7fca3a5fcd35425b0d6aa37cd0eb1146c6fec8ae5f4a462f058180057e956a4316a26a0c0600780014ffe2f632cf64f135f8d0b337ca6642a949c3654783a4c0 +DIST genpatches-5.10-22.experimental.tar.xz 17824 BLAKE2B a05cdc918c9f37fd78f2a61e02ccaf22efc31a72131db6c4b4d3ae1edc1d49c1cb58917b77a3a7a5c6b866616980a8247bef3c80a35103b2a044ff1e86daa741 SHA512 6d0b9f07095e219ddf4bb2e590ac50bd28494c3ec42f58318f889856e6110e6cf9a20ecdde19699a3303867287edef60d448f426d8389a58117fa97435e2005a +DIST genpatches-5.10-22.extras.tar.xz 1772 BLAKE2B 3a72d1838aca6ca79985e06d9efc44a10bc3e766431c2ebca64b773c96be52cf27f121331585030e334d2eb7d1415deb34f42c265619b16186fb406baa12bd23 SHA512 81559580dda2d4ecbe693eb25d9d537f0d3dc3a01c1a863f17eff3b0e890a2850bdbb7ed5e856bf6b9c7dde944dd771710a8b64812391b5a3c214cc0e2c8538f +DIST genpatches-5.11-1.base.tar.xz 3440 BLAKE2B eb1e9a9f2060023cb410bf3db8c4f4fe283eff47f545a434dfc1edb98aa513940f30a2a88566422192b79f7ab36c607b9bc63253c067070d9a479d6318fd34b3 SHA512 a862fe33272bb6b0e4095c862c74361f015fc57316b9dbbdf2782f2e57c131fbe7fe9b9ba81c3d5a7d71788f2d56abdbd28f1c7571973c3f378cd05199c0421f +DIST genpatches-5.11-1.experimental.tar.xz 6096 BLAKE2B be00b2b75d44ebdd7c69e03b7b6488e5689f1417d2a101be806446fd290575813f246c209cf3be3b981cbb22913ce67a5b0703806b7905f8eb7fac835e0093f7 SHA512 3ddd49fe67cacf45335010e8f1fdaa0c01eeeb025ef3f73153055319b5e53b6222467f8281bfb2ceb89eeff8421a57109aada0f1b9bc37b8039c37aa1b227382 +DIST genpatches-5.11-1.extras.tar.xz 1772 BLAKE2B e6f8eae67db54099424f33e17bbfa66d36ae44c98d5f58969634a709a4b949a675a7ec1053eab4db4f745513d9730b68439ecf888e92f0fc9ef369822b39a388 SHA512 cf9d0ee27618b1b49322cefda8d85f66fd94820b9902948c8dd9a33d4e14acf511e7aabf611df5e070a4011e06d80164a512d124f5686b5b16fd81409098d8eb +DIST genpatches-5.11-2.base.tar.xz 7488 BLAKE2B 380a7f62e8a65fdaccc89df23b67a0d5dc95baee09a8e83d4ec249a920f60b3e5834afaaa870b3ffb89f10c55f8958a5458b9d0fe8968e2990bc8c710316e3a1 SHA512 b025e4a40fe3e7b568f8007a8047c7e85bd66cad3617b5bc7e3420f92a71083b1b1ca3c71170a24865c40b721b0a3ad5cd0db1441a4641f0057b59ce9dcd58c5 +DIST genpatches-5.11-2.experimental.tar.xz 6096 BLAKE2B 383a1c5d8464dc9165374a01889071132f3c110d92c371b04a2c70a025136e3002c3a4f739baffbe41a8e894c4056f317c1f9915a0cf120040af000f9b89cf2b SHA512 65040c1d78b89b47a0440f1e14d35a9889ea429bf2a22bad110126f317c2d444a5c4e8cfac9ec2b0a5b6b43bad0513cb370b32ad67a05485e18ad1f38b96d3f4 +DIST genpatches-5.11-2.extras.tar.xz 1772 BLAKE2B cf53815e6d8ff17ab8d8877a6e4ac0fb75c36905e84a6343367bdc81169cf30183b103de00390e5c73f911730d86305acbc1ea51f88c23cffdbf83347d9fbd79 SHA512 010ccddf99b02e03bef2204a4ce9c094c56e31d79fc6e5fb2f63711fb66bcda063b0fa4ff198a0dce7885cb07e6ff85dc6f89739b2fe4f2b8fb3e5ee0f615007 +DIST genpatches-5.11-3.base.tar.xz 11280 BLAKE2B 83a975b07b3e04e19b008e5a5c4f08fa551b3558b68afb800cb3c886f782a21950d5ea1029b631a6caa2658f02e7ae819e8d8c137a076470120d94deab99e524 SHA512 0a8b19f888af853e6a12aff9d6675f7a9977fef92efa19e69c79a6325fc1626efe7aa9fec8c42ee65ba29f0757b166567679a54d0351f19ea502183e92a63ac5 +DIST genpatches-5.11-3.experimental.tar.xz 6092 BLAKE2B ac1c5aa031e99dd332c51c44c05e00460bf2d1244ab6e00179d81c941b58c97c9aef3b8dd14ebc87e3b00f2fb4a393172d17e38121898850452ec3377ce02b7c SHA512 248d5a585d8963a31e3951a0ecce5c6b0522c32df14505bb6d7ad4fa69a9e00eb4dd5c31e561f13f14dd3aeac50db9aa2c43ff8dcb10cb363eba5af386fe8788 +DIST genpatches-5.11-3.extras.tar.xz 1772 BLAKE2B 165d5928e6afc65544392186737efd1df9e1179591ef7edd85a1868971ea76016161a38a615e9e692c4515fe7fc19424a0cfd01420b5ec57a60c8d1d2d223cb7 SHA512 c74015c4e1b824c61db9e9deca6b30a839ae9a8fb5747cb6c46e2af99a9221f11bb971099554107bbfc58ea5389d96e810f9cf8e55d0bcc16a093eef941c6ec8 +DIST genpatches-5.4-100.base.tar.xz 3072228 BLAKE2B e9dcc72a03ee2ceb3e02d8dc76b57178c6b7066e07b925bffbd6edf72befb262b68c953522052a357040ee1d087da414a5a100d29762fb65c0e0e1dd122879b7 SHA512 7ab34d9742d5d941632abbc392ca38c6dede00993263e9487a0f7f329b6d36803b9c26017e8f1daf00956f79d34a0a9365fcf5ddfb2322a03ed58476441c7bdf +DIST genpatches-5.4-100.experimental.tar.xz 18084 BLAKE2B 61c2dadebeb773b2bb463580c84e12e43f67e5f22ffb6b7d6636e506ccff7f24d5bd6eaec35a4607c6c116589375a7ebe1cf89132c8df5254868c8202f2c8b18 SHA512 76eda39adc319d465f4670aa36d62a7b2f484008d92906969e346670574f6af44a858f254daae5466598c0ce7c9fb5d0500fb2322ef43bc45ad526a79e070e10 +DIST genpatches-5.4-100.extras.tar.xz 1772 BLAKE2B 60ef6c84479783e92f613314e753e723201e8f58938e1ba7d58831b045cb02669dadbb4fe66eb10f4c7543359d9d16371aec09d6dbbf341471dedcf6bca29121 SHA512 0e8b851b181fa711645996b989c92ea0a4665094197700c4b5315bd92c2f4e6dde59ddeb6931f2533c8095a3f9e8a4e5e23bd5d0d473814a46aadacd10c30a62 +DIST genpatches-5.4-101.base.tar.xz 3089116 BLAKE2B c6e716ab8d0e98d3b3b4c492d6a516ada65f5e77d375cb9164a080aabd94311c50a222135499eef9dcad3f80b29b831a3fe015c3006178651c2136620f9079c5 SHA512 1bdd6f8f23a6151298e2e2fec493c9a2e95a1a65f4a4b6ff95598f45d4fad783da2a596c05b5582ec3d82ed8d8aaf654706da768a1b248bdae37fb08481b3dc3 +DIST genpatches-5.4-101.experimental.tar.xz 18088 BLAKE2B 23c77868245b6b19dd6c06de11f06c511baf17f461f7b3e487a86df852a4a7030513c3e87d3ef1496d5f9bb0c6943b198caaf5a4351c448fdf4bb3743aa3e88e SHA512 bca35c22b8c59370d29cffe854e355fb65889c3e3d0783768b7d0de3060f564dced4a2db443a3144b9ec48a95dbb9f39b2637f376399f97d4d2b25f0eec60027 +DIST genpatches-5.4-101.extras.tar.xz 1768 BLAKE2B 44b92b9c288f4f10f499e5b6d2179b44ee3418890905341703901a71b703ff99e992d6e7424521e67d3b1f80e41286c2357187c66e9b1ae7c1feef430f0ed74a SHA512 e397f970bc3b68b91f059e4b4f2d6163f8416340096b16b040eed8a5242a001db37b0fe8c1fd2a54c73bf6121aa55efa1c362b7837e930b758bc3bd33f8dce09 +DIST genpatches-5.4-103.base.tar.xz 3091428 BLAKE2B 73b7a87dea4ca50bc1ab188b0948c0236f740f18b9dce7d8e4238dcbe9e045dc96dffb7a4c363e195dd2f04b537c53a537920bb6bbcfabc363bc109355771bfb SHA512 afea1a44e1eee6692aa8b398c21bbea62ab0ced41db7eb821d879015cff6c88a80a605dc263085119affd6a4005ae08e483f2293438c5986f6772031956e62b0 +DIST genpatches-5.4-103.experimental.tar.xz 6704 BLAKE2B be746144877ce742a7ba65adaea01f479a93be410d13e3661d181586404f12c32f05835273143d47984f251dc49deea5e83b46c0ffb7a80225c76a428e5a84b0 SHA512 71c43112ab0b2c564c8190bc4312c2485f370cdcf060c1799f60cbe9ed11f8f625ca28a2330f911560fb682e866ab3ed162ce99a64191b2513553983b921d130 +DIST genpatches-5.4-103.extras.tar.xz 1768 BLAKE2B 0b28c7f0c9bf45f3ac7370e751045760069d078e0609f5987b7faac6e367bdc0d0a16f9f94a7684f9c76c43a25b6e59acdfa44614e86e3fdb13eff532621926c SHA512 7e7c4653684a09bfe9b264b0e4c6b8de7d842c91e4ed1c005bd87ac996f1e2cdbc461c8d4cb084707ee5214a0e16e9e26ab21d6860331e245924feeafc1900be +DIST genpatches-5.4-104.base.tar.xz 3093716 BLAKE2B da8a9f572f4a22eb101a477ed2b2a81b0adaed65f1913c163b58dc958de661707733fb1e0d06e49ec342666ca0c212313d3a5fbca60c79779009b91361e23f42 SHA512 2ef214d2e4ea982c6702991519aaa183d6731f882fa59db5cc2d7832c7fcaf8de57dc2173f4a59922e5d90da2d046753b3eed609513c84c784c13d5be747303b +DIST genpatches-5.4-104.experimental.tar.xz 6700 BLAKE2B 3254eb73899fbe426890f7effdbe484dc2b1398469fb35ca1006503a91aa558a9e5d775b5587c73500686bc334eda1ceea49f10a5479d920ce3a1662fda5fec8 SHA512 a8f6193cd6fd4a6214a28a7039c7407d3d714e398d16da63ac63703da81a1bbc7cc903808106c11125e7c973a2709728e0100d379b22a214bfe51edeed1dfab6 +DIST genpatches-5.4-104.extras.tar.xz 1768 BLAKE2B 7f335d61bd5f44cfa74ce2082259a48791ed90c21da4d05ff13c191adf1f658e68634c4cf9779274e6f775409695634ca40187754b0f9d50b406c26df26adbc4 SHA512 a8080605c59079063065d9bebc9d846ab8aab73f2f192f6c5becea2b51304a1e4d91e20d9aacd61f2cfa5b967bb8e30d620ddd60592017f308ad2f65ab7287a5 DIST genpatches-5.4-82.base.tar.xz 2792480 BLAKE2B 39960646116f5f85ee657a29557d8fd9e809ae9bc60aac349c91e7680f2a0565800ba37a478573098dbad41b686336a058985d2925e5046fa68eeaea8df25477 SHA512 6a76eebd7178e2ccc522477f53c36f74e6fd691f87c547dffa2602a516ad9a6a01f05c953e12bbe6ba9aa2ce34b176a6a081a22da40c7d86855e5dfc34098059 DIST genpatches-5.4-82.experimental.tar.xz 6704 BLAKE2B 4dcaa6977e25a2d9327d043a15115eba34a802bfa80d532ff2ae3c1495a861d4a4a85ad102e69558d247ae9a0effbf4628e8963f435b949eeffd35f735ea49bc SHA512 4fba72e9efc3dd11fe934be4820703f2f8268c5479dcdae1183104a6b1c2c22715b4529d6e8a4f65d8e46d52b12ab47e3d2eee8dda038af5cac7b799263e84d2 DIST genpatches-5.4-82.extras.tar.xz 1772 BLAKE2B 8eff7ca01490badd5dad15497f77bf43c268ccb494db9eb4c18f4f59219f1a5d79ef2a6f35caee87e3c423b0fff1ef94a6d6477e5074397f78e4bd23b9c40d95 SHA512 bdcc7eb08c1cdb599e69b254f55685f7beec83f256518d42c31d0df9a4e1c6376c184145ce47d28e0b688d2166e139445ef5f9f284e817ba9f37eaf812852a88 -DIST genpatches-5.4-92.base.tar.xz 2987648 BLAKE2B ffdccfc93b1b759494cd3adf2496e2074e847c46ec1c9dfdab32d3a7dfaf5a334df0391ba7ccb35250c562a529df8ae2784656628e110887b593536ac6b0d3ea SHA512 d2c08ecebcabaeb658407626c71c98201f86cf6510c4906b37f45d0f9fd6677b709fbdd9a1ce16622632c9a2e72a11d93463bdae62c5d8d0655c999223909e51 -DIST genpatches-5.4-92.experimental.tar.xz 18084 BLAKE2B 8341edc51d259311407055d080b7759b5895c7899724ac19f49ef18115a6eaf0192606fc8b63edb37770e8daed75e3d69d9b0395238a1ae3b1da391af2f6c39d SHA512 4d77cf39d5bc8dba49c1a430b4f0e5570db24e7f91fe3bdaf9661be98432c5b8bc492f3ecc24e4495c880601fa563af2dc538684ce3c31daabd31fb55a253ec2 -DIST genpatches-5.4-92.extras.tar.xz 1768 BLAKE2B 41cca01e9893db97ab1c7bc920d3240b3aec6207ff6516b346a87f24b47811077d7bbbdca49ed267238af4f5eeb2e8e0de03c946fb6f3784a08bdde348a5a64b SHA512 bb88a3c13a4335b93eb1ded903696e63ffa87b0a1dc587f464335fe077623abc36831fe514f33737960328ec765c5c0bf5489e84dff3fc6ae37ab2e1cd61d94e -DIST genpatches-5.4-93.base.tar.xz 3001024 BLAKE2B d5f3020aae1a920a076457cf28ae640e8ab7387652a61db3d631a3494c5cb0e8706d92debb6356768fea992679aefd4bda6d212a9918a714740439811dd3ef6d SHA512 420512b65e20f00fcabf4d122cf5fd166a6cc196a77451f8a06b333ca2cdc189c38654333e565cc555b1f3e9745e9c4b188b98648cd57ccb395ca1259675e4d2 -DIST genpatches-5.4-93.experimental.tar.xz 18084 BLAKE2B be9a54735db9f489daf3d739edf8ea52d28212400f70635c480debe46a47b029c2e364a83be897c28a013539ed4340cf1730daa1b2aea862a11bc3435b3e7cfc SHA512 cd61fd88df270a49fdce6cb4362ec4aa73b101fb26a83a5a0361133775702a59c9c19abc5ed201dd697054bca66d233f0289d0174abf663de8f18a92baaff301 -DIST genpatches-5.4-93.extras.tar.xz 1772 BLAKE2B 0ad1eff5f82120235a1f326176beeaefcf7aa547eecc94ad103a5be1701dd922ae0309431a10233c0df5bf63c5ba970bdec32e6ca782965e369be2fa5a4577dc SHA512 b5415fe59ba41d60a46e0c123abcee0bb72b5a7d7358789947627ae086c7391c09f116a16c32b2475c278ea14d7275932046d686aa4a849942cbf64440506c92 -DIST genpatches-5.4-94.base.tar.xz 3006280 BLAKE2B a8130e4be0b40fd0c82d9da6c3f42d3e45dc0119b7a981a62b0577e16cb73ae7edb76b407ecdaaf0bd53a118164208529d9bde3958c9592cedb3ef04815e64e9 SHA512 bf4b59da586a4f5f4a03b40273cbb6d5e9e49273c9c15fa2d3dd7eb002c0c24db895fa3987c93268c1dbfb1402197192f2f2c42b22f443a50089ce26d0f721a2 -DIST genpatches-5.4-94.experimental.tar.xz 18092 BLAKE2B 9f404c2ec62147ad30cd50c3d47727f254fdf3fb6c291a4c97ffc4ca260f979cde0d907ddc27fccd013dea871016fbec70a8cd21da86ba1422d9bcfcfe28b9fe SHA512 2496144bd1b7210290837c88c63b5ee648fb935deae76354101097f30ed2e50a02ae666ba9451aa8c658999ac72fd52c0bf3091348301093aa7ebf74a271ab7b -DIST genpatches-5.4-94.extras.tar.xz 1772 BLAKE2B d7f9cbdd2739ff180d7fa1de7ae24f9d0beeed259b00b0a67e6a3e9dfeb7a2e7136c0682af7e50491fa9010ea3e3e03a37cb8eac96047a4d4e58177d64caf72d SHA512 eee973e296444e301a6d9f59e82e39b2d2b1aa6605fe62c54a3710f300bad9e3b3a13c14f16f357a6c8775c50b47d390f537f15030c4fb08a6d81e5ba4008f1d -DIST genpatches-5.4-95.base.tar.xz 3022876 BLAKE2B e935ec5e2cacf478fd8ac2f343d0e582cceddf811ea4d87d5518b946b8b0501e7aff29d406407d3f0d276ea32a616f022789ee1318b282c6fd77b3aaf0d64631 SHA512 4e87014b78683372d525d6409c5c038429423371a1369f2c3b1455e53f5360290dd323ccc24aaeeb4a9e66452e9c87dba439c75192b77e4fc7bc888bc1c4cdac -DIST genpatches-5.4-95.experimental.tar.xz 18096 BLAKE2B 5e37e20fc56f19d06ca044028507115a61d322e0cc4b31919824052243a23a1516077c0744d1f8377fc4d44b091fc0901714ec34f469a5a93f3364d1994943ed SHA512 3bae5d5b4844c2cf9085cd060c217ed249ce1476a1220c531bf1ffec3f88612bdc34027946fe9739ae8a6ea06677c75cdd5d491dc0475b41f0c18f5c085c024a -DIST genpatches-5.4-95.extras.tar.xz 1772 BLAKE2B 29c822d815b565e99441f122bb978db211288f69ec3e3795e2555aa58cc3d2911debaeddcf202ce7be335771310589548a9de82d0500982894b621d0f773d7a3 SHA512 860978d98d7715b1359e0f3e47a0369ee6ef9e1cc4fd4201ad879dcab0aac644f6a951875643ccb70d31b6dad8b23d0b4ca7b32e50739bd87499760829949749 -DIST genpatches-5.4-96.base.tar.xz 3031600 BLAKE2B 9ba35f7958842a1fd4c9a7e7d3666ea1339ee5fadde6b771b78f67a8bb27c07e8dad8498e9b85fa0bcfd641f5aef9641793a02061b03becd372ea86245820895 SHA512 3edea8a4fc2a29e0f989089633256b270589ad77a225f3cef6e414c5877de1be8a4d5d9da28bfa4fba848f33ee322c4f01befcdf384c9271c97c90e2e2d3ad39 -DIST genpatches-5.4-96.experimental.tar.xz 18092 BLAKE2B 00610aa541214806bd5fa8a0c239b5f3fa4a731471284b50038a8e2278fdcf711da5dde2ec35b992856f9f496dda13b015c11b24e571824f17f741a228898979 SHA512 6c2dd5cce9f85f7b27cf26e2495bb7c0cf62f8a554b09465b843baee70dcffbc265ae780c735c82605427033d25070ee6e540cf5297923388a80db173d0b8f2e -DIST genpatches-5.4-96.extras.tar.xz 1772 BLAKE2B f33c734139f65245694d3cb98712733a901e89c79d05fab03de42d82d6e45ed3ec41ab4e17f2cd20be2ec31d469cf02a5efc7bad93832c67d3ad0bbf147b07e6 SHA512 8b7d6d058906b9c9afb7addba0c3072d70758bd75ea2989787beab5a3a83725541b4084c34cbb1e90b6cc8bb323a002dfca7065cc88fc834891f04397caa645c -DIST genpatches-5.4-97.base.tar.xz 3041620 BLAKE2B 4b738b0b9dc990d47577b44c4d1931c28727b461891a673eaa82e3add22f56f57494548c76ce6f63872f62d2b58c2c4e1fbdb84d5b4233f1a9df326fe29de60a SHA512 34adda6c55d8fd491c8c667c9ed71deb6afd4f92fcb26999baec619088dd3483be0b665a76bcf72f1f52abfb6b0bb8a0909c2cb549220ec130afdaa0ea482c84 -DIST genpatches-5.4-97.experimental.tar.xz 18088 BLAKE2B ef222d8b76cfc71cf29bbb3eff90729f8521466e967d03612fc04d02dcfbc766471931fe4ed263aa85e9f53c09453a81266cdeff781eb94a57e7f755bc08d427 SHA512 a8ace0a51ca8c51c6dc07339b3ef5dc05ef4ed6642736fa69123a49f9ec18bd36ea3f875a6f35c1dc8a1d9e0f6d87bde0a6f388ad3851e97b4dcd51243058f5f -DIST genpatches-5.4-97.extras.tar.xz 1772 BLAKE2B 5c0ed8ac19c10d0e95ff270bb7c2fd559405218f836290df7bdcd5c07ac3cb7e06221d05e40906d97242807ece263c1aa226cba583e5a822d55328608c765d1c SHA512 08cbda97510319fc497b806238c76eb60ad12b35ec7e075ee10ae3cbc6db61b1b3ea061c9c7b3a11f21125fb0d9e111a6a717eed6c3f885a7244d9e63e02c697 -DIST genpatches-5.4-98.base.tar.xz 3049548 BLAKE2B 38d6f3b3c7121721667ae183683e7e2fb9e3edb66d5caccb7a802429c4f6ee68b2cbda5503464064268efbc8f7f3d7fb5c66164f08c815f228c439fc3d55adb4 SHA512 174247357b558834635b90b79346c7c5005a84fd17c0d20cbe09d2405a7d32b0d7e3f14a8683e26f1c12058d510f2827ed0cab5fbb12cb829679a10c317e25bd -DIST genpatches-5.4-98.experimental.tar.xz 18084 BLAKE2B 2a4a66a51bed50ace689e2777f31811010dead8fdc44af2c10c865e459ce54c2eb00479b3daea6ff3ef78373800844c45aff4c375eb4e6ca3e269196ebf1e038 SHA512 94bd6b11f40be6fedc8a56546fbed4b5f266e4a778e6f06ad03842e86e61d9537e6b9675f11e8554814ddf8f4715fa2eb77c64da03ffa1dde568786bae57b769 -DIST genpatches-5.4-98.extras.tar.xz 1772 BLAKE2B 620bd1c1f60762806ecf90c391f97864567d8ebbf41279bf3a10e1a98de636cefa9616907bdb4922e7ae8c202ef5f3d68a5f551d83af54e70f5252431172730b SHA512 a1c5f239564745bbf1347831995699d52011d856d0965d020cb6f082bb5ca9031f8f9e6fa7d692f04042bbfdcd9aea7e20721198a961021ffa62bd5fcce666a1 DIST genpatches-5.4-99.base.tar.xz 3064716 BLAKE2B f71d76c88a9932d3b0e1b45d065fa0946f36a3100e3b59c5ce4c373519119066973067e4bb74d094cd5b79e689affa4615faf40da75a730b62df2259d3361c43 SHA512 833a83d7aecb1a216783fdf57e0fda342fd481c74166d976326a8333dfb2a13bd61f1b20b749f17b3498756b6134f8538a971507427f4e955bc9128742a3be5f DIST genpatches-5.4-99.experimental.tar.xz 18092 BLAKE2B a6263f1dd87eb2f701e248ce34c48251cb3ab796fc38ac4a9477c14528436eac0a767a3f380f634f8a68b987dad500b3c11ddba873982e958b0c8d14aaba2691 SHA512 995c465b79f4f67678c325c84abf3d66970b2e3de786b1b83863b224f2a83335401384f236a71b9294daa6a2d815ae79c6b612b0e157463a317c507e447eda76 DIST genpatches-5.4-99.extras.tar.xz 1772 BLAKE2B 6ffe84c928fc61b306d3e9a096470c090b79bfe99c90981b64e324d40157e818b50c0aebbaf342f51eeba29867b8cf8a6e91394dd594c1ecdb4f2a64f8d76e00 SHA512 7f2db3353809e7922951e1e884d7fe4a426556750bf4e38619278185fb09d519b30a972f4b5aeda3f7aca335fc95372edcc5dadd0881febbf43403c4d5c1c497 @@ -153,4 +111,5 @@ DIST linux-4.19.tar.xz 103117552 BLAKE2B 1dbf16cf410867412d17568fe42bc1e90c03418 DIST linux-4.4.tar.xz 87295988 BLAKE2B f260f1858994f5d481fd078c86e51bddbc958f7c5d1586f60dced772e1b1107ecf3aae0558c3e6f39c36f7d3aa1e6cd1e5c64ec9d6f2218f47b98413da6466fb SHA512 13c8459933a8b80608e226a1398e3d1848352ace84bcfb7e6a4a33cb230bbe1ab719d4b58e067283df91ce5311be6d2d595fc8c19e2ae6ecc652499415614b3e DIST linux-4.9.tar.xz 93192404 BLAKE2B 83ae310b17d47f1f18d6d28537c31e10f3e60458c5954c4611158ca99e71cc0da2e051272eabf27d5887df4a7cb4a5dd66ff993077c11d2221e92d300a0b48d7 SHA512 bf67ff812cc3cb7e5059e82cc5db0d9a7c5637f7ed9a42e4730c715bf7047c81ed3a571225f92a33ef0b6d65f35595bc32d773356646df2627da55e9bc7f1f1a DIST linux-5.10.tar.xz 116606704 BLAKE2B b923d7b66309224f42f35f8a5fa219421b0a9362d2adacdadd8d96251f61f7230878ea297a269a7f3b3c56830f0b177e068691e1d7f88501a05653b0a13274d1 SHA512 95bc137d0cf9148da6a9d1f1a878698dc27b40f68e22c597544010a6c591ce1b256f083489d3ff45ff77753289b535135590194d88ef9f007d0ddab3d74de70e +DIST linux-5.11.tar.xz 117619104 BLAKE2B 81300c27bd5476387a83123aaeb4163c73eb61e9245806c23660cb5e6a4fa88ffc9def027031335fa0270fc4080506cd415990014364e3a98b9d2e8c58a29524 SHA512 a567ec133018bb5ec00c60281479b466c26e02137a93a9c690e83997947df02b6fd94e76e8df748f6d70ceb58a19bacc3b1467de10b7a1fad2763db32b3f1330 DIST linux-5.4.tar.xz 109441440 BLAKE2B 193bc4a3147e147d5529956164ec4912fad5d5c6fb07f909ff1056e57235834173194afc686993ccd785c1ff15804de0961b625f3008cca0e27493efc8f27b13 SHA512 9f60f77e8ab972b9438ac648bed17551c8491d6585a5e85f694b2eaa4c623fbc61eb18419b2656b6795eac5deec0edaa04547fc6723fbda52256bd7f3486898f diff --git a/sys-kernel/gentoo-sources/gentoo-sources-4.14.217.ebuild b/sys-kernel/gentoo-sources/gentoo-sources-4.14.217.ebuild deleted file mode 100644 index 5783404f2ecc..000000000000 --- a/sys-kernel/gentoo-sources/gentoo-sources-4.14.217.ebuild +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright 1999-2021 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI="6" -ETYPE="sources" -K_WANT_GENPATCHES="base extras experimental" -K_GENPATCHES_VER="227" - -inherit kernel-2 -detect_version -detect_arch - -KEYWORDS="~alpha amd64 ~arm ~arm64 ~hppa ~ia64 ~mips ~ppc ~ppc64 ~s390 ~sparc x86" -HOMEPAGE="https://dev.gentoo.org/~mpagano/genpatches" -IUSE="experimental" - -DESCRIPTION="Full sources including the Gentoo patchset for the ${KV_MAJOR}.${KV_MINOR} kernel tree" -SRC_URI="${KERNEL_URI} ${GENPATCHES_URI} ${ARCH_URI}" - -pkg_postinst() { - kernel-2_pkg_postinst - einfo "For more info on this patchset, and how to report problems, see:" - einfo "${HOMEPAGE}" -} - -pkg_postrm() { - kernel-2_pkg_postrm -} diff --git a/sys-kernel/gentoo-sources/gentoo-sources-4.14.218.ebuild b/sys-kernel/gentoo-sources/gentoo-sources-4.14.222.ebuild index 6db90d2787e6..41f1b71a7ef0 100644 --- a/sys-kernel/gentoo-sources/gentoo-sources-4.14.218.ebuild +++ b/sys-kernel/gentoo-sources/gentoo-sources-4.14.222.ebuild @@ -4,7 +4,7 @@ EAPI="6" ETYPE="sources" K_WANT_GENPATCHES="base extras experimental" -K_GENPATCHES_VER="228" +K_GENPATCHES_VER="232" inherit kernel-2 detect_version diff --git a/sys-kernel/gentoo-sources/gentoo-sources-4.19.169.ebuild b/sys-kernel/gentoo-sources/gentoo-sources-4.19.169.ebuild deleted file mode 100644 index f10f4e927f86..000000000000 --- a/sys-kernel/gentoo-sources/gentoo-sources-4.19.169.ebuild +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright 1999-2021 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI="6" -ETYPE="sources" -K_WANT_GENPATCHES="base extras experimental" -K_GENPATCHES_VER="168" - -inherit kernel-2 -detect_version -detect_arch - -KEYWORDS="~alpha ~amd64 ~arm ~arm64 ~hppa ~ia64 ~mips ~ppc ~ppc64 ~s390 ~sparc ~x86" -HOMEPAGE="https://dev.gentoo.org/~mpagano/genpatches" -IUSE="experimental" - -DESCRIPTION="Full sources including the Gentoo patchset for the ${KV_MAJOR}.${KV_MINOR} kernel tree" -SRC_URI="${KERNEL_URI} ${GENPATCHES_URI} ${ARCH_URI}" - -pkg_postinst() { - kernel-2_pkg_postinst - einfo "For more info on this patchset, and how to report problems, see:" - einfo "${HOMEPAGE}" -} - -pkg_postrm() { - kernel-2_pkg_postrm -} diff --git a/sys-kernel/gentoo-sources/gentoo-sources-4.19.170.ebuild b/sys-kernel/gentoo-sources/gentoo-sources-4.19.170.ebuild deleted file mode 100644 index 434c93393eab..000000000000 --- a/sys-kernel/gentoo-sources/gentoo-sources-4.19.170.ebuild +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright 1999-2021 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI="6" -ETYPE="sources" -K_WANT_GENPATCHES="base extras experimental" -K_GENPATCHES_VER="169" - -inherit kernel-2 -detect_version -detect_arch - -KEYWORDS="~alpha amd64 ~arm ~arm64 ~hppa ~ia64 ~mips ~ppc ~ppc64 ~s390 ~sparc x86" -HOMEPAGE="https://dev.gentoo.org/~mpagano/genpatches" -IUSE="experimental" - -DESCRIPTION="Full sources including the Gentoo patchset for the ${KV_MAJOR}.${KV_MINOR} kernel tree" -SRC_URI="${KERNEL_URI} ${GENPATCHES_URI} ${ARCH_URI}" - -pkg_postinst() { - kernel-2_pkg_postinst - einfo "For more info on this patchset, and how to report problems, see:" - einfo "${HOMEPAGE}" -} - -pkg_postrm() { - kernel-2_pkg_postrm -} diff --git a/sys-kernel/gentoo-sources/gentoo-sources-4.19.171.ebuild b/sys-kernel/gentoo-sources/gentoo-sources-4.19.171.ebuild deleted file mode 100644 index 8bc4bab20978..000000000000 --- a/sys-kernel/gentoo-sources/gentoo-sources-4.19.171.ebuild +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright 1999-2021 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI="6" -ETYPE="sources" -K_WANT_GENPATCHES="base extras experimental" -K_GENPATCHES_VER="170" - -inherit kernel-2 -detect_version -detect_arch - -KEYWORDS="~alpha ~amd64 ~arm ~arm64 ~hppa ~ia64 ~mips ~ppc ~ppc64 ~s390 ~sparc ~x86" -HOMEPAGE="https://dev.gentoo.org/~mpagano/genpatches" -IUSE="experimental" - -DESCRIPTION="Full sources including the Gentoo patchset for the ${KV_MAJOR}.${KV_MINOR} kernel tree" -SRC_URI="${KERNEL_URI} ${GENPATCHES_URI} ${ARCH_URI}" - -pkg_postinst() { - kernel-2_pkg_postinst - einfo "For more info on this patchset, and how to report problems, see:" - einfo "${HOMEPAGE}" -} - -pkg_postrm() { - kernel-2_pkg_postrm -} diff --git a/sys-kernel/gentoo-sources/gentoo-sources-4.19.172.ebuild b/sys-kernel/gentoo-sources/gentoo-sources-4.19.172.ebuild deleted file mode 100644 index 9972407c88b9..000000000000 --- a/sys-kernel/gentoo-sources/gentoo-sources-4.19.172.ebuild +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright 1999-2021 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI="6" -ETYPE="sources" -K_WANT_GENPATCHES="base extras experimental" -K_GENPATCHES_VER="171" - -inherit kernel-2 -detect_version -detect_arch - -KEYWORDS="~alpha ~amd64 ~arm ~arm64 ~hppa ~ia64 ~mips ~ppc ~ppc64 ~s390 ~sparc ~x86" -HOMEPAGE="https://dev.gentoo.org/~mpagano/genpatches" -IUSE="experimental" - -DESCRIPTION="Full sources including the Gentoo patchset for the ${KV_MAJOR}.${KV_MINOR} kernel tree" -SRC_URI="${KERNEL_URI} ${GENPATCHES_URI} ${ARCH_URI}" - -pkg_postinst() { - kernel-2_pkg_postinst - einfo "For more info on this patchset, and how to report problems, see:" - einfo "${HOMEPAGE}" -} - -pkg_postrm() { - kernel-2_pkg_postrm -} diff --git a/sys-kernel/gentoo-sources/gentoo-sources-4.14.215.ebuild b/sys-kernel/gentoo-sources/gentoo-sources-4.19.176.ebuild index 2c465b51b092..b4674d571fd4 100644 --- a/sys-kernel/gentoo-sources/gentoo-sources-4.14.215.ebuild +++ b/sys-kernel/gentoo-sources/gentoo-sources-4.19.176.ebuild @@ -4,7 +4,7 @@ EAPI="6" ETYPE="sources" K_WANT_GENPATCHES="base extras experimental" -K_GENPATCHES_VER="225" +K_GENPATCHES_VER="175" inherit kernel-2 detect_version diff --git a/sys-kernel/gentoo-sources/gentoo-sources-4.14.216.ebuild b/sys-kernel/gentoo-sources/gentoo-sources-4.19.177.ebuild index 0c6403a95493..f7c2b2668565 100644 --- a/sys-kernel/gentoo-sources/gentoo-sources-4.14.216.ebuild +++ b/sys-kernel/gentoo-sources/gentoo-sources-4.19.177.ebuild @@ -4,7 +4,7 @@ EAPI="6" ETYPE="sources" K_WANT_GENPATCHES="base extras experimental" -K_GENPATCHES_VER="226" +K_GENPATCHES_VER="176" inherit kernel-2 detect_version diff --git a/sys-kernel/gentoo-sources/gentoo-sources-4.4.251.ebuild b/sys-kernel/gentoo-sources/gentoo-sources-4.4.251.ebuild deleted file mode 100644 index bc91bdc17905..000000000000 --- a/sys-kernel/gentoo-sources/gentoo-sources-4.4.251.ebuild +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright 1999-2021 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI="6" -ETYPE="sources" -K_WANT_GENPATCHES="base extras experimental" -K_GENPATCHES_VER="253" - -inherit kernel-2 -detect_version -detect_arch - -KEYWORDS="~alpha ~amd64 ~arm ~arm64 ~hppa ~ia64 ~mips ~ppc ~ppc64 ~s390 ~sparc ~x86" -HOMEPAGE="https://dev.gentoo.org/~mpagano/genpatches" -IUSE="experimental" - -DESCRIPTION="Full sources including the Gentoo patchset for the ${KV_MAJOR}.${KV_MINOR} kernel tree" -SRC_URI="${KERNEL_URI} ${GENPATCHES_URI} ${ARCH_URI}" - -pkg_postinst() { - kernel-2_pkg_postinst - einfo "For more info on this patchset, and how to report problems, see:" - einfo "${HOMEPAGE}" -} - -pkg_postrm() { - kernel-2_pkg_postrm -} diff --git a/sys-kernel/gentoo-sources/gentoo-sources-4.4.252.ebuild b/sys-kernel/gentoo-sources/gentoo-sources-4.4.252.ebuild deleted file mode 100644 index 909eda897d23..000000000000 --- a/sys-kernel/gentoo-sources/gentoo-sources-4.4.252.ebuild +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright 1999-2021 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI="6" -ETYPE="sources" -K_WANT_GENPATCHES="base extras experimental" -K_GENPATCHES_VER="254" - -inherit kernel-2 -detect_version -detect_arch - -KEYWORDS="~alpha ~amd64 ~arm ~arm64 ~hppa ~ia64 ~mips ~ppc ~ppc64 ~s390 ~sparc ~x86" -HOMEPAGE="https://dev.gentoo.org/~mpagano/genpatches" -IUSE="experimental" - -DESCRIPTION="Full sources including the Gentoo patchset for the ${KV_MAJOR}.${KV_MINOR} kernel tree" -SRC_URI="${KERNEL_URI} ${GENPATCHES_URI} ${ARCH_URI}" - -pkg_postinst() { - kernel-2_pkg_postinst - einfo "For more info on this patchset, and how to report problems, see:" - einfo "${HOMEPAGE}" -} - -pkg_postrm() { - kernel-2_pkg_postrm -} diff --git a/sys-kernel/gentoo-sources/gentoo-sources-4.4.253.ebuild b/sys-kernel/gentoo-sources/gentoo-sources-4.4.253.ebuild deleted file mode 100644 index dc51d0bfe419..000000000000 --- a/sys-kernel/gentoo-sources/gentoo-sources-4.4.253.ebuild +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright 1999-2021 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI="6" -ETYPE="sources" -K_WANT_GENPATCHES="base extras experimental" -K_GENPATCHES_VER="255" - -inherit kernel-2 -detect_version -detect_arch - -KEYWORDS="~alpha amd64 ~arm ~arm64 ~hppa ~ia64 ~mips ~ppc ~ppc64 ~s390 ~sparc x86" -HOMEPAGE="https://dev.gentoo.org/~mpagano/genpatches" -IUSE="experimental" - -DESCRIPTION="Full sources including the Gentoo patchset for the ${KV_MAJOR}.${KV_MINOR} kernel tree" -SRC_URI="${KERNEL_URI} ${GENPATCHES_URI} ${ARCH_URI}" - -pkg_postinst() { - kernel-2_pkg_postinst - einfo "For more info on this patchset, and how to report problems, see:" - einfo "${HOMEPAGE}" -} - -pkg_postrm() { - kernel-2_pkg_postrm -} diff --git a/sys-kernel/gentoo-sources/gentoo-sources-4.4.254.ebuild b/sys-kernel/gentoo-sources/gentoo-sources-4.4.254.ebuild deleted file mode 100644 index 44e29420f662..000000000000 --- a/sys-kernel/gentoo-sources/gentoo-sources-4.4.254.ebuild +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright 1999-2021 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI="6" -ETYPE="sources" -K_WANT_GENPATCHES="base extras experimental" -K_GENPATCHES_VER="256" - -inherit kernel-2 -detect_version -detect_arch - -KEYWORDS="~alpha ~amd64 ~arm ~arm64 ~hppa ~ia64 ~mips ~ppc ~ppc64 ~s390 ~sparc ~x86" -HOMEPAGE="https://dev.gentoo.org/~mpagano/genpatches" -IUSE="experimental" - -DESCRIPTION="Full sources including the Gentoo patchset for the ${KV_MAJOR}.${KV_MINOR} kernel tree" -SRC_URI="${KERNEL_URI} ${GENPATCHES_URI} ${ARCH_URI}" - -pkg_postinst() { - kernel-2_pkg_postinst - einfo "For more info on this patchset, and how to report problems, see:" - einfo "${HOMEPAGE}" -} - -pkg_postrm() { - kernel-2_pkg_postrm -} diff --git a/sys-kernel/gentoo-sources/gentoo-sources-4.19.168.ebuild b/sys-kernel/gentoo-sources/gentoo-sources-4.4.258.ebuild index 36464fadd431..2d050c08857c 100644 --- a/sys-kernel/gentoo-sources/gentoo-sources-4.19.168.ebuild +++ b/sys-kernel/gentoo-sources/gentoo-sources-4.4.258.ebuild @@ -4,7 +4,7 @@ EAPI="6" ETYPE="sources" K_WANT_GENPATCHES="base extras experimental" -K_GENPATCHES_VER="167" +K_GENPATCHES_VER="260" inherit kernel-2 detect_version diff --git a/sys-kernel/gentoo-sources/gentoo-sources-4.9.251.ebuild b/sys-kernel/gentoo-sources/gentoo-sources-4.9.251.ebuild deleted file mode 100644 index 4856aa05c1d6..000000000000 --- a/sys-kernel/gentoo-sources/gentoo-sources-4.9.251.ebuild +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright 1999-2021 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI="6" -ETYPE="sources" -K_WANT_GENPATCHES="base extras experimental" -K_GENPATCHES_VER="255" - -inherit kernel-2 -detect_version -detect_arch - -KEYWORDS="~alpha ~amd64 ~arm ~arm64 ~hppa ~ia64 ~mips ~ppc ~ppc64 ~s390 ~sparc ~x86" -HOMEPAGE="https://dev.gentoo.org/~mpagano/genpatches" -IUSE="experimental" - -DESCRIPTION="Full sources including the Gentoo patchset for the ${KV_MAJOR}.${KV_MINOR} kernel tree" -SRC_URI="${KERNEL_URI} ${GENPATCHES_URI} ${ARCH_URI}" - -pkg_postinst() { - kernel-2_pkg_postinst - einfo "For more info on this patchset, and how to report problems, see:" - einfo "${HOMEPAGE}" -} - -pkg_postrm() { - kernel-2_pkg_postrm -} diff --git a/sys-kernel/gentoo-sources/gentoo-sources-4.9.252.ebuild b/sys-kernel/gentoo-sources/gentoo-sources-4.9.252.ebuild deleted file mode 100644 index 44e29420f662..000000000000 --- a/sys-kernel/gentoo-sources/gentoo-sources-4.9.252.ebuild +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright 1999-2021 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI="6" -ETYPE="sources" -K_WANT_GENPATCHES="base extras experimental" -K_GENPATCHES_VER="256" - -inherit kernel-2 -detect_version -detect_arch - -KEYWORDS="~alpha ~amd64 ~arm ~arm64 ~hppa ~ia64 ~mips ~ppc ~ppc64 ~s390 ~sparc ~x86" -HOMEPAGE="https://dev.gentoo.org/~mpagano/genpatches" -IUSE="experimental" - -DESCRIPTION="Full sources including the Gentoo patchset for the ${KV_MAJOR}.${KV_MINOR} kernel tree" -SRC_URI="${KERNEL_URI} ${GENPATCHES_URI} ${ARCH_URI}" - -pkg_postinst() { - kernel-2_pkg_postinst - einfo "For more info on this patchset, and how to report problems, see:" - einfo "${HOMEPAGE}" -} - -pkg_postrm() { - kernel-2_pkg_postrm -} diff --git a/sys-kernel/gentoo-sources/gentoo-sources-4.9.253.ebuild b/sys-kernel/gentoo-sources/gentoo-sources-4.9.253.ebuild deleted file mode 100644 index 77aa974ecb87..000000000000 --- a/sys-kernel/gentoo-sources/gentoo-sources-4.9.253.ebuild +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright 1999-2021 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI="6" -ETYPE="sources" -K_WANT_GENPATCHES="base extras experimental" -K_GENPATCHES_VER="257" - -inherit kernel-2 -detect_version -detect_arch - -KEYWORDS="~alpha amd64 ~arm ~arm64 ~hppa ~ia64 ~mips ~ppc ~ppc64 ~s390 ~sparc x86" -HOMEPAGE="https://dev.gentoo.org/~mpagano/genpatches" -IUSE="experimental" - -DESCRIPTION="Full sources including the Gentoo patchset for the ${KV_MAJOR}.${KV_MINOR} kernel tree" -SRC_URI="${KERNEL_URI} ${GENPATCHES_URI} ${ARCH_URI}" - -pkg_postinst() { - kernel-2_pkg_postinst - einfo "For more info on this patchset, and how to report problems, see:" - einfo "${HOMEPAGE}" -} - -pkg_postrm() { - kernel-2_pkg_postrm -} diff --git a/sys-kernel/gentoo-sources/gentoo-sources-4.9.254.ebuild b/sys-kernel/gentoo-sources/gentoo-sources-4.9.254.ebuild deleted file mode 100644 index 09534dde64fc..000000000000 --- a/sys-kernel/gentoo-sources/gentoo-sources-4.9.254.ebuild +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright 1999-2021 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI="6" -ETYPE="sources" -K_WANT_GENPATCHES="base extras experimental" -K_GENPATCHES_VER="258" - -inherit kernel-2 -detect_version -detect_arch - -KEYWORDS="~alpha ~amd64 ~arm ~arm64 ~hppa ~ia64 ~mips ~ppc ~ppc64 ~s390 ~sparc ~x86" -HOMEPAGE="https://dev.gentoo.org/~mpagano/genpatches" -IUSE="experimental" - -DESCRIPTION="Full sources including the Gentoo patchset for the ${KV_MAJOR}.${KV_MINOR} kernel tree" -SRC_URI="${KERNEL_URI} ${GENPATCHES_URI} ${ARCH_URI}" - -pkg_postinst() { - kernel-2_pkg_postinst - einfo "For more info on this patchset, and how to report problems, see:" - einfo "${HOMEPAGE}" -} - -pkg_postrm() { - kernel-2_pkg_postrm -} diff --git a/sys-kernel/gentoo-sources/gentoo-sources-4.9.258.ebuild b/sys-kernel/gentoo-sources/gentoo-sources-4.9.258.ebuild new file mode 100644 index 000000000000..201bb9292ead --- /dev/null +++ b/sys-kernel/gentoo-sources/gentoo-sources-4.9.258.ebuild @@ -0,0 +1,28 @@ +# Copyright 1999-2021 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +EAPI="6" +ETYPE="sources" +K_WANT_GENPATCHES="base extras experimental" +K_GENPATCHES_VER="262" + +inherit kernel-2 +detect_version +detect_arch + +KEYWORDS="~alpha ~amd64 ~arm ~arm64 ~hppa ~ia64 ~mips ~ppc ~ppc64 ~s390 ~sparc ~x86" +HOMEPAGE="https://dev.gentoo.org/~mpagano/genpatches" +IUSE="experimental" + +DESCRIPTION="Full sources including the Gentoo patchset for the ${KV_MAJOR}.${KV_MINOR} kernel tree" +SRC_URI="${KERNEL_URI} ${GENPATCHES_URI} ${ARCH_URI}" + +pkg_postinst() { + kernel-2_pkg_postinst + einfo "For more info on this patchset, and how to report problems, see:" + einfo "${HOMEPAGE}" +} + +pkg_postrm() { + kernel-2_pkg_postrm +} diff --git a/sys-kernel/gentoo-sources/gentoo-sources-5.10.10.ebuild b/sys-kernel/gentoo-sources/gentoo-sources-5.10.10.ebuild deleted file mode 100644 index 56efe9fc96f9..000000000000 --- a/sys-kernel/gentoo-sources/gentoo-sources-5.10.10.ebuild +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright 1999-2021 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI="6" -ETYPE="sources" -K_WANT_GENPATCHES="base extras experimental" -K_GENPATCHES_VER="12" - -inherit kernel-2 -detect_version -detect_arch - -KEYWORDS="~alpha ~amd64 ~arm ~arm64 ~hppa ~ia64 ~mips ~ppc ~ppc64 ~s390 ~sparc ~x86" -HOMEPAGE="https://dev.gentoo.org/~mpagano/genpatches" -IUSE="experimental" - -DESCRIPTION="Full sources including the Gentoo patchset for the ${KV_MAJOR}.${KV_MINOR} kernel tree" -SRC_URI="${KERNEL_URI} ${GENPATCHES_URI} ${ARCH_URI}" - -pkg_postinst() { - kernel-2_pkg_postinst - einfo "For more info on this patchset, and how to report problems, see:" - einfo "${HOMEPAGE}" -} - -pkg_postrm() { - kernel-2_pkg_postrm -} diff --git a/sys-kernel/gentoo-sources/gentoo-sources-5.10.11.ebuild b/sys-kernel/gentoo-sources/gentoo-sources-5.10.16.ebuild index c8d0c37d4a34..888fd442db11 100644 --- a/sys-kernel/gentoo-sources/gentoo-sources-5.10.11.ebuild +++ b/sys-kernel/gentoo-sources/gentoo-sources-5.10.16.ebuild @@ -4,7 +4,7 @@ EAPI="6" ETYPE="sources" K_WANT_GENPATCHES="base extras experimental" -K_GENPATCHES_VER="13" +K_GENPATCHES_VER="18" inherit kernel-2 detect_version diff --git a/sys-kernel/gentoo-sources/gentoo-sources-5.10.12.ebuild b/sys-kernel/gentoo-sources/gentoo-sources-5.10.17.ebuild index 0be2f31b2432..2cd5c9892bc9 100644 --- a/sys-kernel/gentoo-sources/gentoo-sources-5.10.12.ebuild +++ b/sys-kernel/gentoo-sources/gentoo-sources-5.10.17.ebuild @@ -4,7 +4,7 @@ EAPI="6" ETYPE="sources" K_WANT_GENPATCHES="base extras experimental" -K_GENPATCHES_VER="14" +K_GENPATCHES_VER="19" inherit kernel-2 detect_version diff --git a/sys-kernel/gentoo-sources/gentoo-sources-5.10.13.ebuild b/sys-kernel/gentoo-sources/gentoo-sources-5.10.18.ebuild index 6bd952a77a73..93ddcea2be73 100644 --- a/sys-kernel/gentoo-sources/gentoo-sources-5.10.13.ebuild +++ b/sys-kernel/gentoo-sources/gentoo-sources-5.10.18.ebuild @@ -4,7 +4,7 @@ EAPI="6" ETYPE="sources" K_WANT_GENPATCHES="base extras experimental" -K_GENPATCHES_VER="15" +K_GENPATCHES_VER="21" inherit kernel-2 detect_version diff --git a/sys-kernel/gentoo-sources/gentoo-sources-5.10.19.ebuild b/sys-kernel/gentoo-sources/gentoo-sources-5.10.19.ebuild new file mode 100644 index 000000000000..782dc7f46c14 --- /dev/null +++ b/sys-kernel/gentoo-sources/gentoo-sources-5.10.19.ebuild @@ -0,0 +1,28 @@ +# Copyright 1999-2021 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +EAPI="6" +ETYPE="sources" +K_WANT_GENPATCHES="base extras experimental" +K_GENPATCHES_VER="22" + +inherit kernel-2 +detect_version +detect_arch + +KEYWORDS="~alpha ~amd64 ~arm ~arm64 ~hppa ~ia64 ~mips ~ppc ~ppc64 ~riscv ~s390 ~sparc ~x86" +HOMEPAGE="https://dev.gentoo.org/~mpagano/genpatches" +IUSE="experimental" + +DESCRIPTION="Full sources including the Gentoo patchset for the ${KV_MAJOR}.${KV_MINOR} kernel tree" +SRC_URI="${KERNEL_URI} ${GENPATCHES_URI} ${ARCH_URI}" + +pkg_postinst() { + kernel-2_pkg_postinst + einfo "For more info on this patchset, and how to report problems, see:" + einfo "${HOMEPAGE}" +} + +pkg_postrm() { + kernel-2_pkg_postrm +} diff --git a/sys-kernel/gentoo-sources/gentoo-sources-5.10.8.ebuild b/sys-kernel/gentoo-sources/gentoo-sources-5.10.8.ebuild deleted file mode 100644 index 260c6174d12e..000000000000 --- a/sys-kernel/gentoo-sources/gentoo-sources-5.10.8.ebuild +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright 1999-2021 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI="6" -ETYPE="sources" -K_WANT_GENPATCHES="base extras experimental" -K_GENPATCHES_VER="10" - -inherit kernel-2 -detect_version -detect_arch - -KEYWORDS="~alpha ~amd64 ~arm ~arm64 ~hppa ~ia64 ~mips ~ppc ~ppc64 ~s390 ~sparc ~x86" -HOMEPAGE="https://dev.gentoo.org/~mpagano/genpatches" -IUSE="experimental" - -DESCRIPTION="Full sources including the Gentoo patchset for the ${KV_MAJOR}.${KV_MINOR} kernel tree" -SRC_URI="${KERNEL_URI} ${GENPATCHES_URI} ${ARCH_URI}" - -pkg_postinst() { - kernel-2_pkg_postinst - einfo "For more info on this patchset, and how to report problems, see:" - einfo "${HOMEPAGE}" -} - -pkg_postrm() { - kernel-2_pkg_postrm -} diff --git a/sys-kernel/gentoo-sources/gentoo-sources-5.10.9.ebuild b/sys-kernel/gentoo-sources/gentoo-sources-5.10.9.ebuild deleted file mode 100644 index b3115878befc..000000000000 --- a/sys-kernel/gentoo-sources/gentoo-sources-5.10.9.ebuild +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright 1999-2021 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI="6" -ETYPE="sources" -K_WANT_GENPATCHES="base extras experimental" -K_GENPATCHES_VER="11" - -inherit kernel-2 -detect_version -detect_arch - -KEYWORDS="~alpha ~amd64 ~arm ~arm64 ~hppa ~ia64 ~mips ~ppc ~ppc64 ~s390 ~sparc ~x86" -HOMEPAGE="https://dev.gentoo.org/~mpagano/genpatches" -IUSE="experimental" - -DESCRIPTION="Full sources including the Gentoo patchset for the ${KV_MAJOR}.${KV_MINOR} kernel tree" -SRC_URI="${KERNEL_URI} ${GENPATCHES_URI} ${ARCH_URI}" - -pkg_postinst() { - kernel-2_pkg_postinst - einfo "For more info on this patchset, and how to report problems, see:" - einfo "${HOMEPAGE}" -} - -pkg_postrm() { - kernel-2_pkg_postrm -} diff --git a/sys-kernel/gentoo-sources/gentoo-sources-5.11.0.ebuild b/sys-kernel/gentoo-sources/gentoo-sources-5.11.0.ebuild new file mode 100644 index 000000000000..5133f7764460 --- /dev/null +++ b/sys-kernel/gentoo-sources/gentoo-sources-5.11.0.ebuild @@ -0,0 +1,28 @@ +# Copyright 1999-2021 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +EAPI="6" +ETYPE="sources" +K_WANT_GENPATCHES="base extras experimental" +K_GENPATCHES_VER="1" + +inherit kernel-2 +detect_version +detect_arch + +KEYWORDS="~alpha ~amd64 ~arm ~arm64 ~hppa ~ia64 ~mips ~ppc ~ppc64 ~riscv ~s390 ~sparc ~x86" +HOMEPAGE="https://dev.gentoo.org/~mpagano/genpatches" +IUSE="experimental" + +DESCRIPTION="Full sources including the Gentoo patchset for the ${KV_MAJOR}.${KV_MINOR} kernel tree" +SRC_URI="${KERNEL_URI} ${GENPATCHES_URI} ${ARCH_URI}" + +pkg_postinst() { + kernel-2_pkg_postinst + einfo "For more info on this patchset, and how to report problems, see:" + einfo "${HOMEPAGE}" +} + +pkg_postrm() { + kernel-2_pkg_postrm +} diff --git a/sys-kernel/gentoo-sources/gentoo-sources-5.11.1.ebuild b/sys-kernel/gentoo-sources/gentoo-sources-5.11.1.ebuild new file mode 100644 index 000000000000..bcf9f3cb6f73 --- /dev/null +++ b/sys-kernel/gentoo-sources/gentoo-sources-5.11.1.ebuild @@ -0,0 +1,28 @@ +# Copyright 1999-2021 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +EAPI="6" +ETYPE="sources" +K_WANT_GENPATCHES="base extras experimental" +K_GENPATCHES_VER="2" + +inherit kernel-2 +detect_version +detect_arch + +KEYWORDS="~alpha ~amd64 ~arm ~arm64 ~hppa ~ia64 ~mips ~ppc ~ppc64 ~riscv ~s390 ~sparc ~x86" +HOMEPAGE="https://dev.gentoo.org/~mpagano/genpatches" +IUSE="experimental" + +DESCRIPTION="Full sources including the Gentoo patchset for the ${KV_MAJOR}.${KV_MINOR} kernel tree" +SRC_URI="${KERNEL_URI} ${GENPATCHES_URI} ${ARCH_URI}" + +pkg_postinst() { + kernel-2_pkg_postinst + einfo "For more info on this patchset, and how to report problems, see:" + einfo "${HOMEPAGE}" +} + +pkg_postrm() { + kernel-2_pkg_postrm +} diff --git a/sys-kernel/gentoo-sources/gentoo-sources-5.11.2.ebuild b/sys-kernel/gentoo-sources/gentoo-sources-5.11.2.ebuild new file mode 100644 index 000000000000..847b80ffe4b1 --- /dev/null +++ b/sys-kernel/gentoo-sources/gentoo-sources-5.11.2.ebuild @@ -0,0 +1,28 @@ +# Copyright 1999-2021 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +EAPI="6" +ETYPE="sources" +K_WANT_GENPATCHES="base extras experimental" +K_GENPATCHES_VER="3" + +inherit kernel-2 +detect_version +detect_arch + +KEYWORDS="~alpha ~amd64 ~arm ~arm64 ~hppa ~ia64 ~mips ~ppc ~ppc64 ~riscv ~s390 ~sparc ~x86" +HOMEPAGE="https://dev.gentoo.org/~mpagano/genpatches" +IUSE="experimental" + +DESCRIPTION="Full sources including the Gentoo patchset for the ${KV_MAJOR}.${KV_MINOR} kernel tree" +SRC_URI="${KERNEL_URI} ${GENPATCHES_URI} ${ARCH_URI}" + +pkg_postinst() { + kernel-2_pkg_postinst + einfo "For more info on this patchset, and how to report problems, see:" + einfo "${HOMEPAGE}" +} + +pkg_postrm() { + kernel-2_pkg_postrm +} diff --git a/sys-kernel/gentoo-sources/gentoo-sources-5.4.100.ebuild b/sys-kernel/gentoo-sources/gentoo-sources-5.4.100.ebuild new file mode 100644 index 000000000000..cdd2043692ab --- /dev/null +++ b/sys-kernel/gentoo-sources/gentoo-sources-5.4.100.ebuild @@ -0,0 +1,28 @@ +# Copyright 1999-2021 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +EAPI="6" +ETYPE="sources" +K_WANT_GENPATCHES="base extras experimental" +K_GENPATCHES_VER="103" + +inherit kernel-2 +detect_version +detect_arch + +KEYWORDS="~alpha ~amd64 ~arm ~arm64 ~hppa ~ia64 ~mips ~ppc ~ppc64 ~s390 ~sparc ~x86" +HOMEPAGE="https://dev.gentoo.org/~mpagano/genpatches" +IUSE="experimental" + +DESCRIPTION="Full sources including the Gentoo patchset for the ${KV_MAJOR}.${KV_MINOR} kernel tree" +SRC_URI="${KERNEL_URI} ${GENPATCHES_URI} ${ARCH_URI}" + +pkg_postinst() { + kernel-2_pkg_postinst + einfo "For more info on this patchset, and how to report problems, see:" + einfo "${HOMEPAGE}" +} + +pkg_postrm() { + kernel-2_pkg_postrm +} diff --git a/sys-kernel/gentoo-sources/gentoo-sources-5.4.101.ebuild b/sys-kernel/gentoo-sources/gentoo-sources-5.4.101.ebuild new file mode 100644 index 000000000000..e46bcfd231b2 --- /dev/null +++ b/sys-kernel/gentoo-sources/gentoo-sources-5.4.101.ebuild @@ -0,0 +1,28 @@ +# Copyright 1999-2021 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +EAPI="6" +ETYPE="sources" +K_WANT_GENPATCHES="base extras experimental" +K_GENPATCHES_VER="104" + +inherit kernel-2 +detect_version +detect_arch + +KEYWORDS="~alpha ~amd64 ~arm ~arm64 ~hppa ~ia64 ~mips ~ppc ~ppc64 ~s390 ~sparc ~x86" +HOMEPAGE="https://dev.gentoo.org/~mpagano/genpatches" +IUSE="experimental" + +DESCRIPTION="Full sources including the Gentoo patchset for the ${KV_MAJOR}.${KV_MINOR} kernel tree" +SRC_URI="${KERNEL_URI} ${GENPATCHES_URI} ${ARCH_URI}" + +pkg_postinst() { + kernel-2_pkg_postinst + einfo "For more info on this patchset, and how to report problems, see:" + einfo "${HOMEPAGE}" +} + +pkg_postrm() { + kernel-2_pkg_postrm +} diff --git a/sys-kernel/gentoo-sources/gentoo-sources-5.4.90.ebuild b/sys-kernel/gentoo-sources/gentoo-sources-5.4.90.ebuild deleted file mode 100644 index 9b3b0d35df46..000000000000 --- a/sys-kernel/gentoo-sources/gentoo-sources-5.4.90.ebuild +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright 1999-2021 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI="6" -ETYPE="sources" -K_WANT_GENPATCHES="base extras experimental" -K_GENPATCHES_VER="92" - -inherit kernel-2 -detect_version -detect_arch - -KEYWORDS="~alpha ~amd64 ~arm ~arm64 ~hppa ~ia64 ~mips ~ppc ~ppc64 ~s390 ~sparc ~x86" -HOMEPAGE="https://dev.gentoo.org/~mpagano/genpatches" -IUSE="experimental" - -DESCRIPTION="Full sources including the Gentoo patchset for the ${KV_MAJOR}.${KV_MINOR} kernel tree" -SRC_URI="${KERNEL_URI} ${GENPATCHES_URI} ${ARCH_URI}" - -pkg_postinst() { - kernel-2_pkg_postinst - einfo "For more info on this patchset, and how to report problems, see:" - einfo "${HOMEPAGE}" -} - -pkg_postrm() { - kernel-2_pkg_postrm -} diff --git a/sys-kernel/gentoo-sources/gentoo-sources-5.4.91.ebuild b/sys-kernel/gentoo-sources/gentoo-sources-5.4.91.ebuild deleted file mode 100644 index 46d0bbb4d5d7..000000000000 --- a/sys-kernel/gentoo-sources/gentoo-sources-5.4.91.ebuild +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright 1999-2021 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI="6" -ETYPE="sources" -K_WANT_GENPATCHES="base extras experimental" -K_GENPATCHES_VER="93" - -inherit kernel-2 -detect_version -detect_arch - -KEYWORDS="~alpha ~amd64 ~arm ~arm64 ~hppa ~ia64 ~mips ~ppc ~ppc64 ~s390 ~sparc ~x86" -HOMEPAGE="https://dev.gentoo.org/~mpagano/genpatches" -IUSE="experimental" - -DESCRIPTION="Full sources including the Gentoo patchset for the ${KV_MAJOR}.${KV_MINOR} kernel tree" -SRC_URI="${KERNEL_URI} ${GENPATCHES_URI} ${ARCH_URI}" - -pkg_postinst() { - kernel-2_pkg_postinst - einfo "For more info on this patchset, and how to report problems, see:" - einfo "${HOMEPAGE}" -} - -pkg_postrm() { - kernel-2_pkg_postrm -} diff --git a/sys-kernel/gentoo-sources/gentoo-sources-5.4.92.ebuild b/sys-kernel/gentoo-sources/gentoo-sources-5.4.92.ebuild deleted file mode 100644 index c85015165b19..000000000000 --- a/sys-kernel/gentoo-sources/gentoo-sources-5.4.92.ebuild +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright 1999-2021 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI="6" -ETYPE="sources" -K_WANT_GENPATCHES="base extras experimental" -K_GENPATCHES_VER="94" - -inherit kernel-2 -detect_version -detect_arch - -KEYWORDS="~alpha amd64 ~arm ~arm64 ~hppa ~ia64 ~mips ~ppc ~ppc64 ~s390 ~sparc x86" -HOMEPAGE="https://dev.gentoo.org/~mpagano/genpatches" -IUSE="experimental" - -DESCRIPTION="Full sources including the Gentoo patchset for the ${KV_MAJOR}.${KV_MINOR} kernel tree" -SRC_URI="${KERNEL_URI} ${GENPATCHES_URI} ${ARCH_URI}" - -pkg_postinst() { - kernel-2_pkg_postinst - einfo "For more info on this patchset, and how to report problems, see:" - einfo "${HOMEPAGE}" -} - -pkg_postrm() { - kernel-2_pkg_postrm -} diff --git a/sys-kernel/gentoo-sources/gentoo-sources-5.4.93.ebuild b/sys-kernel/gentoo-sources/gentoo-sources-5.4.93.ebuild deleted file mode 100644 index f77c5f2a22d7..000000000000 --- a/sys-kernel/gentoo-sources/gentoo-sources-5.4.93.ebuild +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright 1999-2021 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI="6" -ETYPE="sources" -K_WANT_GENPATCHES="base extras experimental" -K_GENPATCHES_VER="95" - -inherit kernel-2 -detect_version -detect_arch - -KEYWORDS="~alpha ~amd64 ~arm ~arm64 ~hppa ~ia64 ~mips ~ppc ~ppc64 ~s390 ~sparc ~x86" -HOMEPAGE="https://dev.gentoo.org/~mpagano/genpatches" -IUSE="experimental" - -DESCRIPTION="Full sources including the Gentoo patchset for the ${KV_MAJOR}.${KV_MINOR} kernel tree" -SRC_URI="${KERNEL_URI} ${GENPATCHES_URI} ${ARCH_URI}" - -pkg_postinst() { - kernel-2_pkg_postinst - einfo "For more info on this patchset, and how to report problems, see:" - einfo "${HOMEPAGE}" -} - -pkg_postrm() { - kernel-2_pkg_postrm -} diff --git a/sys-kernel/gentoo-sources/gentoo-sources-5.4.94.ebuild b/sys-kernel/gentoo-sources/gentoo-sources-5.4.94.ebuild deleted file mode 100644 index c7fbc7184f24..000000000000 --- a/sys-kernel/gentoo-sources/gentoo-sources-5.4.94.ebuild +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright 1999-2021 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI="6" -ETYPE="sources" -K_WANT_GENPATCHES="base extras experimental" -K_GENPATCHES_VER="96" - -inherit kernel-2 -detect_version -detect_arch - -KEYWORDS="~alpha ~amd64 ~arm ~arm64 ~hppa ~ia64 ~mips ~ppc ~ppc64 ~s390 ~sparc ~x86" -HOMEPAGE="https://dev.gentoo.org/~mpagano/genpatches" -IUSE="experimental" - -DESCRIPTION="Full sources including the Gentoo patchset for the ${KV_MAJOR}.${KV_MINOR} kernel tree" -SRC_URI="${KERNEL_URI} ${GENPATCHES_URI} ${ARCH_URI}" - -pkg_postinst() { - kernel-2_pkg_postinst - einfo "For more info on this patchset, and how to report problems, see:" - einfo "${HOMEPAGE}" -} - -pkg_postrm() { - kernel-2_pkg_postrm -} diff --git a/sys-kernel/gentoo-sources/gentoo-sources-5.4.95.ebuild b/sys-kernel/gentoo-sources/gentoo-sources-5.4.95.ebuild deleted file mode 100644 index 4c5ce9be6c28..000000000000 --- a/sys-kernel/gentoo-sources/gentoo-sources-5.4.95.ebuild +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright 1999-2021 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI="6" -ETYPE="sources" -K_WANT_GENPATCHES="base extras experimental" -K_GENPATCHES_VER="97" - -inherit kernel-2 -detect_version -detect_arch - -KEYWORDS="~alpha ~amd64 ~arm ~arm64 ~hppa ~ia64 ~mips ~ppc ~ppc64 ~s390 ~sparc ~x86" -HOMEPAGE="https://dev.gentoo.org/~mpagano/genpatches" -IUSE="experimental" - -DESCRIPTION="Full sources including the Gentoo patchset for the ${KV_MAJOR}.${KV_MINOR} kernel tree" -SRC_URI="${KERNEL_URI} ${GENPATCHES_URI} ${ARCH_URI}" - -pkg_postinst() { - kernel-2_pkg_postinst - einfo "For more info on this patchset, and how to report problems, see:" - einfo "${HOMEPAGE}" -} - -pkg_postrm() { - kernel-2_pkg_postrm -} diff --git a/sys-kernel/gentoo-sources/gentoo-sources-5.4.96.ebuild b/sys-kernel/gentoo-sources/gentoo-sources-5.4.96.ebuild deleted file mode 100644 index 334c698499dc..000000000000 --- a/sys-kernel/gentoo-sources/gentoo-sources-5.4.96.ebuild +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright 1999-2021 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI="6" -ETYPE="sources" -K_WANT_GENPATCHES="base extras experimental" -K_GENPATCHES_VER="98" - -inherit kernel-2 -detect_version -detect_arch - -KEYWORDS="~alpha ~amd64 ~arm ~arm64 ~hppa ~ia64 ~mips ~ppc ~ppc64 ~s390 ~sparc ~x86" -HOMEPAGE="https://dev.gentoo.org/~mpagano/genpatches" -IUSE="experimental" - -DESCRIPTION="Full sources including the Gentoo patchset for the ${KV_MAJOR}.${KV_MINOR} kernel tree" -SRC_URI="${KERNEL_URI} ${GENPATCHES_URI} ${ARCH_URI}" - -pkg_postinst() { - kernel-2_pkg_postinst - einfo "For more info on this patchset, and how to report problems, see:" - einfo "${HOMEPAGE}" -} - -pkg_postrm() { - kernel-2_pkg_postrm -} diff --git a/sys-kernel/gentoo-sources/gentoo-sources-5.4.98.ebuild b/sys-kernel/gentoo-sources/gentoo-sources-5.4.98.ebuild new file mode 100644 index 000000000000..fcc62220bfe6 --- /dev/null +++ b/sys-kernel/gentoo-sources/gentoo-sources-5.4.98.ebuild @@ -0,0 +1,28 @@ +# Copyright 1999-2021 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +EAPI="6" +ETYPE="sources" +K_WANT_GENPATCHES="base extras experimental" +K_GENPATCHES_VER="100" + +inherit kernel-2 +detect_version +detect_arch + +KEYWORDS="~alpha ~amd64 ~arm ~arm64 ~hppa ~ia64 ~mips ~ppc ~ppc64 ~s390 ~sparc ~x86" +HOMEPAGE="https://dev.gentoo.org/~mpagano/genpatches" +IUSE="experimental" + +DESCRIPTION="Full sources including the Gentoo patchset for the ${KV_MAJOR}.${KV_MINOR} kernel tree" +SRC_URI="${KERNEL_URI} ${GENPATCHES_URI} ${ARCH_URI}" + +pkg_postinst() { + kernel-2_pkg_postinst + einfo "For more info on this patchset, and how to report problems, see:" + einfo "${HOMEPAGE}" +} + +pkg_postrm() { + kernel-2_pkg_postrm +} diff --git a/sys-kernel/gentoo-sources/gentoo-sources-5.4.99.ebuild b/sys-kernel/gentoo-sources/gentoo-sources-5.4.99.ebuild new file mode 100644 index 000000000000..0d9c210c0aae --- /dev/null +++ b/sys-kernel/gentoo-sources/gentoo-sources-5.4.99.ebuild @@ -0,0 +1,28 @@ +# Copyright 1999-2021 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +EAPI="6" +ETYPE="sources" +K_WANT_GENPATCHES="base extras experimental" +K_GENPATCHES_VER="101" + +inherit kernel-2 +detect_version +detect_arch + +KEYWORDS="~alpha ~amd64 ~arm ~arm64 ~hppa ~ia64 ~mips ~ppc ~ppc64 ~s390 ~sparc ~x86" +HOMEPAGE="https://dev.gentoo.org/~mpagano/genpatches" +IUSE="experimental" + +DESCRIPTION="Full sources including the Gentoo patchset for the ${KV_MAJOR}.${KV_MINOR} kernel tree" +SRC_URI="${KERNEL_URI} ${GENPATCHES_URI} ${ARCH_URI}" + +pkg_postinst() { + kernel-2_pkg_postinst + einfo "For more info on this patchset, and how to report problems, see:" + einfo "${HOMEPAGE}" +} + +pkg_postrm() { + kernel-2_pkg_postrm +} diff --git a/sys-kernel/gentoo-sources/metadata.xml b/sys-kernel/gentoo-sources/metadata.xml index 93b88c1e713c..6bda06198dbc 100644 --- a/sys-kernel/gentoo-sources/metadata.xml +++ b/sys-kernel/gentoo-sources/metadata.xml @@ -1,14 +1,15 @@ <?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE pkgmetadata SYSTEM "http://www.gentoo.org/dtd/metadata.dtd"> +<!DOCTYPE pkgmetadata SYSTEM "https://liguros.gitlab.io/dtd/metadata.dtd"> <pkgmetadata> -<maintainer type="project"> + <maintainer type="project"> <email>kernel@gentoo.org</email> <name>Gentoo Kernel Project</name> -</maintainer> -<use> - <flag name="experimental">Apply experimental patches; for more information, see "https://wiki.gentoo.org/wiki/Project:Kernel/Experimental".</flag> -</use> -<upstream> + </maintainer> + <upstream> <remote-id type="cpe">cpe:/o:linux:linux_kernel</remote-id> -</upstream> -</pkgmetadata> + </upstream> + <use> + <flag name="experimental">Apply experimental patches; for more information, see "https://wiki.gentoo.org/wiki/Project:Kernel/Experimental".</flag> + </use> + <origin>gentoo-staging</origin> +</pkgmetadata>
\ No newline at end of file diff --git a/sys-kernel/git-sources/metadata.xml b/sys-kernel/git-sources/metadata.xml index b51fee66c7d2..f8bdb386bfdd 100644 --- a/sys-kernel/git-sources/metadata.xml +++ b/sys-kernel/git-sources/metadata.xml @@ -1,15 +1,16 @@ <?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE pkgmetadata SYSTEM "http://www.gentoo.org/dtd/metadata.dtd"> +<!DOCTYPE pkgmetadata SYSTEM "https://liguros.gitlab.io/dtd/metadata.dtd"> <pkgmetadata> - <maintainer type="person"> - <email>mpagano@gentoo.org</email> - <name>Mike Pagano</name> - </maintainer> - <maintainer type="project"> - <email>kernel@gentoo.org</email> - <name>Gentoo Kernel Project</name> - </maintainer> - <upstream> - <remote-id type="cpe">cpe:/o:linux:linux_kernel</remote-id> - </upstream> -</pkgmetadata> + <maintainer type="person"> + <email>mpagano@gentoo.org</email> + <name>Mike Pagano</name> + </maintainer> + <maintainer type="project"> + <email>kernel@gentoo.org</email> + <name>Gentoo Kernel Project</name> + </maintainer> + <upstream> + <remote-id type="cpe">cpe:/o:linux:linux_kernel</remote-id> + </upstream> + <origin>gentoo-staging</origin> +</pkgmetadata>
\ No newline at end of file diff --git a/sys-kernel/installkernel-gentoo/metadata.xml b/sys-kernel/installkernel-gentoo/metadata.xml index 20e07cdc2be9..4864e10535a8 100644 --- a/sys-kernel/installkernel-gentoo/metadata.xml +++ b/sys-kernel/installkernel-gentoo/metadata.xml @@ -1,8 +1,10 @@ <?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE pkgmetadata SYSTEM "http://www.gentoo.org/dtd/metadata.dtd"> +<!DOCTYPE pkgmetadata SYSTEM "https://liguros.gitlab.io/dtd/metadata.dtd"> <pkgmetadata> - <maintainer type="project"> - <email>dist-kernel@gentoo.org</email> - <name>Distribution Kernel Project</name> - </maintainer> -</pkgmetadata> + <maintainer type="project"> + <email>dist-kernel@gentoo.org</email> + <name>Distribution Kernel Project</name> + </maintainer> + + <origin>gentoo-staging</origin> +</pkgmetadata>
\ No newline at end of file diff --git a/sys-kernel/installkernel-systemd-boot/metadata.xml b/sys-kernel/installkernel-systemd-boot/metadata.xml index 20e07cdc2be9..4864e10535a8 100644 --- a/sys-kernel/installkernel-systemd-boot/metadata.xml +++ b/sys-kernel/installkernel-systemd-boot/metadata.xml @@ -1,8 +1,10 @@ <?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE pkgmetadata SYSTEM "http://www.gentoo.org/dtd/metadata.dtd"> +<!DOCTYPE pkgmetadata SYSTEM "https://liguros.gitlab.io/dtd/metadata.dtd"> <pkgmetadata> - <maintainer type="project"> - <email>dist-kernel@gentoo.org</email> - <name>Distribution Kernel Project</name> - </maintainer> -</pkgmetadata> + <maintainer type="project"> + <email>dist-kernel@gentoo.org</email> + <name>Distribution Kernel Project</name> + </maintainer> + + <origin>gentoo-staging</origin> +</pkgmetadata>
\ No newline at end of file diff --git a/sys-kernel/kergen/metadata.xml b/sys-kernel/kergen/metadata.xml index 83085da60e11..a3a9194be9d7 100644 --- a/sys-kernel/kergen/metadata.xml +++ b/sys-kernel/kergen/metadata.xml @@ -1,15 +1,16 @@ <?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE pkgmetadata SYSTEM "http://www.gentoo.org/dtd/metadata.dtd"> +<!DOCTYPE pkgmetadata SYSTEM "https://liguros.gitlab.io/dtd/metadata.dtd"> <pkgmetadata> - <maintainer type="person"> - <email>jakov.smolic@sartura.hr</email> - <name>Jakov Smolic</name> - </maintainer> - <maintainer type="project"> - <email>proxy-maint@gentoo.org</email> - <name>Proxy Maintainers</name> - </maintainer> - <upstream> - <remote-id type="github">nichoski/kergen</remote-id> - </upstream> -</pkgmetadata> + <maintainer type="person"> + <email>jakov.smolic@sartura.hr</email> + <name>Jakov Smolic</name> + </maintainer> + <maintainer type="project"> + <email>proxy-maint@gentoo.org</email> + <name>Proxy Maintainers</name> + </maintainer> + <upstream> + <remote-id type="github">nichoski/kergen</remote-id> + </upstream> + <origin>gentoo-staging</origin> +</pkgmetadata>
\ No newline at end of file diff --git a/sys-kernel/kpatch/metadata.xml b/sys-kernel/kpatch/metadata.xml index 22ced41d43d1..711dd8f00a40 100644 --- a/sys-kernel/kpatch/metadata.xml +++ b/sys-kernel/kpatch/metadata.xml @@ -1,13 +1,15 @@ <?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE pkgmetadata SYSTEM "http://www.gentoo.org/dtd/metadata.dtd"> +<!DOCTYPE pkgmetadata SYSTEM "https://liguros.gitlab.io/dtd/metadata.dtd"> <pkgmetadata> - <maintainer type="person"> - <email>alicef@gentoo.org</email> - </maintainer> -<use> - <flag name="kpatch-build">Enable tools which convert a source diff patch to a patch module.</flag> - <flag name="kpatch">Enable a command-line tool which allows a user to manage a collection of patch modules.</flag> - <flag name="kmod">Enable a kernel module (.ko file) which provides an interface for the patch modules to register new functions for replacement.</flag> - <flag name="contrib">Enable contrib kpatch services files.</flag> -</use> -</pkgmetadata> + <maintainer type="person"> + <email>alicef@gentoo.org</email> + </maintainer> + + <use> + <flag name="kpatch-build">Enable tools which convert a source diff patch to a patch module.</flag> + <flag name="kpatch">Enable a command-line tool which allows a user to manage a collection of patch modules.</flag> + <flag name="kmod">Enable a kernel module (.ko file) which provides an interface for the patch modules to register new functions for replacement.</flag> + <flag name="contrib">Enable contrib kpatch services files.</flag> + </use> + <origin>gentoo-staging</origin> +</pkgmetadata>
\ No newline at end of file diff --git a/sys-kernel/linux-docs/Manifest b/sys-kernel/linux-docs/Manifest index 6f671c986215..7ab10c20e5a2 100644 --- a/sys-kernel/linux-docs/Manifest +++ b/sys-kernel/linux-docs/Manifest @@ -1,3 +1 @@ -DIST linux-4.19.114.tar.xz 103432512 BLAKE2B b35122b6ff2871053d136c5a259ca0c18b12f5b5854df791508fb8d00dd6cef7b3afe436d604c8bc4628b525a166c9d81697c4938707074d9a15d737841828d7 SHA512 a99b3eb2e458199d4143464f3e35023ed5e7fe26e09f1dcddbbd7e6709cf6fea065012a3d0d538c0d22123b97647bc0265de7f79ea7c756ed5192dc0b78a8b06 DIST linux-5.10.tar.xz 116606704 BLAKE2B b923d7b66309224f42f35f8a5fa219421b0a9362d2adacdadd8d96251f61f7230878ea297a269a7f3b3c56830f0b177e068691e1d7f88501a05653b0a13274d1 SHA512 95bc137d0cf9148da6a9d1f1a878698dc27b40f68e22c597544010a6c591ce1b256f083489d3ff45ff77753289b535135590194d88ef9f007d0ddab3d74de70e -DIST linux-5.4.39.tar.xz 109528644 BLAKE2B 359300cf9628267e5f450623d6ca5e0a918201f3f376c680412e8dad8a196ee86b5b50ccefb95c4ea9e40b0acfdffad07947e64092be4b6b0aa565068615ed12 SHA512 d95a1bace75430a8502ffd5d2225f449580b8cff3d68bd084e4792eceb18a38ae8092f223ef7834bf2b2bcc7cb21487bedc01ae8f1640db14c83bf8dfbcc7360 diff --git a/sys-kernel/linux-docs/linux-docs-4.19.114.ebuild b/sys-kernel/linux-docs/linux-docs-4.19.114.ebuild deleted file mode 100644 index 55cb8e3da43d..000000000000 --- a/sys-kernel/linux-docs/linux-docs-4.19.114.ebuild +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright 1999-2020 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI=7 -inherit toolchain-funcs - -MY_P=linux-${PV} -S=${WORKDIR}/${MY_P} - -DESCRIPTION="Developer documentation generated from the Linux kernel" -HOMEPAGE="https://www.kernel.org/" -SRC_URI="https://www.kernel.org/pub/linux/kernel/v4.x/${MY_P}.tar.xz" - -LICENSE="GPL-2" -SLOT="0" -KEYWORDS="~alpha ~amd64 ~arm ~arm64 ~hppa ~ia64 ~m68k ~ppc ~ppc64 ~s390 ~sparc ~x86" - -IUSE="" -DEPEND="<=dev-python/sphinx-2.4.4" -RDEPEND="" - -src_compile() { - local ARCH=$(tc-arch-kernel) - unset KBUILD_OUTPUT - emake htmldocs -} - -src_install() { - HTML_DOCS=( Documentation/output/. ) - einstalldocs -} diff --git a/sys-kernel/linux-docs/linux-docs-5.10.0.ebuild b/sys-kernel/linux-docs/linux-docs-5.10.17.ebuild index 2b1d4fcb3da2..08dd35006927 100644 --- a/sys-kernel/linux-docs/linux-docs-5.10.0.ebuild +++ b/sys-kernel/linux-docs/linux-docs-5.10.17.ebuild @@ -1,8 +1,9 @@ -# Copyright 1999-2020 Gentoo Authors +# Copyright 1999-2021 Gentoo Authors # Distributed under the terms of the GNU General Public License v2 EAPI=7 -inherit toolchain-funcs +PYTHON_COMPAT=( python3_{6,7,8,9,10} ) +inherit python-any-r1 toolchain-funcs MY_PV="$(ver_cut 1-2)" MY_P=linux-${MY_PV} @@ -18,17 +19,27 @@ SLOT="0" KEYWORDS="~alpha ~amd64 ~arm ~arm64 ~hppa ~ia64 ~m68k ~ppc ~ppc64 ~s390 ~sparc ~x86" IUSE="" -BDEPEND="media-libs/fontconfig" -DEPEND="dev-python/sphinx" + +DEPEND="" RDEPEND="" +BDEPEND="${PYTHON_DEPS} + dev-python/sphinx + dev-python/sphinx_rtd_theme + media-libs/fontconfig" + +src_prepare() { + default + # Fix the Python shebangs. + python_fix_shebang "${S}/Documentation/sphinx/" +} src_compile() { local ARCH=$(tc-arch-kernel) unset KBUILD_OUTPUT + HTML_DOCS=( Documentation/output/. ) emake htmldocs } src_install() { - HTML_DOCS=( Documentation/output/. ) einstalldocs } diff --git a/sys-kernel/linux-docs/linux-docs-5.4.39.ebuild b/sys-kernel/linux-docs/linux-docs-5.4.39.ebuild deleted file mode 100644 index 6047c3f394d0..000000000000 --- a/sys-kernel/linux-docs/linux-docs-5.4.39.ebuild +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright 1999-2020 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI=7 -inherit toolchain-funcs - -MY_P=linux-${PV} -S=${WORKDIR}/${MY_P} - -DESCRIPTION="Developer documentation generated from the Linux kernel" -HOMEPAGE="https://www.kernel.org/" -SRC_URI="https://www.kernel.org/pub/linux/kernel/v5.x/${MY_P}.tar.xz" - -LICENSE="GPL-2" -SLOT="0" -KEYWORDS="~alpha ~amd64 ~arm ~arm64 ~hppa ~ia64 ~m68k ~ppc ~ppc64 ~s390 ~sparc ~x86" - -IUSE="" -BDEPEND="media-libs/fontconfig" -DEPEND="<=dev-python/sphinx-2.4.4" -RDEPEND="" - -src_compile() { - local ARCH=$(tc-arch-kernel) - unset KBUILD_OUTPUT - emake htmldocs -} - -src_install() { - HTML_DOCS=( Documentation/output/. ) - einstalldocs -} diff --git a/sys-kernel/linux-docs/metadata.xml b/sys-kernel/linux-docs/metadata.xml index 8c8d3c0814eb..2b08a4786b0e 100644 --- a/sys-kernel/linux-docs/metadata.xml +++ b/sys-kernel/linux-docs/metadata.xml @@ -1,7 +1,9 @@ <?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE pkgmetadata SYSTEM "http://www.gentoo.org/dtd/metadata.dtd"> +<!DOCTYPE pkgmetadata SYSTEM "https://liguros.gitlab.io/dtd/metadata.dtd"> <pkgmetadata> - <maintainer type="person"> - <email>mpagano@gentoo.org</email> - </maintainer> -</pkgmetadata> + <maintainer type="person"> + <email>mpagano@gentoo.org</email> + </maintainer> + + <origin>gentoo-staging</origin> +</pkgmetadata>
\ No newline at end of file diff --git a/sys-kernel/linux-firmware/metadata.xml b/sys-kernel/linux-firmware/metadata.xml index b1cdaa4debb2..996fdacc5be3 100644 --- a/sys-kernel/linux-firmware/metadata.xml +++ b/sys-kernel/linux-firmware/metadata.xml @@ -1,22 +1,24 @@ <?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE pkgmetadata SYSTEM "http://www.gentoo.org/dtd/metadata.dtd"> +<!DOCTYPE pkgmetadata SYSTEM "https://liguros.gitlab.io/dtd/metadata.dtd"> <pkgmetadata> -<maintainer type="person"> - <email>chithanh@gentoo.org</email> - <name>ChÃ-Thanh Christopher Nguyá»…n</name> -</maintainer> -<maintainer type="person"> - <email>zerochaos@gentoo.org</email> - <name>Rick Farina</name> -</maintainer> -<maintainer type="project"> - <email>kernel@gentoo.org</email> - <name>Gentoo Kernel Project</name> -</maintainer> -<use> - <flag name="initramfs">Create and install initramfs for early microcode loading in /boot (only AMD for now)</flag> - <flag name="redistributable">Install also non-free (but redistributable) firmware files</flag> - <flag name="savedconfig">Allows individual selection of firmware files</flag> - <flag name="unknown-license">Install firmware files whose license is unknown</flag> -</use> -</pkgmetadata> + <maintainer type="person"> + <email>chithanh@gentoo.org</email> + <name>ChÃ-Thanh Christopher Nguyá»…n</name> + </maintainer> + <maintainer type="person"> + <email>zerochaos@gentoo.org</email> + <name>Rick Farina</name> + </maintainer> + <maintainer type="project"> + <email>kernel@gentoo.org</email> + <name>Gentoo Kernel Project</name> + </maintainer> + + <use> + <flag name="initramfs">Create and install initramfs for early microcode loading in /boot (only AMD for now)</flag> + <flag name="redistributable">Install also non-free (but redistributable) firmware files</flag> + <flag name="savedconfig">Allows individual selection of firmware files</flag> + <flag name="unknown-license">Install firmware files whose license is unknown</flag> + </use> + <origin>gentoo-staging</origin> +</pkgmetadata>
\ No newline at end of file diff --git a/sys-kernel/linux-headers/Manifest b/sys-kernel/linux-headers/Manifest index 658edf3d5078..058352380924 100644 --- a/sys-kernel/linux-headers/Manifest +++ b/sys-kernel/linux-headers/Manifest @@ -4,7 +4,7 @@ DIST gentoo-headers-4.19-1.tar.xz 4040 BLAKE2B 4ccaf4fb6bde84f0b1f29534cf2f6effc DIST gentoo-headers-4.4-1.tar.xz 6624 BLAKE2B 9cdf0c22520e413f175942c4994dd90b0fed8f72c67332a05e7ed72b901ee04594f4e4a3c0252e0a6e057d9c08c4d653387dc36cda82ce9ef8a16e7317ba9ea0 SHA512 dd8a5c627a9cd373022d7afa1beb126f15694f80452821f31fc5c1a3439635814d205bcbc873a5869946472d86cdec872a44f4870751b96d42e89893fca1b983 DIST gentoo-headers-4.9-1.tar.xz 5416 BLAKE2B 2538870b340d4e4b260ada37b0571ba770a4bf93b0f0cf78819b4bf68b8ddc43c314d7fc5d12a78bc71c9bb12306d986ae0ae74159ec7edc7deea371f6b5f015 SHA512 1069f50c58f25ceb8a13c8e53dce6a21e352e2a624da3b9a6d139939e7613e9a97226eb0173fa060ee69443c6a50b53b6d5c6d752dcaebffbe2a78f06cfbe2b6 DIST gentoo-headers-5.10-1.tar.xz 4304 BLAKE2B b5006ff13c8ef8394806919d547f1b15ac32cc4d290e8c5f5a5073f54112db194a9e743177ae54941d8a504e15b662751258259183c47c574936744d7c51b405 SHA512 3154558df20e3a8821af23b2a585eaccb6c40877850b1cf752c435c170f7f322a48e77cee63bcc061b69aff8602987f4506d803c73f394929716295aface4f3d -DIST gentoo-headers-5.4-1.tar.xz 4720 BLAKE2B 74c1f47d8ad77a2df36db005adb25f81ba6128037357dfc1b6d65deb2a5d3e53d2f3b5af60098c3f3f514f85e53bef4c906fb182101d35ae32d73a5af417a583 SHA512 9d83a68c6e9a463bc27efd469a79d58690bdd0fd93d77c1de29938d7192bb546b63d9acad9633e6e043d0089638e67ee39382e987d7403c43d3f3edc83c5ccba +DIST gentoo-headers-5.11-1.tar.xz 3624 BLAKE2B 378eed88876a911e47ea08563f4fea840bfc11def916bce47c3268029ba926ced06e621edb53c9248fed4de547cfb447cc25da2222a864983a746fec06fb60d9 SHA512 896cacd48e9965ea724c13ca5a69b8c9aa4f47e631b539c71e4936462d50da3d34863e7419217ba434bcd97ebf8b05d2fc65bc9e60a584a108e864f4cf7f02fc DIST gentoo-headers-5.4-2.tar.xz 11352 BLAKE2B 0ff989dbfff9070c291efe1a8b925462770e71d0c3faeb2e53581dcce02abe45969ec293a7293b6d843f483927b15f4accc1f24ee4966483164e8f72727cfad8 SHA512 b460e4d00bdd9ec2ecf229f3b2dde7c6468f775399ba6a49fa0533c0688628c7b27d83835c21eab07407fd98c220043cd1b20e37cc4decbd08a3f2fd9cf6c2be DIST gentoo-headers-5.9-1.tar.xz 4304 BLAKE2B 5dda91dac529cf3afca220d0ec323f679eae00e850e127ca6fb7dd42313afe7d4e2b23860a5b58673c070456e1ebd6b0d48efd681a764eef1bab996de579fd11 SHA512 3522d25e4d13f703e69a7e8da1813b38c8977821363b56af1988d78c446087dea4c3499283a2fdef2dc000fde29b945abb821a01f53ac0ac6c2b551699b3b18c DIST gentoo-headers-base-3.18.tar.xz 3776668 BLAKE2B 837a675ecf05ec270549d0ba6b9dcb98fb0e40f22007ebfa3e430152b7149dcfa29c8bbe38c737add07f75642234f1633c1d5ae0170788e8d4f765faf00bbdbe SHA512 6615c604e5e618d26fff5a61691f7827bb05be9790db6c9f8e16e3842bce8f056f9928f85ae5714710b75743b0d0804faba4ba9c76e934e1de22dc03ef6d5535 @@ -13,5 +13,6 @@ DIST gentoo-headers-base-4.19.tar.xz 7956220 BLAKE2B 5b6868188b6cb505556b8f30797 DIST gentoo-headers-base-4.4.tar.xz 3911752 BLAKE2B 5031ecd48b99cb0c9c35ca935fa6a62cc36c076bab193ec397fc0d543170f29c6d5a0827a2ea5517eb68fc838819cbe3e5abd125bb920992492369d5e5c1e7cb SHA512 1cd3de58ff790c3730bea38138c7a45ef95d04288c69ffeabebb884fab3add13bd9c99785ddd87a3ee467a0e1b1cdc457bbd28da349e7c178b4d2374c5fb78a3 DIST gentoo-headers-base-4.9.tar.xz 4052748 BLAKE2B e279954c56170fbfa4ebae8dade731825b3d5f0cd5d73a5b33cd93a9c8f5fa140e14edf0d5ac26a452fe8a61b16fdcc851f5329f56e4c8dcf4472a995de44c4c SHA512 a03418cfba7fa4531279d9122411af3e285e962506e8df9279fbbb27ae08a4e30725bd1cf03f48ad523f61f2889195e6c844fa4c7b4ef2f828baf47ef402abfa DIST linux-5.10.tar.xz 116606704 BLAKE2B b923d7b66309224f42f35f8a5fa219421b0a9362d2adacdadd8d96251f61f7230878ea297a269a7f3b3c56830f0b177e068691e1d7f88501a05653b0a13274d1 SHA512 95bc137d0cf9148da6a9d1f1a878698dc27b40f68e22c597544010a6c591ce1b256f083489d3ff45ff77753289b535135590194d88ef9f007d0ddab3d74de70e +DIST linux-5.11.tar.xz 117619104 BLAKE2B 81300c27bd5476387a83123aaeb4163c73eb61e9245806c23660cb5e6a4fa88ffc9def027031335fa0270fc4080506cd415990014364e3a98b9d2e8c58a29524 SHA512 a567ec133018bb5ec00c60281479b466c26e02137a93a9c690e83997947df02b6fd94e76e8df748f6d70ceb58a19bacc3b1467de10b7a1fad2763db32b3f1330 DIST linux-5.4.tar.xz 109441440 BLAKE2B 193bc4a3147e147d5529956164ec4912fad5d5c6fb07f909ff1056e57235834173194afc686993ccd785c1ff15804de0961b625f3008cca0e27493efc8f27b13 SHA512 9f60f77e8ab972b9438ac648bed17551c8491d6585a5e85f694b2eaa4c623fbc61eb18419b2656b6795eac5deec0edaa04547fc6723fbda52256bd7f3486898f DIST linux-5.9.tar.xz 115507140 BLAKE2B e8d11472d63a9f8409ca12a2e8c97c6963a3d4516b5a398b627d6ece565584526f9b5a1377a2fa4bd184c09c7db94c987428bc5d52df0c788464a67e9e8d6dcb SHA512 d3d92ce4246bad74c9a784212f160d98449b1e8793970c2c308276568d852b8effe0528686bdb87d55d691f09a826abf7938d69bdd4759ce65ddd5c05ffe4eca diff --git a/sys-kernel/linux-headers/linux-headers-5.10.ebuild b/sys-kernel/linux-headers/linux-headers-5.10.ebuild index adf8f695fe67..2d58b2ba544f 100644 --- a/sys-kernel/linux-headers/linux-headers-5.10.ebuild +++ b/sys-kernel/linux-headers/linux-headers-5.10.ebuild @@ -15,7 +15,7 @@ SRC_URI="${KERNEL_URI} ${PATCH_VER:+https://dev.gentoo.org/~slyfox/distfiles/gentoo-headers-${PATCH_PV}-${PATCH_VER}.tar.xz} " -KEYWORDS="~alpha ~amd64 ~arm ~arm64 hppa ~ia64 ~m68k ~mips ~ppc ppc64 ~riscv ~s390 sparc ~x86 ~amd64-linux ~x86-linux" +KEYWORDS="~alpha amd64 ~arm ~arm64 hppa ~ia64 ~m68k ~mips ppc ppc64 ~riscv ~s390 sparc x86 ~amd64-linux ~x86-linux" DEPEND="app-arch/xz-utils net-misc/rsync diff --git a/sys-kernel/linux-headers/linux-headers-5.4.ebuild b/sys-kernel/linux-headers/linux-headers-5.11.ebuild index d89a67aa0507..e30b503134aa 100644 --- a/sys-kernel/linux-headers/linux-headers-5.4.ebuild +++ b/sys-kernel/linux-headers/linux-headers-5.11.ebuild @@ -1,4 +1,4 @@ -# Copyright 1999-2020 Gentoo Authors +# Copyright 1999-2021 Gentoo Authors # Distributed under the terms of the GNU General Public License v2 EAPI="6" @@ -15,7 +15,7 @@ SRC_URI="${KERNEL_URI} ${PATCH_VER:+https://dev.gentoo.org/~slyfox/distfiles/gentoo-headers-${PATCH_PV}-${PATCH_VER}.tar.xz} " -KEYWORDS="~alpha amd64 arm arm64 hppa ~ia64 ~m68k ~mips ppc ppc64 ~riscv s390 sparc x86 ~amd64-linux ~x86-linux" +KEYWORDS="~alpha ~amd64 ~arm ~arm64 ~hppa ~ia64 ~m68k ~mips ~ppc ~ppc64 ~riscv ~s390 ~sparc ~x86 ~amd64-linux ~x86-linux" DEPEND="app-arch/xz-utils net-misc/rsync @@ -43,5 +43,5 @@ src_install() { } src_test() { - emake ARCH=$(tc-arch-kernel) headers_check + emake headers_check ${xmakeopts} } diff --git a/sys-kernel/linux-headers/metadata.xml b/sys-kernel/linux-headers/metadata.xml index fcf3f047e8b4..87a9e39d0491 100644 --- a/sys-kernel/linux-headers/metadata.xml +++ b/sys-kernel/linux-headers/metadata.xml @@ -1,11 +1,12 @@ <?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE pkgmetadata SYSTEM "http://www.gentoo.org/dtd/metadata.dtd"> +<!DOCTYPE pkgmetadata SYSTEM "https://liguros.gitlab.io/dtd/metadata.dtd"> <pkgmetadata> -<maintainer type="project"> + <maintainer type="project"> <email>toolchain@gentoo.org</email> <name>Gentoo Toolchain Project</name> -</maintainer> -<upstream> + </maintainer> + <upstream> <remote-id type="cpe">cpe:/o:linux:linux_kernel</remote-id> -</upstream> -</pkgmetadata> + </upstream> + <origin>gentoo-staging</origin> +</pkgmetadata>
\ No newline at end of file diff --git a/sys-kernel/liquorix-sources/Manifest b/sys-kernel/liquorix-sources/Manifest new file mode 100644 index 000000000000..cefc957b9aa8 --- /dev/null +++ b/sys-kernel/liquorix-sources/Manifest @@ -0,0 +1,8 @@ +AUX 4567_distro-Gentoo-Kconfig.patch 4621 BLAKE2B 07a79d4a95b93e57402358dcc5d712d607fe273cee9b9523c37a79ee1d1b8d56542757b79e200b59292a0da69d8865d6e86116e86e3cc8552988ec83fa71d70d SHA512 b1306f9d6b5ad26e2ade5810a7b724ab83b5788c5afc4460c95f9259542d9ac5f0c7b5f2546db97a0baa3d7ba45ab536247eab599fb2cd17316ba60c997658f7 +DIST linux-5.10.tar.xz 116606704 BLAKE2B b923d7b66309224f42f35f8a5fa219421b0a9362d2adacdadd8d96251f61f7230878ea297a269a7f3b3c56830f0b177e068691e1d7f88501a05653b0a13274d1 SHA512 95bc137d0cf9148da6a9d1f1a878698dc27b40f68e22c597544010a6c591ce1b256f083489d3ff45ff77753289b535135590194d88ef9f007d0ddab3d74de70e +DIST linux-5.11.tar.xz 117619104 BLAKE2B 81300c27bd5476387a83123aaeb4163c73eb61e9245806c23660cb5e6a4fa88ffc9def027031335fa0270fc4080506cd415990014364e3a98b9d2e8c58a29524 SHA512 a567ec133018bb5ec00c60281479b466c26e02137a93a9c690e83997947df02b6fd94e76e8df748f6d70ceb58a19bacc3b1467de10b7a1fad2763db32b3f1330 +DIST liquorix-sources-5.10.17_p1.tar.gz 1096189 BLAKE2B de63cef509a2b45ac4ca2410ec3133a8826c3f1682877ebc15a04ee827709e342b216df2181b07198e36de8d7a8a096503bee0ab024576eaf12cec61ad9e8244 SHA512 93de2a0bc01537f9d9e5f117257c5d6c7ec8c16e5ad7ae8c350dd776c774190fc90add3361a15889b95bd24b3ca9d2a192bd4c3fb9a7431de61ea06bc3801792 +DIST liquorix-sources-5.11.2_p2.tar.gz 470518 BLAKE2B 0c70bd844f6d7f2e65311ef1c86a5838a1d706b8ab8bd7eca13b9d5c9e64d66e81e5de8632571e31aa15baf42a41f66da9ccefd8a4a209d3342b1fc12ecc8ad4 SHA512 45674b1170dfa65ee9382ed59b1bfffa4f4cdfe295af41052c1e933e20dfbb61c45a30c0d1d647c16cb544d29a7e243a3923289ff447f646b00f30f7395ba70b +EBUILD liquorix-sources-5.10.17_p1.ebuild 1817 BLAKE2B 63fe896688a91f8ead46582f5f715a866f6ed24a0e5a4ddaaef208fab71cd0c3e728b1ad0745f2a040f72780ed57f2b9953f566f427ac405f64ea208adea26f5 SHA512 e58c7a3b98141e0950888bc837905e7ca27ea323ba43a4a0307a9ac4cad82e729cd7546ef9a9d479671f8e66dd60ddded658aeb96bd23f57e73ff2d0920bbd05 +EBUILD liquorix-sources-5.11.2_p2.ebuild 1816 BLAKE2B 4acf1a21a027e7f1603605c97117eb1f2e5b6e854c01f00eefaecf610c930431f133d2d61e2e792ad8a1ee2b58adccd154611e17fe12016d7cce0d2d38a5e19c SHA512 fecffefcdd07628ec4be584f4c47d184137aeba9c2d5f7732d026b1321846a19a9cf2dae64506972376d6df3caaacfbc0d4e0fb5a19943b2e3d34cb911d7c5bc +MISC metadata.xml 227 BLAKE2B dd2ac5f8e910fdcd398041e812b41ae620497e9506eb716f37a685632b152087ca6e3e8b8ad0c40fc235dddbb383c7dd091e6d12ac767607cec031c1e98f3692 SHA512 ba8bbc456d19901db460bec6512ffb1e3ab905978e7f4bda11f9dd0ec8761faacde2c9487771b30ff5863febe20ccea294bc1731763eab2f8a2bb2af5d6e1ae2 diff --git a/sys-kernel/cairn-sources/files/5.10.14/gentoo-patches/4567_distro-Gentoo-Kconfig.patch b/sys-kernel/liquorix-sources/files/4567_distro-Gentoo-Kconfig.patch index e754a3e6e459..ecff093a3843 100644 --- a/sys-kernel/cairn-sources/files/5.10.14/gentoo-patches/4567_distro-Gentoo-Kconfig.patch +++ b/sys-kernel/liquorix-sources/files/4567_distro-Gentoo-Kconfig.patch @@ -1,14 +1,14 @@ ---- a/Kconfig 2020-04-15 11:05:30.202413863 -0400 -+++ b/Kconfig 2020-04-15 10:37:45.683952949 -0400 +--- a/Kconfig 2019-08-07 08:33:43.669367779 -0400 ++++ b/Kconfig 2019-08-07 08:34:29.669657000 -0400 @@ -32,3 +32,5 @@ source "lib/Kconfig" source "lib/Kconfig.debug" source "Documentation/Kconfig" + +source "distro/Kconfig" ---- /dev/null 2020-09-24 03:06:47.590000000 -0400 -+++ b/distro/Kconfig 2020-09-24 11:31:29.403150624 -0400 -@@ -0,0 +1,158 @@ +--- /dev/null 2019-09-18 03:31:42.730171526 -0400 ++++ b/distro/Kconfig 2019-09-18 13:28:03.170769896 -0400 +@@ -0,0 +1,149 @@ +menu "Gentoo Linux" + +config GENTOO_LINUX @@ -65,7 +65,6 @@ + select NET_NS + select PID_NS + select SYSVIPC -+ select UTS_NS + + help + This enables options required by various Portage FEATURES. @@ -92,12 +91,7 @@ + depends on GENTOO_LINUX + + select BINFMT_SCRIPT -+ select CGROUPS -+ select EPOLL + select FILE_LOCKING -+ select INOTIFY_USER -+ select SIGNALFD -+ select TIMERFD + + help + The init system is the first thing that loads after the kernel booted. @@ -120,8 +114,6 @@ + + select AUTOFS4_FS + select BLK_DEV_BSG -+ select BPF_SYSCALL -+ select CGROUP_BPF + select CGROUPS + select CHECKPOINT_RESTORE + select CRYPTO_HMAC @@ -145,7 +137,6 @@ + select TIMERFD + select TMPFS_POSIX_ACL + select TMPFS_XATTR -+ select USER_NS + + select ANON_INODES + select BLOCK diff --git a/sys-kernel/liquorix-sources/liquorix-sources-5.10.17_p1.ebuild b/sys-kernel/liquorix-sources/liquorix-sources-5.10.17_p1.ebuild new file mode 100644 index 000000000000..d5b19e52e5a1 --- /dev/null +++ b/sys-kernel/liquorix-sources/liquorix-sources-5.10.17_p1.ebuild @@ -0,0 +1,67 @@ +# Copyright 2020-2021 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +EAPI=6 +ETYPE="sources" + +inherit eapi7-ver + +K_USEPV="yes" +UNIPATCH_STRICTORDER="yes" +K_SECURITY_UNSUPPORTED="1" +GIT_COMMIT="5.10-25" + +CKV="$(ver_cut 1-2)" +ETYPE="sources" + +inherit kernel-2 +#detect_version +K_NOSETEXTRAVERSION="don't_set_it" + +DESCRIPTION="The Liquorix Kernel Sources v5.x" +HOMEPAGE="https://liquorix.net/" +LIQUORIX_VERSION="${GIT_COMMIT/_p[0-9]*}" +LIQUORIX_FILE="${P}.tar.gz" +LIQUORIX_URI="https://github.com/damentz/liquorix-package/archive/${LIQUORIX_VERSION}.tar.gz -> ${LIQUORIX_FILE}" +SRC_URI="${KERNEL_URI} ${LIQUORIX_URI}"; + +KEYWORDS="-* ~amd64 ~ppc ~ppc64 ~x86" +IUSE="" + +KV_FULL="${PVR/_p/-pf}" +S="${WORKDIR}"/linux-"${KV_FULL}" + +pkg_setup(){ + ewarn + ewarn "${PN} is *not* supported by the Gentoo Kernel Project in any way." + ewarn "If you need support, please contact the Liquorix developers directly." + ewarn "Do *not* open bugs in Gentoo's bugzilla unless you have issues with" + ewarn "the ebuilds. Thank you." + ewarn + kernel-2_pkg_setup +} + +src_unpack() { + unpack "${LIQUORIX_FILE}" + kernel-2_src_unpack +} + +src_prepare(){ + # Taken from + # https://github.com/damentz/liquorix-package/blob/5.6/linux-liquorix/debian/patches/series + local lqx_patches="${WORKDIR}/liquorix-package-${GIT_COMMIT}/linux-liquorix/debian/patches" + eapply "${lqx_patches}/zen/v${PV/_p/-lqx}.patch" + + # Probably don't need these. + eapply "${lqx_patches}/debian/version.patch" + eapply "${lqx_patches}/debian/uname-version-timestamp.patch" + eapply "${lqx_patches}/debian/kernelvariables.patch" + + # Adds config options for OpenRC/Systemd + eapply "${FILESDIR}"/4567_distro-Gentoo-Kconfig.patch + + eapply_user +} + +K_EXTRAEINFO="For more info on liquorix-sources and details on how to report problems, see: \ +${HOMEPAGE}." diff --git a/sys-kernel/liquorix-sources/liquorix-sources-5.11.2_p2.ebuild b/sys-kernel/liquorix-sources/liquorix-sources-5.11.2_p2.ebuild new file mode 100644 index 000000000000..16699a32887a --- /dev/null +++ b/sys-kernel/liquorix-sources/liquorix-sources-5.11.2_p2.ebuild @@ -0,0 +1,67 @@ +# Copyright 2020-2021 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +EAPI=6 +ETYPE="sources" + +inherit eapi7-ver + +K_USEPV="yes" +UNIPATCH_STRICTORDER="yes" +K_SECURITY_UNSUPPORTED="1" +GIT_COMMIT="5.11-4" + +CKV="$(ver_cut 1-2)" +ETYPE="sources" + +inherit kernel-2 +#detect_version +K_NOSETEXTRAVERSION="don't_set_it" + +DESCRIPTION="The Liquorix Kernel Sources v5.x" +HOMEPAGE="https://liquorix.net/" +LIQUORIX_VERSION="${GIT_COMMIT/_p[0-9]*}" +LIQUORIX_FILE="${P}.tar.gz" +LIQUORIX_URI="https://github.com/damentz/liquorix-package/archive/${LIQUORIX_VERSION}.tar.gz -> ${LIQUORIX_FILE}" +SRC_URI="${KERNEL_URI} ${LIQUORIX_URI}"; + +KEYWORDS="-* ~amd64 ~ppc ~ppc64 ~x86" +IUSE="" + +KV_FULL="${PVR/_p/-pf}" +S="${WORKDIR}"/linux-"${KV_FULL}" + +pkg_setup(){ + ewarn + ewarn "${PN} is *not* supported by the Gentoo Kernel Project in any way." + ewarn "If you need support, please contact the Liquorix developers directly." + ewarn "Do *not* open bugs in Gentoo's bugzilla unless you have issues with" + ewarn "the ebuilds. Thank you." + ewarn + kernel-2_pkg_setup +} + +src_unpack() { + unpack "${LIQUORIX_FILE}" + kernel-2_src_unpack +} + +src_prepare(){ + # Taken from + # https://github.com/damentz/liquorix-package/blob/5.6/linux-liquorix/debian/patches/series + local lqx_patches="${WORKDIR}/liquorix-package-${GIT_COMMIT}/linux-liquorix/debian/patches" + eapply "${lqx_patches}/zen/v${PV/_p/-lqx}.patch" + + # Probably don't need these. + eapply "${lqx_patches}/debian/version.patch" + eapply "${lqx_patches}/debian/uname-version-timestamp.patch" + eapply "${lqx_patches}/debian/kernelvariables.patch" + + # Adds config options for OpenRC/Systemd + eapply "${FILESDIR}"/4567_distro-Gentoo-Kconfig.patch + + eapply_user +} + +K_EXTRAEINFO="For more info on liquorix-sources and details on how to report problems, see: \ +${HOMEPAGE}." diff --git a/sys-kernel/liquorix-sources/metadata.xml b/sys-kernel/liquorix-sources/metadata.xml new file mode 100644 index 000000000000..dd23ea1018d0 --- /dev/null +++ b/sys-kernel/liquorix-sources/metadata.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE pkgmetadata SYSTEM "http://www.gentoo.org/dtd/metadata.dtd"> +<pkgmetadata> + <maintainer type="person"> + <email>jmcclain2020@protonmail.com</email> + </maintainer> +</pkgmetadata> diff --git a/sys-kernel/mips-sources/Manifest b/sys-kernel/mips-sources/Manifest index ae956ca3af1f..31fb2c77cbf1 100644 --- a/sys-kernel/mips-sources/Manifest +++ b/sys-kernel/mips-sources/Manifest @@ -5,6 +5,6 @@ DIST mips-sources-4.14.0-patches-v2.tar.xz 287560 BLAKE2B 9fb6b07dcb0336be95c863 DIST mips-sources-4.19.0-patches-v2.tar.xz 289940 BLAKE2B ffca5540cbd663ed3eab3f748dec7727ca6f1abe11ce107fe1780b8191175b77d8c59f70d5e9254f01c43d507f805f081f15bd150f66da1d11e2a91715dcb038 SHA512 c67ac8c6f041a96348a5a6023919fc5586b70b6c3aa52777945d5f1a831e6bd24d867c0318034cf304a3c8f4c6ff0d2af3611b3ad2bc476f3bf3762d39a215f8 DIST mips-sources-5.4-patches-v3.tar.xz 195616 BLAKE2B 389d5d86265d14961d739f13623ed5a1efa0b4e6a649816eccb41f947186316560473a1ec0222d1db84ce8cc1e0c8dadb4dd499b941e37de201571cc37359e74 SHA512 4181b776ec17526c246516d0d2fb2737f12a214a18c2526085a71174a12e30735d7b497d9cba658a2579c05055a74191ebbdd658003c7b28265d49915bc94b58 DIST mipsgit-4.14.0-20180128.diff.xz 1008 BLAKE2B 2a317ff97aab096883680c6b653e993aee31994e6caec52c52dfbbb61f1dc1f25d03ebd3182fa122923a67aeee0aa598b36e603692333e4c9ccdc741fd456d96 SHA512 378deb1bc1d10a6b4912e5e4a0d6fcab28952e2e59c35fc879601841cf8160081b318a2598ef74db225e95f0f26483f6b9a56a348811b1ee7b8934391dd271ae -DIST patch-4.14.213.xz 4083152 BLAKE2B d99d56454b23101cfe0fdbaa9284d1d000d29f73d782783a71b27ec57fd2a19ddeaa24702bb072566d222e3b554c8719b1025cefc243dd1c826793671865cb4b SHA512 dd5cabd8f2422d642bd953e398b2b3fbc11456f8f3ab7846713e27d0339c85e93cd97ce436986b3d6518c4a3e9f8449d9a53e1c6215273cb2b56688adcf2e075 -DIST patch-4.19.163.xz 3661280 BLAKE2B 182cdeec98f3c4a5ec057e3f286f8019ff5cc22d23863a08b820aeb8404fd34afae913c0bdb06c4d4f571c9146cd13778eedba840e2920f9af2348c5c38fad12 SHA512 6302649e09aae6e35d7963de5dbe4edf9e9fe5439e67188bd604929752853e5e57e31c140e76db87f2cf79345ca254e4b9a893489942c87159aea62746e10663 -DIST patch-5.4.85.xz 2424448 BLAKE2B 21d66e5642782d20a620544397f89f2c5fb85c8261582c4cf915623b564973a2e36d7d933c0b088f88c5198a3f889e24f1bf58ba17a0cb615f2223c47855bb7c SHA512 32c2a9e4555d978b05bce821ced22f99b86be97bec50314716f374c3cc4a74da4807bf7735c038e03af2998d85092db770115acf584ed3f6f9c1d8924f159c97 +DIST patch-4.14.221.xz 4125144 BLAKE2B 474f8791e2b59f1524681e70300d5a9543a4b56fb7affbd02a22d67d4df2632c7aa37a73d032697b3b10291671efd96f5eaf13c4632c05801a4a7cac99a4c219 SHA512 fd332b076ac0231ea4b3806bd6cb58f0b66bd9317ae352fb6f90856e92df5cc96d2c89bc8c44001f2f34ea98b43fbbe8b8eae0abe2249fe561b8dd4a2c76bcb5 +DIST patch-4.19.176.xz 3779956 BLAKE2B 136d927a3254a8214b7c0766971b4585e7a08d13ac4b5e7160f24a1a0d687dfe234632b873aac3cff9fd596b9191acee202e88b7f5d7e139a3284aa544983f0a SHA512 9bb51df1822242aee8340b8d54b5d1eb9bab8c0fff37a5b671f2ab7d10e5b3f1bd9f6a7e13af600434cc406a42b6638a5659cc056917c44a158bf243b5383146 +DIST patch-5.4.99.xz 2620252 BLAKE2B e6b965a159fd019e95207eab66f0cee6ed35334d634594c4d8a433cfdb4be6b8274bc3794754c27ab9dc52223b6760c303ba5a9a2624b7799fb4d831ba49c8df SHA512 00b9128b450c86742ecdfd9656d2527625cd257e95dd18bf032d0c9325e5eb67dc65e30b30b95e1dd00f590eb6ea85710d9c43b2d92fe03e93d761b34b7cc498 diff --git a/sys-kernel/mips-sources/metadata.xml b/sys-kernel/mips-sources/metadata.xml index 83fb9fad8bd8..4d2a44d14581 100644 --- a/sys-kernel/mips-sources/metadata.xml +++ b/sys-kernel/mips-sources/metadata.xml @@ -1,17 +1,18 @@ <?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE pkgmetadata SYSTEM "http://www.gentoo.org/dtd/metadata.dtd"> +<!DOCTYPE pkgmetadata SYSTEM "https://liguros.gitlab.io/dtd/metadata.dtd"> <pkgmetadata> - <maintainer type="project"> - <email>mips@gentoo.org</email> - <name>Mips Team</name> - </maintainer> - <use> - <flag name="ip27">Enables additional support for SGI Origin (IP27)</flag> - <flag name="ip28">Enables additional support for SGI Indigo2 Impact R10000 (IP28)</flag> - <flag name="ip30">Enables support for SGI Octane (IP30, 'Speedracer')</flag> - <flag name="experimental">Apply experimental (80xx) patches.</flag> - </use> - <upstream> - <remote-id type="cpe">cpe:/o:linux:linux_kernel</remote-id> - </upstream> -</pkgmetadata> + <maintainer type="project"> + <email>mips@gentoo.org</email> + <name>Mips Team</name> + </maintainer> + <upstream> + <remote-id type="cpe">cpe:/o:linux:linux_kernel</remote-id> + </upstream> + <use> + <flag name="ip27">Enables additional support for SGI Origin (IP27)</flag> + <flag name="ip28">Enables additional support for SGI Indigo2 Impact R10000 (IP28)</flag> + <flag name="ip30">Enables support for SGI Octane (IP30, 'Speedracer')</flag> + <flag name="experimental">Apply experimental (80xx) patches.</flag> + </use> + <origin>gentoo-staging</origin> +</pkgmetadata>
\ No newline at end of file diff --git a/sys-kernel/mips-sources/mips-sources-4.14.213.ebuild b/sys-kernel/mips-sources/mips-sources-4.14.221.ebuild index 9f9dc8ee3367..64bd5b08b301 100644 --- a/sys-kernel/mips-sources/mips-sources-4.14.213.ebuild +++ b/sys-kernel/mips-sources/mips-sources-4.14.221.ebuild @@ -1,4 +1,4 @@ -# Copyright 1999-2020 Gentoo Authors +# Copyright 1999-2021 Gentoo Authors # Distributed under the terms of the GNU General Public License v2 # EAPI Version diff --git a/sys-kernel/mips-sources/mips-sources-4.19.163.ebuild b/sys-kernel/mips-sources/mips-sources-4.19.176.ebuild index 076bf3615ae8..4f2c0e512d0b 100644 --- a/sys-kernel/mips-sources/mips-sources-4.19.163.ebuild +++ b/sys-kernel/mips-sources/mips-sources-4.19.176.ebuild @@ -1,4 +1,4 @@ -# Copyright 1999-2020 Gentoo Authors +# Copyright 1999-2021 Gentoo Authors # Distributed under the terms of the GNU General Public License v2 # EAPI Version diff --git a/sys-kernel/mips-sources/mips-sources-5.4.85.ebuild b/sys-kernel/mips-sources/mips-sources-5.4.99.ebuild index bc279adfe801..1a6b743ec994 100644 --- a/sys-kernel/mips-sources/mips-sources-5.4.85.ebuild +++ b/sys-kernel/mips-sources/mips-sources-5.4.99.ebuild @@ -1,4 +1,4 @@ -# Copyright 1999-2020 Gentoo Authors +# Copyright 1999-2021 Gentoo Authors # Distributed under the terms of the GNU General Public License v2 # EAPI Version diff --git a/sys-kernel/opensuse-sources/metadata.xml b/sys-kernel/opensuse-sources/metadata.xml index 36b446b63544..35b97c0ead43 100644 --- a/sys-kernel/opensuse-sources/metadata.xml +++ b/sys-kernel/opensuse-sources/metadata.xml @@ -1,11 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE pkgmetadata SYSTEM "https://liguros.gitlab.io/dtd/metadata.dtd"> <pkgmetadata> - <herd>funtoo</herd> - <maintainer> - <email>dev@liguros.net</email> - </maintainer> - <use> - <flag name='binary'>Builds and installs kernel automatically</flag> - <flag name='rt'>Applies the CONFIG_PREEMPT_RT patch series</flag> - </use> - <origin>ports</origin> -</pkgmetadata> + <maintainer type="project"> + <email>dev@liguros.net</email> + <name>Development</name> + </maintainer> + + <use> + <flag name="binary">Builds and installs kernel automatically</flag> + <flag name="rt">Applies the CONFIG_PREEMPT_RT patch series</flag> + </use> + <origin>ports</origin> +</pkgmetadata>
\ No newline at end of file diff --git a/sys-kernel/opensuse-sources/opensuse-sources-5.6.2.ebuild b/sys-kernel/opensuse-sources/opensuse-sources-5.6.2.ebuild index 1123fee01858..988b2bc07fe6 100644 --- a/sys-kernel/opensuse-sources/opensuse-sources-5.6.2.ebuild +++ b/sys-kernel/opensuse-sources/opensuse-sources-5.6.2.ebuild @@ -1,3 +1,4 @@ +# Copyright 2020-2021 LiGurOs Authors # Distributed under the terms of the GNU General Public License v2 # Documentation for adding new kernels -- do not remove! diff --git a/sys-kernel/pf-sources/Manifest b/sys-kernel/pf-sources/Manifest index 3372b1b6c961..409c3d3592b1 100644 --- a/sys-kernel/pf-sources/Manifest +++ b/sys-kernel/pf-sources/Manifest @@ -1,20 +1,13 @@ DIST genpatches-5.10-1.base.tar.xz 3840 BLAKE2B 08ac1f83dc9a1cfc1d4cf0a3a5ab4c9d4686a80348247ec7cd1da6e49db92d6932a1864113f2631d5528a4ba732945b2afe73d03061bd3c532b3d1e4d9571999 SHA512 04356093c4df6a7ee0876b89be5b90f8bc90c920628e5fe69b5787ce82e003be05eaac142310f10f32d0549a6676af846734ae4ac188c2b96c2eca2cb0a6f4b0 DIST genpatches-5.10-1.extras.tar.xz 1768 BLAKE2B e99d5d2137d5752845ba8284a0dd57620851c3620603e871973af5841b54e9bfdde92ea2408ddedb55355f2c954c80641b06098060043916d2483e10cfb8293a SHA512 0034e5ab57cccb2e969a3b9e1f674614ca853779c552c37be9c5afb0a37112bf8f2c30e1b21832d56320c70c1d622081b60369c6a86fa737a23c3ed953267453 -DIST genpatches-5.10-3.base.tar.xz 5524 BLAKE2B 3811736bbb95e9f4b9745cc0f02bd1c183bde82e4c10924a72cb1b4a0fdd3703cdc591c2e8fe266c3ffd29ef65258bf57ac314318c01d73dd08a17e449108c60 SHA512 50d8e1c26600657f76a4aefc4cbb7aa7db1b9265db77344769ac33bc988d692d84f4d7d7b9055ed2278c6e8c195902b6561ccfede741c7a77c42cfec9dd3ed56 -DIST genpatches-5.10-3.extras.tar.xz 1772 BLAKE2B a5453e4e9187373c7dc1b2e77a7877a53eaf3c0cfb578b199d93715dae78cb47c72e644e4de50e0837712b8a61ef151b4f6cd61a7d85de306bbe8d5dfdda4af6 SHA512 394220858394f89a1beadaaa1bbc86049f1bfd8e850c72fd7e27d0db23b4600d148a602fb4c68a3399e6a8fef3a7e0d45ae0c946976dce7418f0547841a4d21d +DIST genpatches-5.11-1.base.tar.xz 3440 BLAKE2B eb1e9a9f2060023cb410bf3db8c4f4fe283eff47f545a434dfc1edb98aa513940f30a2a88566422192b79f7ab36c607b9bc63253c067070d9a479d6318fd34b3 SHA512 a862fe33272bb6b0e4095c862c74361f015fc57316b9dbbdf2782f2e57c131fbe7fe9b9ba81c3d5a7d71788f2d56abdbd28f1c7571973c3f378cd05199c0421f +DIST genpatches-5.11-1.extras.tar.xz 1772 BLAKE2B e6f8eae67db54099424f33e17bbfa66d36ae44c98d5f58969634a709a4b949a675a7ec1053eab4db4f745513d9730b68439ecf888e92f0fc9ef369822b39a388 SHA512 cf9d0ee27618b1b49322cefda8d85f66fd94820b9902948c8dd9a33d4e14acf511e7aabf611df5e070a4011e06d80164a512d124f5686b5b16fd81409098d8eb DIST genpatches-5.9-1.base.tar.xz 4004 BLAKE2B 8a4577d42262fa901186acc60d28221d00e5c9140886705f018d9989f818d96ee4d9a6586b292e7b1d945bea9e2408e3161a73e0999defe1b7f99d0a339eb7be SHA512 d6ba1051f9561aa30d7b196336c34930285d613e8119b152f1d6cc447cb22db5ac07c25f89d4ceddf58c9370c42699d0250a31449be2da3c591896b0c87d8718 DIST genpatches-5.9-1.extras.tar.xz 1764 BLAKE2B 32d29f0448aef113ba9c9591c5d3b671d00d07abde9f35f365b48168887913bb2da95a8a52b852453307cabb111115a26178be4cbcc016e53a26a31f783a9df7 SHA512 df007dc98c1acdd31773f7dcf8aeb22812aa55e5593e8509b6a8762f2dcf06c95d69ad7cdce992e7a5fe730754bef26242acdc4e4da51ee29206fabb86c9cb0e DIST linux-5.10.tar.xz 116606704 BLAKE2B b923d7b66309224f42f35f8a5fa219421b0a9362d2adacdadd8d96251f61f7230878ea297a269a7f3b3c56830f0b177e068691e1d7f88501a05653b0a13274d1 SHA512 95bc137d0cf9148da6a9d1f1a878698dc27b40f68e22c597544010a6c591ce1b256f083489d3ff45ff77753289b535135590194d88ef9f007d0ddab3d74de70e +DIST linux-5.11.tar.xz 117619104 BLAKE2B 81300c27bd5476387a83123aaeb4163c73eb61e9245806c23660cb5e6a4fa88ffc9def027031335fa0270fc4080506cd415990014364e3a98b9d2e8c58a29524 SHA512 a567ec133018bb5ec00c60281479b466c26e02137a93a9c690e83997947df02b6fd94e76e8df748f6d70ceb58a19bacc3b1467de10b7a1fad2763db32b3f1330 DIST linux-5.9.tar.xz 115507140 BLAKE2B e8d11472d63a9f8409ca12a2e8c97c6963a3d4516b5a398b627d6ece565584526f9b5a1377a2fa4bd184c09c7db94c987428bc5d52df0c788464a67e9e8d6dcb SHA512 d3d92ce4246bad74c9a784212f160d98449b1e8793970c2c308276568d852b8effe0528686bdb87d55d691f09a826abf7938d69bdd4759ce65ddd5c05ffe4eca -DIST pf-sources-5.10_p10.patch 4844801 BLAKE2B d38596ac73cc10cc81d3ce742a587bf9de918c7fdda7aa721d3ff721d562339bc6dc3a97f361888804754c7182e99459fc312a9efaaa37b94b58b7f502539586 SHA512 377ab784d9dc138ec4482382c912335cae05e86be7dd47f13fe3df402f12a40d613f3e30a0067f01b682bb5ca4dfbcf9592cc166f0b42424af70a702f8651dcd -DIST pf-sources-5.10_p11.patch 5051168 BLAKE2B e27dbf5ba44ed5ad7892b06cc3760fd44b4036c0281284a05f6d783078c2b719384efa9b9e0ff39a59cdfd5143f8c43d336a7e413fea5ddd1ff7c0fc8e43b2c8 SHA512 953b034583683574e6d95d6dbce03bad43973bd27037352dc5bfa12c966660792b92fd87ad0de47b6543e599f22ee89dd9e10bc2e76e9bfff377c353fe9e2205 DIST pf-sources-5.10_p12.patch 5244822 BLAKE2B ca004890e20a07864e858bf1834265f125d1a1a7130ecd2f4a1718b4be61dd8dbfd6c4ca7f5740219afc83f1a4645d159d57b546937bcabec59511abe3d78e58 SHA512 5aa8f303798f93e5ad2042878fa15f5ab717ad265fc6db5d35e2b429cf240ce57f042ff8c2c0ac442e552a4925093e1550f1405caffcce648b46140fb809266b -DIST pf-sources-5.10_p2.patch 2555927 BLAKE2B 69684df6616e243f5bda273ce4fd30300cde82355e3e71ef3f265bbc2fe2f680d035875ce76e836c0ee432692b69736ada54026bedbfa4423826260b5c3e05a1 SHA512 cdcaa01a9b89b935ee7b3035516c38b69ed38b897e4566adc132416fdb1953f965c33471192a3e0c85187af8edc2f0645d65e324d7b591fb4e3cabda4b05126c -DIST pf-sources-5.10_p3.patch 2588302 BLAKE2B 47a3aaa429b773edfa4f1a2eeb046648f57204a8b1985710eaf11d95baceb92950352b03e819250d59614b52e8315758a78e72a646f4bedddc5674c2571a06ab SHA512 3701656ddb88b59bb816b96c8b986f9abf4087231dac7ef2c07f1a406e8edbffb7da6e0099ff0ce3a9f73557c96984e8e7b6a9cc69d4cd129d7f7e05535fee1f -DIST pf-sources-5.10_p4.patch 3769450 BLAKE2B 5f470380efe3224150267125022012553daa36aea6bcc62d7df28a78a0f091aef925f6a2964d11e68877750b25ef5449a7d87577db30068d417106e6a76dd396 SHA512 8c0f0f48ff19e2c93ab1a0ec0387ba59365c4b5dedd4d4b7f323ac0f24502862e6e2a50c8c3c5be911836392aefba3d1c99b2fe1bc2ec8849ffff9c72a4dff2d -DIST pf-sources-5.10_p5.patch 3767157 BLAKE2B 7ea53839532d97225bbb95cd0e56c5e81d51cbe7e01bbfb09a5aea08fabbad7dee415da0ff79b6b248e2f88bb73434d53ba17808a8d62d403387cccc269e9f9d SHA512 2c07b1e66fad2e2ae1c279cfe9a41585c98ad0fe7d592a20d04e203e7a74ef9dddf6d8a970adb797727185dcbb28fa7a6a1faefcc2adb6a1eb0d309c43356f7e -DIST pf-sources-5.10_p6.patch 3863592 BLAKE2B 5ce92850e459f9ea9bdd19d4375f13a7554adbdcd3ed2b2c77c1e138c6cb508554ab8701398f77485f9551ad6422fd14e4f7ba708d607d9a107ccd818c42f560 SHA512 44398b4bcef521267ed4b9dc56281cff2587680498f68130361bab8de8bf164601bc95642493dcbb08eaf43ffca3b333ab2a12db825e7f52eb0171bb191bbaea -DIST pf-sources-5.10_p7.patch 4104263 BLAKE2B a53f381c255aa242955d7401496b5b21fba743c2a4d3d0c31a06d67c15806e1672c8910f165140ddc1aff6958e93d2871c50e64b81afeff50f1982bd854c9c19 SHA512 583f48a8fba4cc62b60a17a0274ada2f17bd8a75b16b0e9e27fa9536e743bfbba57c561a544a7c8b7a87e65059aa01e92259c9c55dc46544445d5026b06fcd82 -DIST pf-sources-5.10_p8.patch 4232466 BLAKE2B efe977028da96031c2834af65fc7da943ad0d7d0155a54e614a61ae825672b147dca31491487c8bb500aac9db869e303d3ced6a30bdd9f6fdf4bf0a0d93dc9c3 SHA512 bf64e4a12627f5c0b39dba44f815d7a42758a9e0a79fb341c535ed2b64e99068c8fdc1b8e3ae6656e815280337715b2b19d084fb589a5c60a1e5ab8e2153e27a -DIST pf-sources-5.10_p9.patch 4509136 BLAKE2B a0bd46d0e6f833849736da492e89fbc3885bf3b96db0f1cbd03525e5d60a2a8f224851f92c73f51224565ba27517ab3310af8b853fa03fedc55d8f035bda0389 SHA512 45ad1097dc270a347be598c053bc19d0a830f86e124e317c5bdf3682ed41c523ed80d277ae94ca6ecee247792254b8f16b9c9ad5c90288dec9ab6d4cb5f0d272 +DIST pf-sources-5.11_p1.patch 2710131 BLAKE2B 67a3528d1c59f24af9f09bc669e736d41394041874e07ebaa68bba8393d98b6094f3c733f1f395cb0a816f418702934d7ac828fceabebcec187526ca378929f4 SHA512 0bc79a5eb093c0b072826098b78894d59bab2bb8107221c9727c4aebb839b2e4d066c2f4918614bfbf4e3af210a6d1852189303f9ebf338f2e5038f166d4dfb0 +DIST pf-sources-5.11_p2.patch 2720760 BLAKE2B db2ccb4449d6ed2d545c15ef82b99d581e462908ab2290b62119c09da93a7cf202e3a1792a1bf3afb6ae98f4c9f8ea34ef7ad7056206f3eac7daa8a7a9559f4a SHA512 1ab4748cac5a8a210a48543606c2c3e30e4528c819b4e7d7e29d992d4f9b14ae6e7219d7d96d090fc887d72887735e52dad9a8d396d775c8c32b80b01532a9ea DIST pf-sources-5.9_p7.patch 3027972 BLAKE2B 9247ea63b30f9d42d79303b73a900d468a71e703333932f7f15ae697cdba52c46358297023e037226c219fad5df912fb5d21e6f4b7190556ca799fa84924480e SHA512 c69e14f59bf98944b3329c65b7e2c271d74a756bc8c890130bf3cc68b4b96d31f1c33c4edb128580fcaefeb6e42dd04b1eb3d7f071b2d58bc764d26322bda8cd diff --git a/sys-kernel/pf-sources/metadata.xml b/sys-kernel/pf-sources/metadata.xml index c10c60b8af4d..c721efa075f4 100644 --- a/sys-kernel/pf-sources/metadata.xml +++ b/sys-kernel/pf-sources/metadata.xml @@ -1,11 +1,12 @@ <?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE pkgmetadata SYSTEM "http://www.gentoo.org/dtd/metadata.dtd"> +<!DOCTYPE pkgmetadata SYSTEM "https://liguros.gitlab.io/dtd/metadata.dtd"> <pkgmetadata> - <maintainer type="person"> - <email>juippis@gentoo.org</email> - <name>Joonas Niilola</name> - </maintainer> - <upstream> - <remote-id type="cpe">cpe:/o:linux:linux_kernel</remote-id> - </upstream> -</pkgmetadata> + <maintainer type="person"> + <email>juippis@gentoo.org</email> + <name>Joonas Niilola</name> + </maintainer> + <upstream> + <remote-id type="cpe">cpe:/o:linux:linux_kernel</remote-id> + </upstream> + <origin>gentoo-staging</origin> +</pkgmetadata>
\ No newline at end of file diff --git a/sys-kernel/pf-sources/pf-sources-5.10_p2.ebuild b/sys-kernel/pf-sources/pf-sources-5.10_p2.ebuild deleted file mode 100644 index f73be470724f..000000000000 --- a/sys-kernel/pf-sources/pf-sources-5.10_p2.ebuild +++ /dev/null @@ -1,69 +0,0 @@ -# Copyright 1999-2020 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI=6 - -# Define what default functions to run -ETYPE="sources" - -# No 'experimental' USE flag provided, but we still want to use genpatches -K_EXP_GENPATCHES_NOUSE="1" - -# Just get basic genpatches, -pf patch set already includes vanilla-linux updates -K_GENPATCHES_VER="3" - -# -pf already sets EXTRAVERSION to kernel Makefile -K_NOSETEXTRAVERSION="1" - -# Not supported by the Gentoo security team -K_SECURITY_UNSUPPORTED="1" - -# We want the very basic patches from gentoo-sources, experimental patch is -# already included in pf-sources -K_WANT_GENPATCHES="base extras" - -# This is already patched via -pf patch set. -UNIPATCH_EXCLUDE="1001_linux-5.10.1.patch" - -inherit kernel-2 optfeature -detect_version - -DESCRIPTION="Linux kernel fork that includes the pf-kernel patchset and Gentoo's genpatches" -HOMEPAGE="https://gitlab.com/post-factum/pf-kernel/-/wikis/README - https://dev.gentoo.org/~mpagano/genpatches/" -SRC_URI="${KERNEL_URI} - https://github.com/pfactum/pf-kernel/compare/v${PV/_p*/}...v${PV/_p*/}-pf${PV/*_p/}.diff -> ${P}.patch - https://dev.gentoo.org/~mpagano/genpatches/tarballs/genpatches-${PV/_p*/}-${K_GENPATCHES_VER}.base.tar.xz - https://dev.gentoo.org/~mpagano/genpatches/tarballs/genpatches-${PV/_p*/}-${K_GENPATCHES_VER}.extras.tar.xz" - -KEYWORDS="~amd64 ~ppc ~ppc64 ~x86" - -S="${WORKDIR}/linux-${PVR}-pf" - -PATCHES=( "${DISTDIR}/${P}.patch" ) - -K_EXTRAEINFO="For more info on pf-sources and details on how to report problems, - see: ${HOMEPAGE}." - -pkg_setup() { - ewarn "" - ewarn "${PN} is *not* supported by the Gentoo Kernel Project in any way." - ewarn "If you need support, please contact the pf developers directly." - ewarn "Do *not* open bugs in Gentoo's bugzilla unless you have issues with" - ewarn "the ebuilds. Thank you." - ewarn "" - - kernel-2_pkg_setup -} - -src_prepare() { - # kernel-2_src_prepare doesn't apply PATCHES(). - default -} - -pkg_postinst() { - kernel-2_pkg_postinst - - elog "Optional features:" - optfeature "Userspace KSM helper" sys-process/uksmd -} diff --git a/sys-kernel/pf-sources/pf-sources-5.10_p3.ebuild b/sys-kernel/pf-sources/pf-sources-5.10_p3.ebuild deleted file mode 100644 index 28b132ed0a4e..000000000000 --- a/sys-kernel/pf-sources/pf-sources-5.10_p3.ebuild +++ /dev/null @@ -1,66 +0,0 @@ -# Copyright 1999-2020 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI=6 - -# Define what default functions to run -ETYPE="sources" - -# No 'experimental' USE flag provided, but we still want to use genpatches -K_EXP_GENPATCHES_NOUSE="1" - -# Just get basic genpatches, -pf patch set already includes vanilla-linux updates -K_GENPATCHES_VER="1" - -# -pf already sets EXTRAVERSION to kernel Makefile -K_NOSETEXTRAVERSION="1" - -# Not supported by the Gentoo security team -K_SECURITY_UNSUPPORTED="1" - -# We want the very basic patches from gentoo-sources, experimental patch is -# already included in pf-sources -K_WANT_GENPATCHES="base extras" - -inherit kernel-2 optfeature -detect_version - -DESCRIPTION="Linux kernel fork that includes the pf-kernel patchset and Gentoo's genpatches" -HOMEPAGE="https://gitlab.com/post-factum/pf-kernel/-/wikis/README - https://dev.gentoo.org/~mpagano/genpatches/" -SRC_URI="${KERNEL_URI} - https://github.com/pfactum/pf-kernel/compare/v${PV/_p*/}...v${PV/_p*/}-pf${PV/*_p/}.diff -> ${P}.patch - https://dev.gentoo.org/~mpagano/genpatches/tarballs/genpatches-${PV/_p*/}-${K_GENPATCHES_VER}.base.tar.xz - https://dev.gentoo.org/~mpagano/genpatches/tarballs/genpatches-${PV/_p*/}-${K_GENPATCHES_VER}.extras.tar.xz" - -KEYWORDS="~amd64 ~ppc ~ppc64 ~x86" - -S="${WORKDIR}/linux-${PVR}-pf" - -PATCHES=( "${DISTDIR}/${P}.patch" ) - -K_EXTRAEINFO="For more info on pf-sources and details on how to report problems, - see: ${HOMEPAGE}." - -pkg_setup() { - ewarn "" - ewarn "${PN} is *not* supported by the Gentoo Kernel Project in any way." - ewarn "If you need support, please contact the pf developers directly." - ewarn "Do *not* open bugs in Gentoo's bugzilla unless you have issues with" - ewarn "the ebuilds. Thank you." - ewarn "" - - kernel-2_pkg_setup -} - -src_prepare() { - # kernel-2_src_prepare doesn't apply PATCHES(). - default -} - -pkg_postinst() { - kernel-2_pkg_postinst - - elog "Optional features:" - optfeature "Userspace KSM helper" sys-process/uksmd -} diff --git a/sys-kernel/pf-sources/pf-sources-5.10_p4.ebuild b/sys-kernel/pf-sources/pf-sources-5.10_p4.ebuild deleted file mode 100644 index 223e79a03a51..000000000000 --- a/sys-kernel/pf-sources/pf-sources-5.10_p4.ebuild +++ /dev/null @@ -1,66 +0,0 @@ -# Copyright 1999-2021 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI=6 - -# Define what default functions to run -ETYPE="sources" - -# No 'experimental' USE flag provided, but we still want to use genpatches -K_EXP_GENPATCHES_NOUSE="1" - -# Just get basic genpatches, -pf patch set already includes vanilla-linux updates -K_GENPATCHES_VER="1" - -# -pf already sets EXTRAVERSION to kernel Makefile -K_NOSETEXTRAVERSION="1" - -# Not supported by the Gentoo security team -K_SECURITY_UNSUPPORTED="1" - -# We want the very basic patches from gentoo-sources, experimental patch is -# already included in pf-sources -K_WANT_GENPATCHES="base extras" - -inherit kernel-2 optfeature -detect_version - -DESCRIPTION="Linux kernel fork that includes the pf-kernel patchset and Gentoo's genpatches" -HOMEPAGE="https://gitlab.com/post-factum/pf-kernel/-/wikis/README - https://dev.gentoo.org/~mpagano/genpatches/" -SRC_URI="${KERNEL_URI} - https://github.com/pfactum/pf-kernel/compare/v${PV/_p*/}...v${PV/_p*/}-pf${PV/*_p/}.diff -> ${P}.patch - https://dev.gentoo.org/~mpagano/genpatches/tarballs/genpatches-${PV/_p*/}-${K_GENPATCHES_VER}.base.tar.xz - https://dev.gentoo.org/~mpagano/genpatches/tarballs/genpatches-${PV/_p*/}-${K_GENPATCHES_VER}.extras.tar.xz" - -KEYWORDS="~amd64 ~ppc ~ppc64 ~x86" - -S="${WORKDIR}/linux-${PVR}-pf" - -PATCHES=( "${DISTDIR}/${P}.patch" ) - -K_EXTRAEINFO="For more info on pf-sources and details on how to report problems, - see: ${HOMEPAGE}." - -pkg_setup() { - ewarn "" - ewarn "${PN} is *not* supported by the Gentoo Kernel Project in any way." - ewarn "If you need support, please contact the pf developers directly." - ewarn "Do *not* open bugs in Gentoo's bugzilla unless you have issues with" - ewarn "the ebuilds. Thank you." - ewarn "" - - kernel-2_pkg_setup -} - -src_prepare() { - # kernel-2_src_prepare doesn't apply PATCHES(). - default -} - -pkg_postinst() { - kernel-2_pkg_postinst - - elog "Optional features:" - optfeature "Userspace KSM helper" sys-process/uksmd -} diff --git a/sys-kernel/pf-sources/pf-sources-5.10_p5.ebuild b/sys-kernel/pf-sources/pf-sources-5.10_p5.ebuild deleted file mode 100644 index 223e79a03a51..000000000000 --- a/sys-kernel/pf-sources/pf-sources-5.10_p5.ebuild +++ /dev/null @@ -1,66 +0,0 @@ -# Copyright 1999-2021 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI=6 - -# Define what default functions to run -ETYPE="sources" - -# No 'experimental' USE flag provided, but we still want to use genpatches -K_EXP_GENPATCHES_NOUSE="1" - -# Just get basic genpatches, -pf patch set already includes vanilla-linux updates -K_GENPATCHES_VER="1" - -# -pf already sets EXTRAVERSION to kernel Makefile -K_NOSETEXTRAVERSION="1" - -# Not supported by the Gentoo security team -K_SECURITY_UNSUPPORTED="1" - -# We want the very basic patches from gentoo-sources, experimental patch is -# already included in pf-sources -K_WANT_GENPATCHES="base extras" - -inherit kernel-2 optfeature -detect_version - -DESCRIPTION="Linux kernel fork that includes the pf-kernel patchset and Gentoo's genpatches" -HOMEPAGE="https://gitlab.com/post-factum/pf-kernel/-/wikis/README - https://dev.gentoo.org/~mpagano/genpatches/" -SRC_URI="${KERNEL_URI} - https://github.com/pfactum/pf-kernel/compare/v${PV/_p*/}...v${PV/_p*/}-pf${PV/*_p/}.diff -> ${P}.patch - https://dev.gentoo.org/~mpagano/genpatches/tarballs/genpatches-${PV/_p*/}-${K_GENPATCHES_VER}.base.tar.xz - https://dev.gentoo.org/~mpagano/genpatches/tarballs/genpatches-${PV/_p*/}-${K_GENPATCHES_VER}.extras.tar.xz" - -KEYWORDS="~amd64 ~ppc ~ppc64 ~x86" - -S="${WORKDIR}/linux-${PVR}-pf" - -PATCHES=( "${DISTDIR}/${P}.patch" ) - -K_EXTRAEINFO="For more info on pf-sources and details on how to report problems, - see: ${HOMEPAGE}." - -pkg_setup() { - ewarn "" - ewarn "${PN} is *not* supported by the Gentoo Kernel Project in any way." - ewarn "If you need support, please contact the pf developers directly." - ewarn "Do *not* open bugs in Gentoo's bugzilla unless you have issues with" - ewarn "the ebuilds. Thank you." - ewarn "" - - kernel-2_pkg_setup -} - -src_prepare() { - # kernel-2_src_prepare doesn't apply PATCHES(). - default -} - -pkg_postinst() { - kernel-2_pkg_postinst - - elog "Optional features:" - optfeature "Userspace KSM helper" sys-process/uksmd -} diff --git a/sys-kernel/pf-sources/pf-sources-5.10_p6.ebuild b/sys-kernel/pf-sources/pf-sources-5.10_p6.ebuild deleted file mode 100644 index 223e79a03a51..000000000000 --- a/sys-kernel/pf-sources/pf-sources-5.10_p6.ebuild +++ /dev/null @@ -1,66 +0,0 @@ -# Copyright 1999-2021 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI=6 - -# Define what default functions to run -ETYPE="sources" - -# No 'experimental' USE flag provided, but we still want to use genpatches -K_EXP_GENPATCHES_NOUSE="1" - -# Just get basic genpatches, -pf patch set already includes vanilla-linux updates -K_GENPATCHES_VER="1" - -# -pf already sets EXTRAVERSION to kernel Makefile -K_NOSETEXTRAVERSION="1" - -# Not supported by the Gentoo security team -K_SECURITY_UNSUPPORTED="1" - -# We want the very basic patches from gentoo-sources, experimental patch is -# already included in pf-sources -K_WANT_GENPATCHES="base extras" - -inherit kernel-2 optfeature -detect_version - -DESCRIPTION="Linux kernel fork that includes the pf-kernel patchset and Gentoo's genpatches" -HOMEPAGE="https://gitlab.com/post-factum/pf-kernel/-/wikis/README - https://dev.gentoo.org/~mpagano/genpatches/" -SRC_URI="${KERNEL_URI} - https://github.com/pfactum/pf-kernel/compare/v${PV/_p*/}...v${PV/_p*/}-pf${PV/*_p/}.diff -> ${P}.patch - https://dev.gentoo.org/~mpagano/genpatches/tarballs/genpatches-${PV/_p*/}-${K_GENPATCHES_VER}.base.tar.xz - https://dev.gentoo.org/~mpagano/genpatches/tarballs/genpatches-${PV/_p*/}-${K_GENPATCHES_VER}.extras.tar.xz" - -KEYWORDS="~amd64 ~ppc ~ppc64 ~x86" - -S="${WORKDIR}/linux-${PVR}-pf" - -PATCHES=( "${DISTDIR}/${P}.patch" ) - -K_EXTRAEINFO="For more info on pf-sources and details on how to report problems, - see: ${HOMEPAGE}." - -pkg_setup() { - ewarn "" - ewarn "${PN} is *not* supported by the Gentoo Kernel Project in any way." - ewarn "If you need support, please contact the pf developers directly." - ewarn "Do *not* open bugs in Gentoo's bugzilla unless you have issues with" - ewarn "the ebuilds. Thank you." - ewarn "" - - kernel-2_pkg_setup -} - -src_prepare() { - # kernel-2_src_prepare doesn't apply PATCHES(). - default -} - -pkg_postinst() { - kernel-2_pkg_postinst - - elog "Optional features:" - optfeature "Userspace KSM helper" sys-process/uksmd -} diff --git a/sys-kernel/pf-sources/pf-sources-5.10_p7.ebuild b/sys-kernel/pf-sources/pf-sources-5.10_p7.ebuild deleted file mode 100644 index 223e79a03a51..000000000000 --- a/sys-kernel/pf-sources/pf-sources-5.10_p7.ebuild +++ /dev/null @@ -1,66 +0,0 @@ -# Copyright 1999-2021 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI=6 - -# Define what default functions to run -ETYPE="sources" - -# No 'experimental' USE flag provided, but we still want to use genpatches -K_EXP_GENPATCHES_NOUSE="1" - -# Just get basic genpatches, -pf patch set already includes vanilla-linux updates -K_GENPATCHES_VER="1" - -# -pf already sets EXTRAVERSION to kernel Makefile -K_NOSETEXTRAVERSION="1" - -# Not supported by the Gentoo security team -K_SECURITY_UNSUPPORTED="1" - -# We want the very basic patches from gentoo-sources, experimental patch is -# already included in pf-sources -K_WANT_GENPATCHES="base extras" - -inherit kernel-2 optfeature -detect_version - -DESCRIPTION="Linux kernel fork that includes the pf-kernel patchset and Gentoo's genpatches" -HOMEPAGE="https://gitlab.com/post-factum/pf-kernel/-/wikis/README - https://dev.gentoo.org/~mpagano/genpatches/" -SRC_URI="${KERNEL_URI} - https://github.com/pfactum/pf-kernel/compare/v${PV/_p*/}...v${PV/_p*/}-pf${PV/*_p/}.diff -> ${P}.patch - https://dev.gentoo.org/~mpagano/genpatches/tarballs/genpatches-${PV/_p*/}-${K_GENPATCHES_VER}.base.tar.xz - https://dev.gentoo.org/~mpagano/genpatches/tarballs/genpatches-${PV/_p*/}-${K_GENPATCHES_VER}.extras.tar.xz" - -KEYWORDS="~amd64 ~ppc ~ppc64 ~x86" - -S="${WORKDIR}/linux-${PVR}-pf" - -PATCHES=( "${DISTDIR}/${P}.patch" ) - -K_EXTRAEINFO="For more info on pf-sources and details on how to report problems, - see: ${HOMEPAGE}." - -pkg_setup() { - ewarn "" - ewarn "${PN} is *not* supported by the Gentoo Kernel Project in any way." - ewarn "If you need support, please contact the pf developers directly." - ewarn "Do *not* open bugs in Gentoo's bugzilla unless you have issues with" - ewarn "the ebuilds. Thank you." - ewarn "" - - kernel-2_pkg_setup -} - -src_prepare() { - # kernel-2_src_prepare doesn't apply PATCHES(). - default -} - -pkg_postinst() { - kernel-2_pkg_postinst - - elog "Optional features:" - optfeature "Userspace KSM helper" sys-process/uksmd -} diff --git a/sys-kernel/pf-sources/pf-sources-5.10_p8.ebuild b/sys-kernel/pf-sources/pf-sources-5.10_p8.ebuild deleted file mode 100644 index 223e79a03a51..000000000000 --- a/sys-kernel/pf-sources/pf-sources-5.10_p8.ebuild +++ /dev/null @@ -1,66 +0,0 @@ -# Copyright 1999-2021 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI=6 - -# Define what default functions to run -ETYPE="sources" - -# No 'experimental' USE flag provided, but we still want to use genpatches -K_EXP_GENPATCHES_NOUSE="1" - -# Just get basic genpatches, -pf patch set already includes vanilla-linux updates -K_GENPATCHES_VER="1" - -# -pf already sets EXTRAVERSION to kernel Makefile -K_NOSETEXTRAVERSION="1" - -# Not supported by the Gentoo security team -K_SECURITY_UNSUPPORTED="1" - -# We want the very basic patches from gentoo-sources, experimental patch is -# already included in pf-sources -K_WANT_GENPATCHES="base extras" - -inherit kernel-2 optfeature -detect_version - -DESCRIPTION="Linux kernel fork that includes the pf-kernel patchset and Gentoo's genpatches" -HOMEPAGE="https://gitlab.com/post-factum/pf-kernel/-/wikis/README - https://dev.gentoo.org/~mpagano/genpatches/" -SRC_URI="${KERNEL_URI} - https://github.com/pfactum/pf-kernel/compare/v${PV/_p*/}...v${PV/_p*/}-pf${PV/*_p/}.diff -> ${P}.patch - https://dev.gentoo.org/~mpagano/genpatches/tarballs/genpatches-${PV/_p*/}-${K_GENPATCHES_VER}.base.tar.xz - https://dev.gentoo.org/~mpagano/genpatches/tarballs/genpatches-${PV/_p*/}-${K_GENPATCHES_VER}.extras.tar.xz" - -KEYWORDS="~amd64 ~ppc ~ppc64 ~x86" - -S="${WORKDIR}/linux-${PVR}-pf" - -PATCHES=( "${DISTDIR}/${P}.patch" ) - -K_EXTRAEINFO="For more info on pf-sources and details on how to report problems, - see: ${HOMEPAGE}." - -pkg_setup() { - ewarn "" - ewarn "${PN} is *not* supported by the Gentoo Kernel Project in any way." - ewarn "If you need support, please contact the pf developers directly." - ewarn "Do *not* open bugs in Gentoo's bugzilla unless you have issues with" - ewarn "the ebuilds. Thank you." - ewarn "" - - kernel-2_pkg_setup -} - -src_prepare() { - # kernel-2_src_prepare doesn't apply PATCHES(). - default -} - -pkg_postinst() { - kernel-2_pkg_postinst - - elog "Optional features:" - optfeature "Userspace KSM helper" sys-process/uksmd -} diff --git a/sys-kernel/pf-sources/pf-sources-5.10_p9.ebuild b/sys-kernel/pf-sources/pf-sources-5.10_p9.ebuild deleted file mode 100644 index 223e79a03a51..000000000000 --- a/sys-kernel/pf-sources/pf-sources-5.10_p9.ebuild +++ /dev/null @@ -1,66 +0,0 @@ -# Copyright 1999-2021 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI=6 - -# Define what default functions to run -ETYPE="sources" - -# No 'experimental' USE flag provided, but we still want to use genpatches -K_EXP_GENPATCHES_NOUSE="1" - -# Just get basic genpatches, -pf patch set already includes vanilla-linux updates -K_GENPATCHES_VER="1" - -# -pf already sets EXTRAVERSION to kernel Makefile -K_NOSETEXTRAVERSION="1" - -# Not supported by the Gentoo security team -K_SECURITY_UNSUPPORTED="1" - -# We want the very basic patches from gentoo-sources, experimental patch is -# already included in pf-sources -K_WANT_GENPATCHES="base extras" - -inherit kernel-2 optfeature -detect_version - -DESCRIPTION="Linux kernel fork that includes the pf-kernel patchset and Gentoo's genpatches" -HOMEPAGE="https://gitlab.com/post-factum/pf-kernel/-/wikis/README - https://dev.gentoo.org/~mpagano/genpatches/" -SRC_URI="${KERNEL_URI} - https://github.com/pfactum/pf-kernel/compare/v${PV/_p*/}...v${PV/_p*/}-pf${PV/*_p/}.diff -> ${P}.patch - https://dev.gentoo.org/~mpagano/genpatches/tarballs/genpatches-${PV/_p*/}-${K_GENPATCHES_VER}.base.tar.xz - https://dev.gentoo.org/~mpagano/genpatches/tarballs/genpatches-${PV/_p*/}-${K_GENPATCHES_VER}.extras.tar.xz" - -KEYWORDS="~amd64 ~ppc ~ppc64 ~x86" - -S="${WORKDIR}/linux-${PVR}-pf" - -PATCHES=( "${DISTDIR}/${P}.patch" ) - -K_EXTRAEINFO="For more info on pf-sources and details on how to report problems, - see: ${HOMEPAGE}." - -pkg_setup() { - ewarn "" - ewarn "${PN} is *not* supported by the Gentoo Kernel Project in any way." - ewarn "If you need support, please contact the pf developers directly." - ewarn "Do *not* open bugs in Gentoo's bugzilla unless you have issues with" - ewarn "the ebuilds. Thank you." - ewarn "" - - kernel-2_pkg_setup -} - -src_prepare() { - # kernel-2_src_prepare doesn't apply PATCHES(). - default -} - -pkg_postinst() { - kernel-2_pkg_postinst - - elog "Optional features:" - optfeature "Userspace KSM helper" sys-process/uksmd -} diff --git a/sys-kernel/pf-sources/pf-sources-5.10_p10.ebuild b/sys-kernel/pf-sources/pf-sources-5.11_p1.ebuild index 223e79a03a51..223e79a03a51 100644 --- a/sys-kernel/pf-sources/pf-sources-5.10_p10.ebuild +++ b/sys-kernel/pf-sources/pf-sources-5.11_p1.ebuild diff --git a/sys-kernel/pf-sources/pf-sources-5.10_p11.ebuild b/sys-kernel/pf-sources/pf-sources-5.11_p2.ebuild index 223e79a03a51..223e79a03a51 100644 --- a/sys-kernel/pf-sources/pf-sources-5.10_p11.ebuild +++ b/sys-kernel/pf-sources/pf-sources-5.11_p2.ebuild diff --git a/sys-kernel/raspberrypi-image/Manifest b/sys-kernel/raspberrypi-image/Manifest index 2d3543d359b9..91fa34ba8ff7 100644 --- a/sys-kernel/raspberrypi-image/Manifest +++ b/sys-kernel/raspberrypi-image/Manifest @@ -1,3 +1,4 @@ DIST raspberrypi-firmware-1.20190925.tar.gz 185571086 BLAKE2B c3a9b2760fa853fbd1dd09bc4048c9e78594f88da5af608c3a761554d4046a4c869db8981c64140a24e82e0a61b8dc776bb8d895df60c6424e44780f78b18cb0 SHA512 4b7b29cc6c2a33d7a37987c492034d9afbb2220364c50cf265e0adf8e5f393c2275dcffaa77c89b3f43b2e98d199741b67590cb60ff8beae8ef677852f63b4a0 DIST raspberrypi-firmware-1.20201201.tar.gz 189332299 BLAKE2B b3ec91f07b4713d26c29be5412d018a220129eef7ddf7c5c09d85e645c2c5754a95f13be7e690ab40648a982e3974cc760aa5b33c76612da836227d38c4ee3a5 SHA512 a7f4591552718956bd7f2d0d377234277e2e6f18cc9714ea30fe13f26d5ae1164b982f39dcf72ae4a18663369ef06d0187d8182713763262371c13107aac4c65 +DIST raspberrypi-firmware-1.20210201.tar.gz 191785657 BLAKE2B 7ef315411e3bc572515f9e60d953166056bd5dfe9afc496eda978dbbbd6f38aa12f1eaba72448bb72166d6bda1ec79e3e3e7c613f4202bc804784b566f118971 SHA512 13d899a103e8d3deb98a6fcca661f712b085935336fc31156e0b8ec5e3c71b373d3394777895ee1907cad9a2ca3efd1a66995ff6df3429c732b002d9ad603414 DIST raspberrypi-image-4.14.98_p20190215.tar.gz 123074917 BLAKE2B cefedb5c979db7dfd47938aad37a567d91d3ad78247c7a63f789362768ab7a39a1967ac116b4b0475e3b210ab11f6474706df042af85a622e8e7905c85ec7498 SHA512 082f26caf427222d838881e5f1e9fa0136765b3eaf74a84877fc33616fd07e49085db0889226c40c655039a9d41a10566510c7d752cfc48a67b4683616a51193 diff --git a/sys-kernel/raspberrypi-image/metadata.xml b/sys-kernel/raspberrypi-image/metadata.xml index 729e6b371508..93f32c4fc772 100644 --- a/sys-kernel/raspberrypi-image/metadata.xml +++ b/sys-kernel/raspberrypi-image/metadata.xml @@ -1,11 +1,12 @@ <?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE pkgmetadata SYSTEM "http://www.gentoo.org/dtd/metadata.dtd"> +<!DOCTYPE pkgmetadata SYSTEM "https://liguros.gitlab.io/dtd/metadata.dtd"> <pkgmetadata> - <maintainer type="person"> - <email>sam@gentoo.org</email> - <name>Sam James</name> - </maintainer> - <upstream> - <remote-id type="github">raspberrypi/firmware</remote-id> - </upstream> -</pkgmetadata> + <maintainer type="person"> + <email>sam@gentoo.org</email> + <name>Sam James</name> + </maintainer> + <upstream> + <remote-id type="github">raspberrypi/firmware</remote-id> + </upstream> + <origin>gentoo-staging</origin> +</pkgmetadata>
\ No newline at end of file diff --git a/sys-kernel/raspberrypi-image/raspberrypi-image-5.10.11_p20210201.ebuild b/sys-kernel/raspberrypi-image/raspberrypi-image-5.10.11_p20210201.ebuild new file mode 100644 index 000000000000..26d80041afd0 --- /dev/null +++ b/sys-kernel/raspberrypi-image/raspberrypi-image-5.10.11_p20210201.ebuild @@ -0,0 +1,43 @@ +# Copyright 1999-2021 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +EAPI=7 + +inherit mount-boot + +DESCRIPTION="Raspberry Pi (all versions) kernel and modules" +HOMEPAGE="https://github.com/raspberrypi/firmware" +LICENSE="GPL-2 raspberrypi-videocore-bin" +SLOT="0" +RESTRICT="binchecks strip" + +# Temporary safety measure to prevent ending up with a pair of +# sys-kernel/raspberrypi-image and sys-boot/raspberrypi-firmware +# both of which installed device tree files. +# Restore to simply "sys-boot/raspberrypi-firmware" when the mentioned version +# and all older ones are deleted. +RDEPEND=">sys-boot/raspberrypi-firmware-1.20190709" + +if [[ "${PV}" == 9999 ]]; then + inherit git-r3 + EGIT_REPO_URI="https://github.com/raspberrypi/firmware" + EGIT_CLONE_TYPE="shallow" +else + [[ "$(ver_cut 4)" == 'p' ]] || die "Unsupported version format, tweak the ebuild." + MY_PV="1.$(ver_cut 5)" + SRC_URI="https://github.com/raspberrypi/firmware/archive/${MY_PV}.tar.gz -> raspberrypi-firmware-${MY_PV}.tar.gz" + S="${WORKDIR}/firmware-${MY_PV}" + KEYWORDS="" + # No keywords until I can give it a boot test + #KEYWORDS="-* ~arm ~arm64" +fi + +src_install() { + insinto /lib/modules + doins -r modules/* + insinto /boot + doins boot/*.img + + doins boot/*.dtb + doins -r boot/overlays +} diff --git a/sys-kernel/raspberrypi-sources/metadata.xml b/sys-kernel/raspberrypi-sources/metadata.xml index 3bc86a942642..8eaec336ce4a 100644 --- a/sys-kernel/raspberrypi-sources/metadata.xml +++ b/sys-kernel/raspberrypi-sources/metadata.xml @@ -1,11 +1,12 @@ <?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE pkgmetadata SYSTEM "http://www.gentoo.org/dtd/metadata.dtd"> +<!DOCTYPE pkgmetadata SYSTEM "https://liguros.gitlab.io/dtd/metadata.dtd"> <pkgmetadata> - <maintainer type="person"> - <email>sam@gentoo.org</email> - <name>Sam James</name> - </maintainer> - <upstream> - <remote-id type="github">raspberrypi/linux</remote-id> - </upstream> -</pkgmetadata> + <maintainer type="person"> + <email>sam@gentoo.org</email> + <name>Sam James</name> + </maintainer> + <upstream> + <remote-id type="github">raspberrypi/linux</remote-id> + </upstream> + <origin>gentoo-staging</origin> +</pkgmetadata>
\ No newline at end of file diff --git a/sys-kernel/rt-sources/metadata.xml b/sys-kernel/rt-sources/metadata.xml index 1346447ab3f0..e7b4807cca07 100644 --- a/sys-kernel/rt-sources/metadata.xml +++ b/sys-kernel/rt-sources/metadata.xml @@ -1,13 +1,14 @@ <?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE pkgmetadata SYSTEM "http://www.gentoo.org/dtd/metadata.dtd"> +<!DOCTYPE pkgmetadata SYSTEM "https://liguros.gitlab.io/dtd/metadata.dtd"> <pkgmetadata> - <maintainer type="person"> - <email>alicef@gentoo.org</email> - </maintainer> - <use> - <flag name="deblob">Remove binary blobs from kernel sources to provide libre license compliance.</flag> - </use> - <upstream> - <remote-id type="cpe">cpe:/o:linux:linux_kernel</remote-id> - </upstream> -</pkgmetadata> + <maintainer type="person"> + <email>alicef@gentoo.org</email> + </maintainer> + <upstream> + <remote-id type="cpe">cpe:/o:linux:linux_kernel</remote-id> + </upstream> + <use> + <flag name="deblob">Remove binary blobs from kernel sources to provide libre license compliance.</flag> + </use> + <origin>gentoo-staging</origin> +</pkgmetadata>
\ No newline at end of file diff --git a/sys-kernel/vanilla-kernel/Manifest b/sys-kernel/vanilla-kernel/Manifest index b515fcca0050..404e195eaba4 100644 --- a/sys-kernel/vanilla-kernel/Manifest +++ b/sys-kernel/vanilla-kernel/Manifest @@ -1,49 +1,33 @@ +DIST gentoo-kernel-config-5.10.18.tar.gz 1219 BLAKE2B 55ec8c66a9b090e590e23574b54edde0fefb575f25e6848b1c84834847304e30e52fc0810b8fd219cfb23c097bb8f7444e0b010bde44209f0c4811f99db7e0aa SHA512 ee137c85e94fe5989646cb19a72aca62ddd4795813f7bbf15d66262b0e72d90d84d5d17a31bae7980c061e0576e3f3254dca53ba6e547cf12cb7ab08771e3900 DIST gentoo-kernel-config-5.10.7.tar.gz 1146 BLAKE2B f755581e9f3be3122e5f6e6fc133d3e5c3116d4580b53f95ff5b2cee5150233fe82be5cd45637a9792ae4612be5d2cb4dd954506f97fe82c9e96cb8b772cb342 SHA512 8c64768e83d2552e69a29c6c3f958ef6a1e5a767acd04b3bfcd0cd49453ab5d0aa54fcfee76a8c9d07f72abdbf70380b070e3d1584e7b7d05a6daa3399892f51 -DIST gentoo-kernel-config-5.4.77-r1.tar.gz 1289 BLAKE2B 6612741cfbf458f4bd8915b476aac3aa6934e8bbab344da877fa4ad52b6133e01f5d44bf0e5d048e79e56c1a351774135ee55f1aa839b230e2418db7c5d9b123 SHA512 2a09dd85af37447b278847aeaad114ef47470726cec015ed5ee1b54b3080f4b2c48de8b2f7b817eeb4e27c753579cf0820053e22caa762cb1552116d8d69eba0 DIST gentoo-kernel-config-5.4.89.tar.gz 1240 BLAKE2B 50bd2e64eb1a62d2f0d67e02b78da56cb507fd7a5993d663b880c94ecd535898285ed01e00d5d07fc1ba0d044657e776456736d8fdcacecf7ca464979a8a1d06 SHA512 ad31f9895b9dd45edd7f8715516edfc303c23600f243f3ca122c7c554c9fdbe3c3aa62970a24ef7291d7937e04c63c0258f6348e796686902a011c055c1bed01 DIST kernel-aarch64-fedora.config.5.10.12 223184 BLAKE2B a0246dac2f7a4ad6a55b611538d24382ac87a8960077811a859c9595ac67f961b4bccb7e139a89abc7c0e26e80832da5c94211fc658082f2e7dde984f14dd29d SHA512 7d803b347b136331db1ad6e22e0445fe0224c3e26cd7c034cbe9794915d457b492e05f77664865079874ec001351553652646e2e08d0fee31e30b841b0008f52 -DIST kernel-aarch64-fedora.config.5.10.7 223162 BLAKE2B 23d78fadc509edd2219ba263266e4a865f98d6aef87ee2e299b81ba86ac36eff580e5c7bdccb0d4a8593afad07136e06171c79e0dd0e072c892a523e6e352933 SHA512 9791c26368173da444ca5ed281effdd5e20f3968f0a65eb607c2741f114443db2bf260d033a28a7f826963b59a8893a1311befcb3eb3609f9b85472e95234bcd +DIST kernel-aarch64-fedora.config.5.11.1 225847 BLAKE2B 50e3db29a9afc3db3c35e3af173e89e2e8d3b573dd8af7c35584e3d0152211cbd5e6ddb749acb3d6d2caa54392a3f51e52b5394a5d032d43ed35861230b277d0 SHA512 6d0594658e205767599453d4d8695c37eabc065d6c17362c3775dd745f6ca62131d7c15126ec41a17e757d3ae2a0569cea6621a7ada4666a8f90e4414391b3dc DIST kernel-aarch64.config.5.4.21 199104 BLAKE2B 578ad451a76204df2a9bbbe34b5cb27051d2ac5e2c33967f562b01338c43f35da6dc33a4c2cc67ea6c3b32b155729360d3748ec28dcaa750f18449245b2e8a09 SHA512 66e9a437beb350fdc59512c17b8f72c5b5bfacf2b35070d810d77e66f49cf7929026cc28ad44b04a016d61e65d9fb4a10af6996ba09b604bf97e9c467d08f8ff DIST kernel-i686-fedora.config.5.10.12 205412 BLAKE2B 92c715b7e2cd7dd74da7970c05981f520597d3e403ce82c8cf4eee31c9f1f50b638792a6bdb256ef5bfdc99f1bcd594e819e8f44dc6febb2ad9a854bad817f2b SHA512 69d8db11723ae1b40fdedfaace74d15bb63198cdb0485e0a1e5eba95b31217110c93a93e39cc7370cf45f1d3a8bc7f75ec096d6db5ea9ecb28ac6b56702ebb10 -DIST kernel-i686-fedora.config.5.10.7 205390 BLAKE2B 103131caa856ae9b062b39cb88ad8616a8ebd7aa53b7562399d72ba998a4049a22ab251927bf43a4936127246455c2cdeeee3b7e349e12bb94af8f6dc242d8ea SHA512 58279d0076f7551569e48db45909263c5c494c4349afaff4087682d7dd0ecadc22dde56482b521ce2eec39b1e6110f5c370206e0c8f7045d4419bb164da7e2ec +DIST kernel-i686-fedora.config.5.11.1 208027 BLAKE2B b4183e8d1121aa8b3f65d0a4542b8ba0f507430ab4cf0004dd0e8b1e24b3be1783316b8bf6becb2002f7fbacc8236b640f533fc2e9dc5696e84d1627c3b0e9c4 SHA512 5b107e376ddef783ee6852ef67143a94340b37ab764ef3ee3c6642401883d314809c959c2025d976336923c115d21d6b39332aa1699c0f884d1faad1d9c3fa32 DIST kernel-i686.config.5.4.21 183910 BLAKE2B 185126ffb85718bb73761d01683def80b6f002d7a7a6eddd8e858a30d8eadc863fb378d83a1cd2ed82b3540337fa66ae44475e31fb41ebc46d77005b6f54e5c0 SHA512 6307afc2295902e44fe65b1cccaa7a0260b295a5f21f1d67ec66197bd972bd3f5675b624f08d9da8b224cb3ec987d5c21cbd743599aeab9ac6214bc651f43476 DIST kernel-ppc64le-fedora.config.5.10.12 192105 BLAKE2B 889141debb0656a358a3381bae14b5216b982acdfce0bc758f9445c16647807a68a788fb290199c2a1a23627bda1ef4c9405b3f5ac2a4176d1d2b55c71fb7db9 SHA512 3ab0f1401d9f50a61477c71369dede438f575d9d2c3a2f5c2cf36d624c2b59a938efca9c981b075511b3860c983eaaf5e5a9f877d659277f09ceba45edd43770 -DIST kernel-ppc64le-fedora.config.5.10.7 192083 BLAKE2B 71c97c04629a05ac8cb4f4cf1740c60e8a25c71a5c9184cf53f13088073b04b269887ee6e57ff83c8caff61ccbfd6845809e6e3057f1fdfc13d9b913b032c653 SHA512 732f4e93b3074180e86bed865e0b6d487857d5eefcb2436e7c24706be0e41c813b27b2292e6995df2d63e9a9f7721c2d566a50ba06675bfa862ca1fc91dc2af5 +DIST kernel-ppc64le-fedora.config.5.11.1 194870 BLAKE2B df6e5a0a789dc6d0c2fbec45820f5e19ec455388f02f04d88d7b3dd5081d2f11e89cfd0159b7a3885aaa029470e916743d59ec3f86756ff4182aa56552aa8476 SHA512 e170912e76e8980435df2a1387792d616490ededda4df681a90312f7fc8ce4065f1c9fd7559d746d8edc0fccfbd35b20fd5db294774f9db7f4635d898cd0dab1 DIST kernel-ppc64le.config.5.4.21 172003 BLAKE2B b53887cb44f7c378cb3866780f8e556e19fdb02130d3b0df01d97698d2a91f7d90a200012559f288e962935742c3fdb67dfb6711876fad37862fe55cdca5b5f6 SHA512 82df8d0be47e9eb20bd7db570539bb061d0b6e2101dc78a54596cf4d0b4e0c536041449304ff9240b051ee09b342ea336c5645e9a3b66a5dfb96d7778ff86008 DIST kernel-x86_64-fedora.config.5.10.12 206357 BLAKE2B 0eda9d4f3f973336cabd67c1ac78f100aabde926354743e8dcb7ff84496f0de49210d45f99bc850a2096078b0b4687aa7fd965d999248559506004f2b29dac0c SHA512 b12f43d3c1a52a4915cd73db98874ce9ae6c425672c0f1c19ed1b1101341c868ebf1c9620bef5449752ec0d7342c1ce38fb77779d0f89b9267096a605ebf7a26 -DIST kernel-x86_64-fedora.config.5.10.7 206335 BLAKE2B 1133bf0f58f8073578d048c5905cc4a539f63a01b57fceb225046c4678172861de20419d8cbf42b0f4655c27a6366ddee41343458d577a2685f3d96b2fd444c6 SHA512 8c5d0de931526d3315793e0a1af4c9c2493c09573c4f2233aaa85f0413a912190c14fa8427593fc3956fff61d89c795f7c9b0509bb30936cc8b9976deafeda66 +DIST kernel-x86_64-fedora.config.5.11.1 208870 BLAKE2B 86e075a95cbc5d6c3cdecb0caf67e18f671ed663aee94b7d0688e25f111dfdf12d890e1f409df04446d18057b6fad8e0fc67adcde34ed581266d458d9c9cabbd SHA512 ab39c8b107471bdd492e6f9c2e181e85e44134b4a2934fedd2f454b9766a32aa2cef2cbf7ed83111e82ffd7794d4bf20f81d98b238751d505c13077abff2b543 DIST kernel-x86_64.config.5.4.21 184907 BLAKE2B 0eb2b07c14cea7545350fcdf3a94f2a531f0137c502ebda9299cacf44da5385686e2049b480b28bc153c9d413d453cfe682b9655eefe70428cb720f57c7bd200 SHA512 f3b3ee6841555ac3a9cc11536a7d44e1a5a8df2bab14ba341fda7df1ceb0de45cf1c799a1d54a64f2858fd1272d348bb52cf269ffa396878c5402baf2730237f -DIST linux-5.10.10.tar.sign 991 BLAKE2B 7b9aa801aeb243c0434172d29fc7e79bc8965c19cef0c7e51d9f00c51f7d8aa2bbcbddcba54d924c0d7538d1dbb638ac3b45043ed212df0e3e92471ea0067f08 SHA512 3045e4c78aeb224c3b320b1104f1429bb742d79b8fab4d4b7b1e3711bcc1dbbe1219b81371857207121300cb99606a1695b6c9f707bf755bb7a4b4630c6486d9 -DIST linux-5.10.10.tar.xz 116625516 BLAKE2B 180f0dd063eab9542fd799c54dd335c4f310bea739048800ab3222526cb1ea7cc4ef43d2a2c27ed0e37a776f5c77540c33795aa63297704d9e215735a1a98606 SHA512 05a3f91470e1402510f10d9ad8b04350be7aa1232fec5083e5bb59e16cae8168b1f117b15508fc0dd345d7f8d20a43029a48ebcf54278596b778c37d2f966ca7 -DIST linux-5.10.11.tar.sign 991 BLAKE2B 8ac1b11f90ddde889d6b76e37048804efcf0357dd8cca975b2f2c1df811c69d8108d6c51a92023dda503ce50f4d9b9e5f633e3f22ca62c9b475901fb35a3cd18 SHA512 252f7fb5397d8766a07bd98f05a6a53ca5b606ff2172b3604ecb9f9c6d240ba2b7aec8956d85967bf6de67117a595100be81153376b62fab0fdb0edccd9833be -DIST linux-5.10.11.tar.xz 116619904 BLAKE2B f2ffb77efeab44e5ac74f275f1c728618a0893c752018946a3908a34dca2797982efb6646df1350f31c9cab2b780aca871dff82b63e2ec59e3bfcdafa0457581 SHA512 251cdb885190769551c7c51476113e53ca11ea32f0234491ece3cfffe9f1c15e517dbba1c8f3c0d1a41351e2c14ccfff94aa00301a0c8a4a86b2569b1dd70ca5 -DIST linux-5.10.12.tar.sign 991 BLAKE2B 9071fa84cf4bb38f815935766787b406e54a976bb95d0829e45b8a1fa50b6c1abd31573bd80e6d3fbb955545a719bd640c3e39d58cd93cbecf1456d76ac69a42 SHA512 1f89429aa3b6d7fe27e8fe358c404e486367344ddea43a06ee2e25492956515f72039a97f50617e9a3eeb3b756f42a1cfbd50d732aede13baca284ede027ee83 -DIST linux-5.10.12.tar.xz 116262828 BLAKE2B f5e16e92c9543708997d9dfee28feb2cd6e6909a33dc7f97c40b507a8d03bd72717b1af84bed3fa25b2a167652d8cd93b66d145d484e5ad292af24b3bf64a649 SHA512 01062437c9af1654346b5baf550dbefe3cedab18b3d793ee528d1fc27556d5ecc438b6a39a4163acb65434f50516f8c98a3b1be723afbb620680695b909a376e -DIST linux-5.10.13.tar.sign 991 BLAKE2B 9a6b3d7602a56917bae3c7de7cf24afbce4a0a8e90471da02b87dd7a868898c0553c52e805bf5d0de33c390575582058b60b90154d1ba7e3e8b7810ce75f6c62 SHA512 0dcbc678ae6fb3bd9f71907e7c32c2a60bd1a9d0f6d2106ed50ebd48a59c6a0fccaeea21bb6bc74b390c5674fe4ace7e9d1b44034096f793e9a2f695f5862abd -DIST linux-5.10.13.tar.xz 116258488 BLAKE2B f2d6f5512c10ced0990d0d0cbc1aa29e5b54b90bff01f16d16093e9c192de9eb0f31e60c9dd51c686ce88c2a1d89a49bedb503af61c91a6a186794fbe71eedde SHA512 e894b9a98d34b0734ad87336530361b712ce60b57e47ea51e0efd66a4446e740b7e2bebc489e41e59523c0cc5f4066f36036eac2c4cfd7d99a63682c24d887be -DIST linux-5.10.14.tar.sign 991 BLAKE2B 089cabc583b586a4dcd5d9b9eb0f33903a2110e7bbda492edd220e7116533af06d41b40d987d952656f9ab62f62287c7d79c30bd1283f82060781760a8d6cc01 SHA512 7942ce1d976af3dedf453a3b2ba142a9f2ce1d7a97764b69b92c65262625ecc81c5c432b8bbf29eeb406f233a38f419a56dc01765cc8d15b5ddb655aa77d0cb6 -DIST linux-5.10.14.tar.xz 116254224 BLAKE2B 34ba86c15532eff73ed3cd5d34bb125a534776425a98c43ceff187a9f950c4a12afbe35c5e63306150cdeff5d4e43c5094182d6533381661fe6e5ce82aeaed16 SHA512 8e5016bfc7f5c090af6247ddac41cb3f811576bd078b2e145d798be6f214f72ee77bbff09d48d54a0154a9b137166650c88a1d178d50d5901dcaa03bb2c5e6f1 -DIST linux-5.10.15.tar.sign 991 BLAKE2B c95f2580e972f4cd1dca76a1b16fb15e118cc271b9ee8564e242669c975a27ced4c632d5c8d8e202fd1d0681e6a34660ba777550c7940277666dba7c15968701 SHA512 202bff0d8fcf1356e8c6df1805fcc76993c7320771979bb1f692672af5f3047ac2ca6e03e63518120f959e2d04a45f5dadcc23722b301e8372ca9561d04d7b0b -DIST linux-5.10.15.tar.xz 116262528 BLAKE2B 7cf58513bf2266697843f6d91fbb214268ad511e110a4e2b66bc0db84ecb4df724a7d65f641eee5837f4d88c1371ec8b313ee8aaa1d1f0260709eae2e3af32b3 SHA512 7b2c38920ebfc9c9aea8cb319949f089a374b6604de4fb01dc6957234970d96830761d784c6f94a5f165f5792dfa9d3a6d8691d18147dc05cc0f03c78efbb61a -DIST linux-5.10.9.tar.sign 989 BLAKE2B 4573f4a502d7b86924051da635af393a0d61628fb88f01d14ec5a8b454974b707f547c60bcf965f73af92e850f496c659847142058e61951065db4e2e40cf8e6 SHA512 0a1700731809dd615a8d692a9be195564d6f0edbf722e72d8fd36cecbe4c3dbbcc26e3a194ab08945445a883d5ef3f491f5358d715537240a430bd750179f5f9 -DIST linux-5.10.9.tar.xz 116619508 BLAKE2B faedb4032fd709d3f0089d706232ec0dcfdf3817223aa910112e6cd58bffea20a3127fee407a465fa3b4db1a54050fabd839809c404492820216fadae70885b9 SHA512 63271212f300a58a5c2826052928aa980994fff6af553f801b0d2a1ae05e3b55788cc46fa26c97f330bab74068a93df58ce768f21fc5edd1481c841b975e56cf -DIST linux-5.4.80.tar.sign 989 BLAKE2B 7d0fa889c353c83eeb38d4868de3736baf6dd668db2b6660472b85dd6f9fffa83350954da80bd8e6441b54aa15324d68734ca863b0b1980b92a7b3a58073037e SHA512 54b7a124065020a69702fbc4ec82359c728ba32e8cafb7ba083d12974914c8309cc6b33b85769d87f91cbb2583b7c0a20d019d1b3808f32f07dda0ec795e8906 -DIST linux-5.4.80.tar.xz 109626784 BLAKE2B b395b0326162ca6d9b9a59966e641eb1df63dbd402c8287b276c915478819132e201ae68fcbab2fbae353591ff4f38951a643b6a2e1283a551ab8464c21a2abc SHA512 ba400e61ce4e55a8bf391b45df15bb71f43f42de1f2cf2c19468f503b102ec1269589908fa186bfff946baf031ae1531f30ab420605a078439508898e5fdfb37 -DIST linux-5.4.83.tar.sign 989 BLAKE2B 0c1c9737b51eb02747146498475436682fec4d0e97c6e90e840682878eff34aeffa6970eac0ce117ce18bb8ca2e15fc1a9b0bfb83e021b710fa10dd713437c32 SHA512 be2564571dc109611e802d5dfe1d69339d375bb01259d46888c18ef03979401d9943721131c10609a8a07f14cfe0b990e558e15c7d89a2eccc71e86d620cf4c0 -DIST linux-5.4.83.tar.xz 109638356 BLAKE2B 0287ca87cc09702a3ce9c83494a3f49712aab4f805cab560fdee29cecb18f9ef132c9f8352793705b371f0faf60fd24f357448a8323ba1c1a2d0ab832b5bac8d SHA512 0b40ffb66fc5b3f35a0c187ffeea0df3dd90644490298fe78ad1fef210f1c72e4b0c33aafc6b1d0959c915a6a0d3ec57ae8a36f8b28486965a8ef158674b1ec3 -DIST linux-5.4.88.tar.sign 989 BLAKE2B a3757a095bb72f810847a45e0dcb7401ba264317cbe6ca4a6cad5503ae5836d77795ac26f00c3ceb9166e188904dd074fcaab0080c42413115f9849222c0b8ee SHA512 f91fe3552b889a0aabf0678876221bb5cc0632485e279d75fa25008a9f409711db63ffdd782653302e522ff04f4ed2e0b34d0e5d2dd7d8c2265f370740269165 -DIST linux-5.4.88.tar.xz 109644692 BLAKE2B 002e09b5a4571a6967979cc7907cbd7f064ef8bb38045cabd73de09735157798db058ac0150cd53b83fdcf69740ec0a2034868626d028aab24d01b86bb8577c6 SHA512 85cfc22c93c40dce1032a909c7af4f7f26e0b9506469a401f8d9b569de6e3f6fe177dbfe7044fd8a786358fae4b4a1df10a08b3cef3a3e0d541ce4f750511346 -DIST linux-5.4.91.tar.sign 989 BLAKE2B 9eb7b9e7201ce69e6779a501e6f6e4a862cec1606150a55961a238d6031ed4b4f5d75b7b16dc2ddf9c4be0984fee53ad264d4b6f2bee2ef8e4a4740f23ca5846 SHA512 d2fbbff77bfd2f927d62f14a47587894b0de479de25c01aafcb74d3a52928992303600a8435ccc7025f33731e9dfd437842b707603e30a2192f6eff5f043478a -DIST linux-5.4.91.tar.xz 109653720 BLAKE2B 5b017547953aded31e54a69c2609dfae6e516b50b10d58fe1aeedbbd93652de33aac737a688b284889bf6d0ee2d5d6551eae73a693ddbf45d9d9fdd0663268d1 SHA512 81d02edc9b4ea416e630064904187e981bd607ac9ae795e19935f53bd91a48d0371ba2786693f6c0f26245752113eb8009bcdf7d04664982eb6343584732c22b -DIST linux-5.4.92.tar.sign 989 BLAKE2B 6140d9b3511b2736d1984390997ac4de59d5b4d760283e52b7024e5d6f243499699b08ee2b6a0297bed052ddb5ad77780dc5c4aa1cca03b8fc6c97f610a5bae3 SHA512 e90ca0faf9e7bd6b76187a2bb0f9edee2aa14fb26c0508cd9e55d90ddd973ae1535a39a143f7d5cd4a8081428de874b09b0fda4c2dfac9e639ede0854fb6d3df -DIST linux-5.4.92.tar.xz 109644104 BLAKE2B 9808a44f886bb4d3d48a2e622ca6cdd53e8756d2d85135a46abafde9e37fca2448411080b8b1dcb3c0df85fcf40cf409dddf2dcf9140b186cd8b43d1a21a18b4 SHA512 ad61b167001b3119056c316261d76ae1d7ce16562f3c47599da460a0d2860f1f38a581dbdb72fd0f941bc8a0245522b6856893a3be7d7d5b03775521e168b0b9 -DIST linux-5.4.93.tar.sign 989 BLAKE2B 0c689529e483c971526bb20bab3d5a63e63c18a48d773c30c8d7131606d97b5ee5be0df8e83d34b41230e9239ab108d175912585bf482252352074b7cf9e8354 SHA512 5b273851ccf9bab4ae3a840348fa91e817cb46ed2fa6159bf6289c8eb03a3075c3b06cb31da4a8d2ef6a6d3a9048d4738c4bd73c9c35b3c44b4ecbf09868b6d6 -DIST linux-5.4.93.tar.xz 109661584 BLAKE2B 78f0369835ba737fadb4145fab290408c163c74293fbb29d6e7e28eb7a4f505f90786394509ad955d76d68b8ace919cb2d297fa765efece13aaf9c3e4c056db7 SHA512 b60839ae4efe4563396897723e5cf644e9f15f058efc72b7eb3b91ac42a6190863fa9f7023bbff4f1339a6d542555af34fffe7fb278ca7efb0922585ad27922e +DIST linux-5.10.17.tar.sign 991 BLAKE2B b3b2947df46c96771643ebb2248c83fb81b1ff6bca9191e3ede8e18cf06e5e26ec2c4e179fb1c14026cfddcb110447faeb28fcd7ad93779413353ac8335ef37c SHA512 8abaa8abe2475c0017f755836208c38007c419b832605e81c775d23aa4e23bb20cd5ca88d5a482b331560bb4d940eaf7db3c2a795f77d7b5bb0a39f86130c3a9 +DIST linux-5.10.17.tar.xz 116272648 BLAKE2B 7317e13e6262adf6d69f1192370be8eb2a31054a3626cf20e3e42d4f794f1f1767495c85cc891853a647c246828de31915090706fcdc514c7c563dbd5bbae4bf SHA512 2d8700ceee0c027597415de2b9fa478a651c6f5074b68d60609a4c46398ac5a854f9323fc07b187caca5294759bf99832d7496c4f4cca222240b07435b27bd60 +DIST linux-5.10.18.tar.sign 991 BLAKE2B 2fce16ebaabfa28241ea267bf96c365d044315f7aef281b98153703e86fda15e19d21d89130898a54bb89b61bde7cecaf8ee951ae980ef0bd7d2cd86201d554e SHA512 1e603f79a8783933a078da7d155294ee6cb1490914626c247cd29929a74936297504e1b9967616cbc57bd48da5dae73c26c0a9bab98a5ababb1e689cff0168a4 +DIST linux-5.10.18.tar.xz 116263744 BLAKE2B c633632c8a2c80f238105878c1b4a062ae81e1c7e404b73572c0cb0dd458645cf46c0881cea96668c8cf40a9b12da2d4693e18495f8fee0627ceab87eea34236 SHA512 e9ab577036391692d7237e2d945d8a682afa4bc889f03934db4e1873db26df6404f7ae0cb989986ec64fdb529a3308c6c9c496247596ad43592c1d8fc52e9c46 +DIST linux-5.10.19.tar.sign 991 BLAKE2B 70ee178a74d6c1a779ea399875bb884b52f918e9a8a797fccae7fb26e7eff9eec1a0cc9421e43597d9d477d53d4a26a7fab4afb8f6280a67d48b171829a56bfe SHA512 af99693e0a30d625f346fc682b19bac68247af58574e9a78b2a5478cc0df4a5fca0a2a3ebc3c86f7d5451a6b1f87c0ff524336c4f09b49cfbfb4d21b9776309d +DIST linux-5.10.19.tar.xz 116276000 BLAKE2B bda18c64b1d7be5cba5d3942386764a778a60b360eb47faeb3f2c84806835d2b325b75a00f5cc3a8a3680e0004ff339caa3a7a301cb6a453e838c92b9f89c3db SHA512 95a9e41d3b23a8b88e2a2ad12e6503efe577b80cff398b51ba7f6ccb0b73768a1cefb2cacb727dd54bd5b5638ad1d5cdabdb23c06aed37d726a59b190de1f2d6 +DIST linux-5.11.2.tar.sign 989 BLAKE2B 404589119de8a0bff3e0feb77a54eb98add568470d4260767830ecb488fec415a0eb79a87eb6b19963b26a78ab8944d4041a38a80dc515f42f14350dcf825fcc SHA512 497f0c06d43cede60cb60816bac0cc22a3c7976bb71bb2f2aedced69c44561b842bae94cf51d5cd0ed506c1eb5b58c038bbf17049176f074cd0e7442eded4fdc +DIST linux-5.11.2.tar.xz 117609344 BLAKE2B 62f47c769998fa713cda9024a4ecbe7ba2140acde629082630c2c0b076b4e941b0a1e82f7d2b7cd4ed6e84759ea93de78e212ecbe1341d9055091d26d83286dc SHA512 16090ec6dea7a8c417ca7483b296902c9b55b423482ad8a881dffcaae76411806bc9502373efd6a51b0acefec3a44c19c5a7d42c5b76c1321183a4798a5959d3 +DIST linux-5.4.100.tar.sign 991 BLAKE2B f1442b1523de568ed757ab3ba89d571b0c5d85a192718a85ec72736858c0025b09b0d22eee906d4300e41a8f24ab8d56eb0039ba0b46b63b049a16c8cd65153b SHA512 7e7e298917a6167aa9d3a61cd1423c5fad89fad06f66c1ac01277aba7000dcbb1558f978644558cc79b57d70b677016077f0f4cdc3eaa69e39cda75b0d5b18d7 +DIST linux-5.4.100.tar.xz 109081252 BLAKE2B 2647a326c55050c3f0340c2e7ce98761e8bc3d5900c74785eac779295ba6e84d99d65a2ba9ab575fb412bd5caf6db6d25b32ce9b10373cb3879de2cbafd861a0 SHA512 8483e34ac7ac59903d51ef2b5607fa2608a824d0f95548f3c8eeefe9a6b4be3bef44865df68960feacd02ed7bc8dbbb1625f0bb8e6626bbf096c2a0db474998a +DIST linux-5.4.101.tar.sign 991 BLAKE2B f10908550c9ebe18dcc06839046ea215d5fa91cef48180836c2582a3200852dd005e39ff5ed6b203bc5ffb4098018fe2437d363ae84404370a9f40e8e92d446d SHA512 bcae0baa578b248d21b270106b5ba0b4ea23f383a24086ba04d7433c2df534ddac9f2373383407637cc3a8e81d14e3f5407dababc3b01333bbeafd36101e2f54 +DIST linux-5.4.101.tar.xz 109078848 BLAKE2B 9dd7727655005ba2bf906fbaac86107dbe541cd42878eb3fb96f9731e8196b4e059dbcd772e7c11c620ef784d09ed353f7d92e2388adecc0906d1c71fc8edea3 SHA512 225d5aeb1e0aad9f048cafe94477c8ea5123f26145681b2a2fe24f81dc61694f964b585b6cdc63eaf3898e5feb38159097cb611b9e2e2455de331e6a4875970e DIST linux-5.4.94.tar.sign 989 BLAKE2B 779a725d0164c98bf2ebc0590af693eebb6fe71837e0f8642b376fb0fa4bc893e8c2b52a16bd0c1cab7aaff4295f6bf31b8fdb7c2d95bd8601eac74925e2211f SHA512 85ec9c16642aac5640d0486ba704b787e2e4156fccdf80f4d538b4d6524c914b64e6ba1d52bdda15b3601faec643d6656fa2cf57976a9afaff5265f9dea840e0 DIST linux-5.4.94.tar.xz 109082512 BLAKE2B fac6683453e41065760cbdd170ea4a5f72778e39807389d2f4c4dd9165dc1727a875ee26e6e440089ec2d8e8b4dca9fa1e1dc02a9b217cada700f9a118ae7613 SHA512 2d9f0feeb9ba6871d31c8a5e281c8e3eed99ce7da3af3be4f222db37f082374f852021a5117a994c8cc37681e5f335329c9e430e7edb835de801c901765a505b -DIST linux-5.4.95.tar.sign 989 BLAKE2B 527763c6afbf7e02269dbe1c4779c5a5464e428a0fae9f44351aeff301ba629b148497a7beb11f9d53479d33414704a5db9ce2535b027e7beda45aef35dc62c3 SHA512 31104d4db2b30a95df0574bcc7eecc07e579b8bbac378d31b015a00294d3a17569f165d5aaed5ae9231c4e707eaf0b2d0d3c594c046c53daad6be31822d4dcb9 -DIST linux-5.4.95.tar.xz 109065052 BLAKE2B 732c57458e4179cf87c46c7ef80e4afbf445e462d877b29d4111b5a8256a0d88879136f6184361b6d8eb2c623978297d994d4db6e572f56f393a917bdf8f540f SHA512 c6f5b306a8dc844dfff006ecc27879a8e120100bee8b429a143cebafd689403d93d8650dc3d962d4e13e906476c4b43bb32e4f2dbcc3002eee9dd070d63b26f7 -DIST linux-5.4.96.tar.sign 989 BLAKE2B b4641189da90cf6e854d9ff9d5cfa7d6f559f4f5fbd9f795a820a0e3f1a57d56122c2a59a94ebaba5c9e444a5839e9bcb684a4139ff09bb6299ad732c462ce86 SHA512 481673d29883c0f150bc1df483e763152aeba251d742471216710d7af61e4ab0f95f6220dfcda0d267d63a5e7d997e700434d8efe8dd0f39f9dee23335383bda -DIST linux-5.4.96.tar.xz 109075552 BLAKE2B b6e604030f3d1f14880a38ec65d2169e668a7eeb43f21045fef28be98560a7fcc91189149a3ccbf2500f3d55860ef71351ea1c79cceb940c67beb6b01149c912 SHA512 4f2017c374af9485aaec6fc021cfa22a1f5e635a2fca7ffe5cd535306a93d3ebcb985d30491f7f4e05ce1d91647ff62a41e766a677acfa7f5b0269b808e069c4 DIST linux-5.4.97.tar.sign 989 BLAKE2B 767058a0c491aa1435d5dcd25d5f26ed1dd283cbb903063d00020e2a5e7a2a965b7774df3fe4e5484bb1c76e906e9622057f60420d9dfe31a5305d85b15e2d1e SHA512 09fc4efaf777d12cfeb61e7d24651ca68461c108666be90bf216ee5586cabf47976d60451f8cbdb636ff3f3a4b66b84edfc0255b26d3589f918c22aa394dd76a DIST linux-5.4.97.tar.xz 109075272 BLAKE2B d8362d202d437953fa7c78a1e7dc3eda31d1fb605b176a92ced0b9d6608c92134fcf1ae8426308f07d5af5cb5fabbee6122cc30bff8abf6a99dc4b5848d3a16c SHA512 fb882d5949ac0cab2910947cc2af3c6f219ff4d8b6941100972caad8133486678a2dfe8af68c9d527a2f55b663a96dabf8c41ea85d941c04934016a0c067eb70 +DIST linux-5.4.99.tar.sign 989 BLAKE2B 92c51f2da875787cc3867319e8e174925443bf43cf07f9dd54d31ba34852e946ae73158db1dc6532c90c3589a3e6bfc27cae42ac22359a2b15999cdf5b3d008f SHA512 5c332cc60d29d615354b1e555dde31e3aaf8846ccc8c4bfe7bc5ebdce20d4a491af367388f1f07feed81f6eaaabb1baf4afc9d995f00541843f2d18eef9c2580 +DIST linux-5.4.99.tar.xz 109078664 BLAKE2B f0a869edf3aa04a2211f039561fa16a419ebde44437c1aca9ac8a7f11ccda240b58eef45c2135a4d7ccd4b7093cf5ce758fba1ed850a653c2debc33f90d4ba91 SHA512 e064ff3c68291c7fb6823499230b3838b5a9471d9e0789ab6eea89ac1cc9c579dc3670dfa3f64cc0c2b68b8027cdb2a239158da73ce7febd600d424eafd6d203 diff --git a/sys-kernel/vanilla-kernel/metadata.xml b/sys-kernel/vanilla-kernel/metadata.xml index b0b959adbe61..3eca39567e28 100644 --- a/sys-kernel/vanilla-kernel/metadata.xml +++ b/sys-kernel/vanilla-kernel/metadata.xml @@ -1,11 +1,13 @@ <?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE pkgmetadata SYSTEM "http://www.gentoo.org/dtd/metadata.dtd"> +<!DOCTYPE pkgmetadata SYSTEM "https://liguros.gitlab.io/dtd/metadata.dtd"> <pkgmetadata> - <maintainer type="project"> - <email>dist-kernel@gentoo.org</email> - <name>Distribution Kernel Project</name> - </maintainer> - <use> - <flag name='initramfs'>Build initramfs along with the kernel.</flag> - </use> -</pkgmetadata> + <maintainer type="project"> + <email>dist-kernel@gentoo.org</email> + <name>Distribution Kernel Project</name> + </maintainer> + + <use> + <flag name="initramfs">Build initramfs along with the kernel.</flag> + </use> + <origin>gentoo-staging</origin> +</pkgmetadata>
\ No newline at end of file diff --git a/sys-kernel/vanilla-kernel/vanilla-kernel-5.10.11.ebuild b/sys-kernel/vanilla-kernel/vanilla-kernel-5.10.11.ebuild deleted file mode 100644 index 51afd5f766b8..000000000000 --- a/sys-kernel/vanilla-kernel/vanilla-kernel-5.10.11.ebuild +++ /dev/null @@ -1,100 +0,0 @@ -# Copyright 2020-2021 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI=7 - -inherit kernel-build verify-sig - -MY_P=linux-${PV} -# https://koji.fedoraproject.org/koji/packageinfo?packageID=8 -CONFIG_VER=5.10.7 -CONFIG_HASH=b238267df7cd80dc3aa6b5b654cbe145367383df -GENTOO_CONFIG_VER=5.10.7 - -DESCRIPTION="Linux kernel built from vanilla upstream sources" -HOMEPAGE="https://www.kernel.org/" -SRC_URI+=" https://cdn.kernel.org/pub/linux/kernel/v$(ver_cut 1).x/${MY_P}.tar.xz - https://github.com/mgorny/gentoo-kernel-config/archive/v${GENTOO_CONFIG_VER}.tar.gz - -> gentoo-kernel-config-${GENTOO_CONFIG_VER}.tar.gz - verify-sig? ( - https://cdn.kernel.org/pub/linux/kernel/v$(ver_cut 1).x/${MY_P}.tar.sign - ) - amd64? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-x86_64-fedora.config - -> kernel-x86_64-fedora.config.${CONFIG_VER} - ) - arm64? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-aarch64-fedora.config - -> kernel-aarch64-fedora.config.${CONFIG_VER} - ) - ppc64? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-ppc64le-fedora.config - -> kernel-ppc64le-fedora.config.${CONFIG_VER} - ) - x86? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-i686-fedora.config - -> kernel-i686-fedora.config.${CONFIG_VER} - )" -S=${WORKDIR}/${MY_P} - -LICENSE="GPL-2" -KEYWORDS="~amd64 ~arm ~arm64 ~ppc64 ~x86" -IUSE="debug" -REQUIRED_USE=" - arm? ( savedconfig )" - -RDEPEND=" - !sys-kernel/vanilla-kernel-bin:${SLOT}" -BDEPEND=" - debug? ( dev-util/dwarves ) - verify-sig? ( app-crypt/openpgp-keys-kernel )" -PDEPEND=" - >=virtual/dist-kernel-${PV}" - -VERIFY_SIG_OPENPGP_KEY_PATH=${BROOT}/usr/share/openpgp-keys/kernel.org.asc - -src_unpack() { - if use verify-sig; then - einfo "Unpacking linux-${PV}.tar.xz ..." - verify-sig_verify_detached - "${DISTDIR}"/linux-${PV}.tar.sign \ - < <(xz -cd "${DISTDIR}"/linux-${PV}.tar.xz | tee >(tar -x)) - assert "Unpack failed" - unpack "gentoo-kernel-config-${GENTOO_CONFIG_VER}.tar.gz" - else - default - fi -} - -src_prepare() { - default - - # prepare the default config - case ${ARCH} in - amd64) - cp "${DISTDIR}/kernel-x86_64-fedora.config.${CONFIG_VER}" .config || die - ;; - arm) - return - ;; - arm64) - cp "${DISTDIR}/kernel-aarch64-fedora.config.${CONFIG_VER}" .config || die - ;; - ppc64) - cp "${DISTDIR}/kernel-ppc64le-fedora.config.${CONFIG_VER}" .config || die - ;; - x86) - cp "${DISTDIR}/kernel-i686-fedora.config.${CONFIG_VER}" .config || die - ;; - *) - die "Unsupported arch ${ARCH}" - ;; - esac - - local merge_configs=( - "${WORKDIR}/gentoo-kernel-config-${GENTOO_CONFIG_VER}"/base.config - ) - use debug || merge_configs+=( - "${WORKDIR}/gentoo-kernel-config-${GENTOO_CONFIG_VER}"/no-debug.config - ) - kernel-build_merge_configs "${merge_configs[@]}" -} diff --git a/sys-kernel/vanilla-kernel/vanilla-kernel-5.10.12.ebuild b/sys-kernel/vanilla-kernel/vanilla-kernel-5.10.12.ebuild deleted file mode 100644 index 51afd5f766b8..000000000000 --- a/sys-kernel/vanilla-kernel/vanilla-kernel-5.10.12.ebuild +++ /dev/null @@ -1,100 +0,0 @@ -# Copyright 2020-2021 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI=7 - -inherit kernel-build verify-sig - -MY_P=linux-${PV} -# https://koji.fedoraproject.org/koji/packageinfo?packageID=8 -CONFIG_VER=5.10.7 -CONFIG_HASH=b238267df7cd80dc3aa6b5b654cbe145367383df -GENTOO_CONFIG_VER=5.10.7 - -DESCRIPTION="Linux kernel built from vanilla upstream sources" -HOMEPAGE="https://www.kernel.org/" -SRC_URI+=" https://cdn.kernel.org/pub/linux/kernel/v$(ver_cut 1).x/${MY_P}.tar.xz - https://github.com/mgorny/gentoo-kernel-config/archive/v${GENTOO_CONFIG_VER}.tar.gz - -> gentoo-kernel-config-${GENTOO_CONFIG_VER}.tar.gz - verify-sig? ( - https://cdn.kernel.org/pub/linux/kernel/v$(ver_cut 1).x/${MY_P}.tar.sign - ) - amd64? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-x86_64-fedora.config - -> kernel-x86_64-fedora.config.${CONFIG_VER} - ) - arm64? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-aarch64-fedora.config - -> kernel-aarch64-fedora.config.${CONFIG_VER} - ) - ppc64? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-ppc64le-fedora.config - -> kernel-ppc64le-fedora.config.${CONFIG_VER} - ) - x86? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-i686-fedora.config - -> kernel-i686-fedora.config.${CONFIG_VER} - )" -S=${WORKDIR}/${MY_P} - -LICENSE="GPL-2" -KEYWORDS="~amd64 ~arm ~arm64 ~ppc64 ~x86" -IUSE="debug" -REQUIRED_USE=" - arm? ( savedconfig )" - -RDEPEND=" - !sys-kernel/vanilla-kernel-bin:${SLOT}" -BDEPEND=" - debug? ( dev-util/dwarves ) - verify-sig? ( app-crypt/openpgp-keys-kernel )" -PDEPEND=" - >=virtual/dist-kernel-${PV}" - -VERIFY_SIG_OPENPGP_KEY_PATH=${BROOT}/usr/share/openpgp-keys/kernel.org.asc - -src_unpack() { - if use verify-sig; then - einfo "Unpacking linux-${PV}.tar.xz ..." - verify-sig_verify_detached - "${DISTDIR}"/linux-${PV}.tar.sign \ - < <(xz -cd "${DISTDIR}"/linux-${PV}.tar.xz | tee >(tar -x)) - assert "Unpack failed" - unpack "gentoo-kernel-config-${GENTOO_CONFIG_VER}.tar.gz" - else - default - fi -} - -src_prepare() { - default - - # prepare the default config - case ${ARCH} in - amd64) - cp "${DISTDIR}/kernel-x86_64-fedora.config.${CONFIG_VER}" .config || die - ;; - arm) - return - ;; - arm64) - cp "${DISTDIR}/kernel-aarch64-fedora.config.${CONFIG_VER}" .config || die - ;; - ppc64) - cp "${DISTDIR}/kernel-ppc64le-fedora.config.${CONFIG_VER}" .config || die - ;; - x86) - cp "${DISTDIR}/kernel-i686-fedora.config.${CONFIG_VER}" .config || die - ;; - *) - die "Unsupported arch ${ARCH}" - ;; - esac - - local merge_configs=( - "${WORKDIR}/gentoo-kernel-config-${GENTOO_CONFIG_VER}"/base.config - ) - use debug || merge_configs+=( - "${WORKDIR}/gentoo-kernel-config-${GENTOO_CONFIG_VER}"/no-debug.config - ) - kernel-build_merge_configs "${merge_configs[@]}" -} diff --git a/sys-kernel/vanilla-kernel/vanilla-kernel-5.10.13.ebuild b/sys-kernel/vanilla-kernel/vanilla-kernel-5.10.17.ebuild index 04ef5ea94afc..04ef5ea94afc 100644 --- a/sys-kernel/vanilla-kernel/vanilla-kernel-5.10.13.ebuild +++ b/sys-kernel/vanilla-kernel/vanilla-kernel-5.10.17.ebuild diff --git a/sys-kernel/vanilla-kernel/vanilla-kernel-5.10.15.ebuild b/sys-kernel/vanilla-kernel/vanilla-kernel-5.10.18.ebuild index 04ef5ea94afc..9fe09baa8621 100644 --- a/sys-kernel/vanilla-kernel/vanilla-kernel-5.10.15.ebuild +++ b/sys-kernel/vanilla-kernel/vanilla-kernel-5.10.18.ebuild @@ -9,7 +9,7 @@ MY_P=linux-${PV} # https://koji.fedoraproject.org/koji/packageinfo?packageID=8 CONFIG_VER=5.10.12 CONFIG_HASH=836165dd2dff34e4f2c47ca8f9c803002c1e6530 -GENTOO_CONFIG_VER=5.10.7 +GENTOO_CONFIG_VER=5.10.18 DESCRIPTION="Linux kernel built from vanilla upstream sources" HOMEPAGE="https://www.kernel.org/" diff --git a/sys-kernel/vanilla-kernel/vanilla-kernel-5.10.14.ebuild b/sys-kernel/vanilla-kernel/vanilla-kernel-5.10.19.ebuild index 04ef5ea94afc..9fe09baa8621 100644 --- a/sys-kernel/vanilla-kernel/vanilla-kernel-5.10.14.ebuild +++ b/sys-kernel/vanilla-kernel/vanilla-kernel-5.10.19.ebuild @@ -9,7 +9,7 @@ MY_P=linux-${PV} # https://koji.fedoraproject.org/koji/packageinfo?packageID=8 CONFIG_VER=5.10.12 CONFIG_HASH=836165dd2dff34e4f2c47ca8f9c803002c1e6530 -GENTOO_CONFIG_VER=5.10.7 +GENTOO_CONFIG_VER=5.10.18 DESCRIPTION="Linux kernel built from vanilla upstream sources" HOMEPAGE="https://www.kernel.org/" diff --git a/sys-kernel/vanilla-kernel/vanilla-kernel-5.10.9.ebuild b/sys-kernel/vanilla-kernel/vanilla-kernel-5.10.9.ebuild deleted file mode 100644 index 51afd5f766b8..000000000000 --- a/sys-kernel/vanilla-kernel/vanilla-kernel-5.10.9.ebuild +++ /dev/null @@ -1,100 +0,0 @@ -# Copyright 2020-2021 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI=7 - -inherit kernel-build verify-sig - -MY_P=linux-${PV} -# https://koji.fedoraproject.org/koji/packageinfo?packageID=8 -CONFIG_VER=5.10.7 -CONFIG_HASH=b238267df7cd80dc3aa6b5b654cbe145367383df -GENTOO_CONFIG_VER=5.10.7 - -DESCRIPTION="Linux kernel built from vanilla upstream sources" -HOMEPAGE="https://www.kernel.org/" -SRC_URI+=" https://cdn.kernel.org/pub/linux/kernel/v$(ver_cut 1).x/${MY_P}.tar.xz - https://github.com/mgorny/gentoo-kernel-config/archive/v${GENTOO_CONFIG_VER}.tar.gz - -> gentoo-kernel-config-${GENTOO_CONFIG_VER}.tar.gz - verify-sig? ( - https://cdn.kernel.org/pub/linux/kernel/v$(ver_cut 1).x/${MY_P}.tar.sign - ) - amd64? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-x86_64-fedora.config - -> kernel-x86_64-fedora.config.${CONFIG_VER} - ) - arm64? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-aarch64-fedora.config - -> kernel-aarch64-fedora.config.${CONFIG_VER} - ) - ppc64? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-ppc64le-fedora.config - -> kernel-ppc64le-fedora.config.${CONFIG_VER} - ) - x86? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-i686-fedora.config - -> kernel-i686-fedora.config.${CONFIG_VER} - )" -S=${WORKDIR}/${MY_P} - -LICENSE="GPL-2" -KEYWORDS="~amd64 ~arm ~arm64 ~ppc64 ~x86" -IUSE="debug" -REQUIRED_USE=" - arm? ( savedconfig )" - -RDEPEND=" - !sys-kernel/vanilla-kernel-bin:${SLOT}" -BDEPEND=" - debug? ( dev-util/dwarves ) - verify-sig? ( app-crypt/openpgp-keys-kernel )" -PDEPEND=" - >=virtual/dist-kernel-${PV}" - -VERIFY_SIG_OPENPGP_KEY_PATH=${BROOT}/usr/share/openpgp-keys/kernel.org.asc - -src_unpack() { - if use verify-sig; then - einfo "Unpacking linux-${PV}.tar.xz ..." - verify-sig_verify_detached - "${DISTDIR}"/linux-${PV}.tar.sign \ - < <(xz -cd "${DISTDIR}"/linux-${PV}.tar.xz | tee >(tar -x)) - assert "Unpack failed" - unpack "gentoo-kernel-config-${GENTOO_CONFIG_VER}.tar.gz" - else - default - fi -} - -src_prepare() { - default - - # prepare the default config - case ${ARCH} in - amd64) - cp "${DISTDIR}/kernel-x86_64-fedora.config.${CONFIG_VER}" .config || die - ;; - arm) - return - ;; - arm64) - cp "${DISTDIR}/kernel-aarch64-fedora.config.${CONFIG_VER}" .config || die - ;; - ppc64) - cp "${DISTDIR}/kernel-ppc64le-fedora.config.${CONFIG_VER}" .config || die - ;; - x86) - cp "${DISTDIR}/kernel-i686-fedora.config.${CONFIG_VER}" .config || die - ;; - *) - die "Unsupported arch ${ARCH}" - ;; - esac - - local merge_configs=( - "${WORKDIR}/gentoo-kernel-config-${GENTOO_CONFIG_VER}"/base.config - ) - use debug || merge_configs+=( - "${WORKDIR}/gentoo-kernel-config-${GENTOO_CONFIG_VER}"/no-debug.config - ) - kernel-build_merge_configs "${merge_configs[@]}" -} diff --git a/sys-kernel/vanilla-kernel/vanilla-kernel-5.10.10.ebuild b/sys-kernel/vanilla-kernel/vanilla-kernel-5.11.2.ebuild index 51afd5f766b8..6faf44c48778 100644 --- a/sys-kernel/vanilla-kernel/vanilla-kernel-5.10.10.ebuild +++ b/sys-kernel/vanilla-kernel/vanilla-kernel-5.11.2.ebuild @@ -7,9 +7,9 @@ inherit kernel-build verify-sig MY_P=linux-${PV} # https://koji.fedoraproject.org/koji/packageinfo?packageID=8 -CONFIG_VER=5.10.7 -CONFIG_HASH=b238267df7cd80dc3aa6b5b654cbe145367383df -GENTOO_CONFIG_VER=5.10.7 +CONFIG_VER=5.11.1 +CONFIG_HASH=07992209452cd7ba529ffdbdd83d01d44cd8ae14 +GENTOO_CONFIG_VER=5.10.18 DESCRIPTION="Linux kernel built from vanilla upstream sources" HOMEPAGE="https://www.kernel.org/" diff --git a/sys-kernel/vanilla-kernel/vanilla-kernel-5.4.91.ebuild b/sys-kernel/vanilla-kernel/vanilla-kernel-5.4.100.ebuild index f8ec23f5913a..f8ec23f5913a 100644 --- a/sys-kernel/vanilla-kernel/vanilla-kernel-5.4.91.ebuild +++ b/sys-kernel/vanilla-kernel/vanilla-kernel-5.4.100.ebuild diff --git a/sys-kernel/vanilla-kernel/vanilla-kernel-5.4.92.ebuild b/sys-kernel/vanilla-kernel/vanilla-kernel-5.4.101.ebuild index f8ec23f5913a..f8ec23f5913a 100644 --- a/sys-kernel/vanilla-kernel/vanilla-kernel-5.4.92.ebuild +++ b/sys-kernel/vanilla-kernel/vanilla-kernel-5.4.101.ebuild diff --git a/sys-kernel/vanilla-kernel/vanilla-kernel-5.4.80.ebuild b/sys-kernel/vanilla-kernel/vanilla-kernel-5.4.80.ebuild deleted file mode 100644 index 7f4ea0861252..000000000000 --- a/sys-kernel/vanilla-kernel/vanilla-kernel-5.4.80.ebuild +++ /dev/null @@ -1,104 +0,0 @@ -# Copyright 2020 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI=7 - -inherit kernel-build verify-sig - -MY_P=linux-${PV} -# https://koji.fedoraproject.org/koji/packageinfo?packageID=8 -CONFIG_VER=5.4.21 -CONFIG_HASH=2809b7faa6a8cb232cd825096c146b7bdc1e08ea -GENTOO_CONFIG_VER=5.4.77-r1 - -DESCRIPTION="Linux kernel built from vanilla upstream sources" -HOMEPAGE="https://www.kernel.org/" -SRC_URI+=" https://cdn.kernel.org/pub/linux/kernel/v$(ver_cut 1).x/${MY_P}.tar.xz - https://github.com/mgorny/gentoo-kernel-config/archive/v${GENTOO_CONFIG_VER}.tar.gz - -> gentoo-kernel-config-${GENTOO_CONFIG_VER}.tar.gz - verify-sig? ( - https://cdn.kernel.org/pub/linux/kernel/v$(ver_cut 1).x/${MY_P}.tar.sign - ) - amd64? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-x86_64.config - -> kernel-x86_64.config.${CONFIG_VER} - ) - arm64? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-aarch64.config - -> kernel-aarch64.config.${CONFIG_VER} - ) - ppc64? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-ppc64le.config - -> kernel-ppc64le.config.${CONFIG_VER} - ) - x86? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-i686.config - -> kernel-i686.config.${CONFIG_VER} - )" -S=${WORKDIR}/${MY_P} - -LICENSE="GPL-2" -KEYWORDS="~amd64 ~arm64 ~x86" -IUSE="debug" - -RDEPEND=" - !sys-kernel/vanilla-kernel-bin:${SLOT}" -BDEPEND=" - debug? ( dev-util/dwarves ) - verify-sig? ( app-crypt/openpgp-keys-kernel )" - -VERIFY_SIG_OPENPGP_KEY_PATH=${BROOT}/usr/share/openpgp-keys/kernel.org.asc - -pkg_pretend() { - ewarn "Starting with 5.4.52, Distribution Kernels are switching from Arch" - ewarn "Linux configs to Fedora. Please keep a backup kernel just in case." - - kernel-install_pkg_pretend -} - -src_unpack() { - if use verify-sig; then - einfo "Unpacking linux-${PV}.tar.xz ..." - verify-sig_verify_detached - "${DISTDIR}"/linux-${PV}.tar.sign \ - < <(xz -cd "${DISTDIR}"/linux-${PV}.tar.xz | tee >(tar -x)) - assert "Unpack failed" - unpack "gentoo-kernel-config-${GENTOO_CONFIG_VER}.tar.gz" - else - default - fi -} - -src_prepare() { - default - - # prepare the default config - case ${ARCH} in - amd64) - cp "${DISTDIR}/kernel-x86_64.config.${CONFIG_VER}" .config || die - ;; - arm64) - cp "${DISTDIR}/kernel-aarch64.config.${CONFIG_VER}" .config || die - ;; - ppc64) - cp "${DISTDIR}/kernel-ppc64le.config.${CONFIG_VER}" .config || die - ;; - x86) - cp "${DISTDIR}/kernel-i686.config.${CONFIG_VER}" .config || die - ;; - *) - die "Unsupported arch ${ARCH}" - ;; - esac - - local merge_configs=( - "${WORKDIR}/gentoo-kernel-config-${GENTOO_CONFIG_VER}"/base.config - ) - use debug || merge_configs+=( - "${WORKDIR}/gentoo-kernel-config-${GENTOO_CONFIG_VER}"/no-debug.config - ) - [[ ${ARCH} == x86 ]] && merge_configs+=( - "${WORKDIR}/gentoo-kernel-config-${GENTOO_CONFIG_VER}"/32-bit.config - ) - - kernel-build_merge_configs "${merge_configs[@]}" -} diff --git a/sys-kernel/vanilla-kernel/vanilla-kernel-5.4.83.ebuild b/sys-kernel/vanilla-kernel/vanilla-kernel-5.4.83.ebuild deleted file mode 100644 index 7f4ea0861252..000000000000 --- a/sys-kernel/vanilla-kernel/vanilla-kernel-5.4.83.ebuild +++ /dev/null @@ -1,104 +0,0 @@ -# Copyright 2020 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI=7 - -inherit kernel-build verify-sig - -MY_P=linux-${PV} -# https://koji.fedoraproject.org/koji/packageinfo?packageID=8 -CONFIG_VER=5.4.21 -CONFIG_HASH=2809b7faa6a8cb232cd825096c146b7bdc1e08ea -GENTOO_CONFIG_VER=5.4.77-r1 - -DESCRIPTION="Linux kernel built from vanilla upstream sources" -HOMEPAGE="https://www.kernel.org/" -SRC_URI+=" https://cdn.kernel.org/pub/linux/kernel/v$(ver_cut 1).x/${MY_P}.tar.xz - https://github.com/mgorny/gentoo-kernel-config/archive/v${GENTOO_CONFIG_VER}.tar.gz - -> gentoo-kernel-config-${GENTOO_CONFIG_VER}.tar.gz - verify-sig? ( - https://cdn.kernel.org/pub/linux/kernel/v$(ver_cut 1).x/${MY_P}.tar.sign - ) - amd64? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-x86_64.config - -> kernel-x86_64.config.${CONFIG_VER} - ) - arm64? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-aarch64.config - -> kernel-aarch64.config.${CONFIG_VER} - ) - ppc64? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-ppc64le.config - -> kernel-ppc64le.config.${CONFIG_VER} - ) - x86? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-i686.config - -> kernel-i686.config.${CONFIG_VER} - )" -S=${WORKDIR}/${MY_P} - -LICENSE="GPL-2" -KEYWORDS="~amd64 ~arm64 ~x86" -IUSE="debug" - -RDEPEND=" - !sys-kernel/vanilla-kernel-bin:${SLOT}" -BDEPEND=" - debug? ( dev-util/dwarves ) - verify-sig? ( app-crypt/openpgp-keys-kernel )" - -VERIFY_SIG_OPENPGP_KEY_PATH=${BROOT}/usr/share/openpgp-keys/kernel.org.asc - -pkg_pretend() { - ewarn "Starting with 5.4.52, Distribution Kernels are switching from Arch" - ewarn "Linux configs to Fedora. Please keep a backup kernel just in case." - - kernel-install_pkg_pretend -} - -src_unpack() { - if use verify-sig; then - einfo "Unpacking linux-${PV}.tar.xz ..." - verify-sig_verify_detached - "${DISTDIR}"/linux-${PV}.tar.sign \ - < <(xz -cd "${DISTDIR}"/linux-${PV}.tar.xz | tee >(tar -x)) - assert "Unpack failed" - unpack "gentoo-kernel-config-${GENTOO_CONFIG_VER}.tar.gz" - else - default - fi -} - -src_prepare() { - default - - # prepare the default config - case ${ARCH} in - amd64) - cp "${DISTDIR}/kernel-x86_64.config.${CONFIG_VER}" .config || die - ;; - arm64) - cp "${DISTDIR}/kernel-aarch64.config.${CONFIG_VER}" .config || die - ;; - ppc64) - cp "${DISTDIR}/kernel-ppc64le.config.${CONFIG_VER}" .config || die - ;; - x86) - cp "${DISTDIR}/kernel-i686.config.${CONFIG_VER}" .config || die - ;; - *) - die "Unsupported arch ${ARCH}" - ;; - esac - - local merge_configs=( - "${WORKDIR}/gentoo-kernel-config-${GENTOO_CONFIG_VER}"/base.config - ) - use debug || merge_configs+=( - "${WORKDIR}/gentoo-kernel-config-${GENTOO_CONFIG_VER}"/no-debug.config - ) - [[ ${ARCH} == x86 ]] && merge_configs+=( - "${WORKDIR}/gentoo-kernel-config-${GENTOO_CONFIG_VER}"/32-bit.config - ) - - kernel-build_merge_configs "${merge_configs[@]}" -} diff --git a/sys-kernel/vanilla-kernel/vanilla-kernel-5.4.88.ebuild b/sys-kernel/vanilla-kernel/vanilla-kernel-5.4.88.ebuild deleted file mode 100644 index af6cbd04ffc6..000000000000 --- a/sys-kernel/vanilla-kernel/vanilla-kernel-5.4.88.ebuild +++ /dev/null @@ -1,107 +0,0 @@ -# Copyright 2020-2021 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI=7 - -inherit kernel-build verify-sig - -MY_P=linux-${PV} -# https://koji.fedoraproject.org/koji/packageinfo?packageID=8 -CONFIG_VER=5.4.21 -CONFIG_HASH=2809b7faa6a8cb232cd825096c146b7bdc1e08ea -GENTOO_CONFIG_VER=5.4.77-r1 - -DESCRIPTION="Linux kernel built from vanilla upstream sources" -HOMEPAGE="https://www.kernel.org/" -SRC_URI+=" https://cdn.kernel.org/pub/linux/kernel/v$(ver_cut 1).x/${MY_P}.tar.xz - https://github.com/mgorny/gentoo-kernel-config/archive/v${GENTOO_CONFIG_VER}.tar.gz - -> gentoo-kernel-config-${GENTOO_CONFIG_VER}.tar.gz - verify-sig? ( - https://cdn.kernel.org/pub/linux/kernel/v$(ver_cut 1).x/${MY_P}.tar.sign - ) - amd64? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-x86_64.config - -> kernel-x86_64.config.${CONFIG_VER} - ) - arm64? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-aarch64.config - -> kernel-aarch64.config.${CONFIG_VER} - ) - ppc64? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-ppc64le.config - -> kernel-ppc64le.config.${CONFIG_VER} - ) - x86? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-i686.config - -> kernel-i686.config.${CONFIG_VER} - )" -S=${WORKDIR}/${MY_P} - -LICENSE="GPL-2" -KEYWORDS="~amd64 ~arm64 ~x86" -IUSE="debug" - -RDEPEND=" - !sys-kernel/vanilla-kernel-bin:${SLOT}" -BDEPEND=" - debug? ( dev-util/dwarves ) - verify-sig? ( app-crypt/openpgp-keys-kernel )" -PDEPEND=" - >=virtual/dist-kernel-${PV}" - -VERIFY_SIG_OPENPGP_KEY_PATH=${BROOT}/usr/share/openpgp-keys/kernel.org.asc - -pkg_pretend() { - ewarn "Starting with 5.4.52, Distribution Kernels are switching from Arch" - ewarn "Linux configs to Fedora. Please keep a backup kernel just in case." - - kernel-install_pkg_pretend -} - -src_unpack() { - [[ ${PV} == 5.4.88 ]] || die "Bump GENTOO_CONFIG_VER!" - if use verify-sig; then - einfo "Unpacking linux-${PV}.tar.xz ..." - verify-sig_verify_detached - "${DISTDIR}"/linux-${PV}.tar.sign \ - < <(xz -cd "${DISTDIR}"/linux-${PV}.tar.xz | tee >(tar -x)) - assert "Unpack failed" - unpack "gentoo-kernel-config-${GENTOO_CONFIG_VER}.tar.gz" - else - default - fi -} - -src_prepare() { - default - - # prepare the default config - case ${ARCH} in - amd64) - cp "${DISTDIR}/kernel-x86_64.config.${CONFIG_VER}" .config || die - ;; - arm64) - cp "${DISTDIR}/kernel-aarch64.config.${CONFIG_VER}" .config || die - ;; - ppc64) - cp "${DISTDIR}/kernel-ppc64le.config.${CONFIG_VER}" .config || die - ;; - x86) - cp "${DISTDIR}/kernel-i686.config.${CONFIG_VER}" .config || die - ;; - *) - die "Unsupported arch ${ARCH}" - ;; - esac - - local merge_configs=( - "${WORKDIR}/gentoo-kernel-config-${GENTOO_CONFIG_VER}"/base.config - ) - use debug || merge_configs+=( - "${WORKDIR}/gentoo-kernel-config-${GENTOO_CONFIG_VER}"/no-debug.config - ) - [[ ${ARCH} == x86 ]] && merge_configs+=( - "${WORKDIR}/gentoo-kernel-config-${GENTOO_CONFIG_VER}"/32-bit.config - ) - - kernel-build_merge_configs "${merge_configs[@]}" -} diff --git a/sys-kernel/vanilla-kernel/vanilla-kernel-5.4.95.ebuild b/sys-kernel/vanilla-kernel/vanilla-kernel-5.4.95.ebuild deleted file mode 100644 index f8ec23f5913a..000000000000 --- a/sys-kernel/vanilla-kernel/vanilla-kernel-5.4.95.ebuild +++ /dev/null @@ -1,106 +0,0 @@ -# Copyright 2020-2021 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI=7 - -inherit kernel-build verify-sig - -MY_P=linux-${PV} -# https://koji.fedoraproject.org/koji/packageinfo?packageID=8 -CONFIG_VER=5.4.21 -CONFIG_HASH=2809b7faa6a8cb232cd825096c146b7bdc1e08ea -GENTOO_CONFIG_VER=5.4.89 - -DESCRIPTION="Linux kernel built from vanilla upstream sources" -HOMEPAGE="https://www.kernel.org/" -SRC_URI+=" https://cdn.kernel.org/pub/linux/kernel/v$(ver_cut 1).x/${MY_P}.tar.xz - https://github.com/mgorny/gentoo-kernel-config/archive/v${GENTOO_CONFIG_VER}.tar.gz - -> gentoo-kernel-config-${GENTOO_CONFIG_VER}.tar.gz - verify-sig? ( - https://cdn.kernel.org/pub/linux/kernel/v$(ver_cut 1).x/${MY_P}.tar.sign - ) - amd64? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-x86_64.config - -> kernel-x86_64.config.${CONFIG_VER} - ) - arm64? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-aarch64.config - -> kernel-aarch64.config.${CONFIG_VER} - ) - ppc64? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-ppc64le.config - -> kernel-ppc64le.config.${CONFIG_VER} - ) - x86? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-i686.config - -> kernel-i686.config.${CONFIG_VER} - )" -S=${WORKDIR}/${MY_P} - -LICENSE="GPL-2" -KEYWORDS="~amd64 ~arm64 ~x86" -IUSE="debug" - -RDEPEND=" - !sys-kernel/vanilla-kernel-bin:${SLOT}" -BDEPEND=" - debug? ( dev-util/dwarves ) - verify-sig? ( app-crypt/openpgp-keys-kernel )" -PDEPEND=" - >=virtual/dist-kernel-${PV}" - -VERIFY_SIG_OPENPGP_KEY_PATH=${BROOT}/usr/share/openpgp-keys/kernel.org.asc - -pkg_pretend() { - ewarn "Starting with 5.4.52, Distribution Kernels are switching from Arch" - ewarn "Linux configs to Fedora. Please keep a backup kernel just in case." - - kernel-install_pkg_pretend -} - -src_unpack() { - if use verify-sig; then - einfo "Unpacking linux-${PV}.tar.xz ..." - verify-sig_verify_detached - "${DISTDIR}"/linux-${PV}.tar.sign \ - < <(xz -cd "${DISTDIR}"/linux-${PV}.tar.xz | tee >(tar -x)) - assert "Unpack failed" - unpack "gentoo-kernel-config-${GENTOO_CONFIG_VER}.tar.gz" - else - default - fi -} - -src_prepare() { - default - - # prepare the default config - case ${ARCH} in - amd64) - cp "${DISTDIR}/kernel-x86_64.config.${CONFIG_VER}" .config || die - ;; - arm64) - cp "${DISTDIR}/kernel-aarch64.config.${CONFIG_VER}" .config || die - ;; - ppc64) - cp "${DISTDIR}/kernel-ppc64le.config.${CONFIG_VER}" .config || die - ;; - x86) - cp "${DISTDIR}/kernel-i686.config.${CONFIG_VER}" .config || die - ;; - *) - die "Unsupported arch ${ARCH}" - ;; - esac - - local merge_configs=( - "${WORKDIR}/gentoo-kernel-config-${GENTOO_CONFIG_VER}"/base.config - ) - use debug || merge_configs+=( - "${WORKDIR}/gentoo-kernel-config-${GENTOO_CONFIG_VER}"/no-debug.config - ) - [[ ${ARCH} == x86 ]] && merge_configs+=( - "${WORKDIR}/gentoo-kernel-config-${GENTOO_CONFIG_VER}"/32-bit.config - ) - - kernel-build_merge_configs "${merge_configs[@]}" -} diff --git a/sys-kernel/vanilla-kernel/vanilla-kernel-5.4.96.ebuild b/sys-kernel/vanilla-kernel/vanilla-kernel-5.4.96.ebuild deleted file mode 100644 index f8ec23f5913a..000000000000 --- a/sys-kernel/vanilla-kernel/vanilla-kernel-5.4.96.ebuild +++ /dev/null @@ -1,106 +0,0 @@ -# Copyright 2020-2021 Gentoo Authors -# Distributed under the terms of the GNU General Public License v2 - -EAPI=7 - -inherit kernel-build verify-sig - -MY_P=linux-${PV} -# https://koji.fedoraproject.org/koji/packageinfo?packageID=8 -CONFIG_VER=5.4.21 -CONFIG_HASH=2809b7faa6a8cb232cd825096c146b7bdc1e08ea -GENTOO_CONFIG_VER=5.4.89 - -DESCRIPTION="Linux kernel built from vanilla upstream sources" -HOMEPAGE="https://www.kernel.org/" -SRC_URI+=" https://cdn.kernel.org/pub/linux/kernel/v$(ver_cut 1).x/${MY_P}.tar.xz - https://github.com/mgorny/gentoo-kernel-config/archive/v${GENTOO_CONFIG_VER}.tar.gz - -> gentoo-kernel-config-${GENTOO_CONFIG_VER}.tar.gz - verify-sig? ( - https://cdn.kernel.org/pub/linux/kernel/v$(ver_cut 1).x/${MY_P}.tar.sign - ) - amd64? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-x86_64.config - -> kernel-x86_64.config.${CONFIG_VER} - ) - arm64? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-aarch64.config - -> kernel-aarch64.config.${CONFIG_VER} - ) - ppc64? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-ppc64le.config - -> kernel-ppc64le.config.${CONFIG_VER} - ) - x86? ( - https://src.fedoraproject.org/rpms/kernel/raw/${CONFIG_HASH}/f/kernel-i686.config - -> kernel-i686.config.${CONFIG_VER} - )" -S=${WORKDIR}/${MY_P} - -LICENSE="GPL-2" -KEYWORDS="~amd64 ~arm64 ~x86" -IUSE="debug" - -RDEPEND=" - !sys-kernel/vanilla-kernel-bin:${SLOT}" -BDEPEND=" - debug? ( dev-util/dwarves ) - verify-sig? ( app-crypt/openpgp-keys-kernel )" -PDEPEND=" - >=virtual/dist-kernel-${PV}" - -VERIFY_SIG_OPENPGP_KEY_PATH=${BROOT}/usr/share/openpgp-keys/kernel.org.asc - -pkg_pretend() { - ewarn "Starting with 5.4.52, Distribution Kernels are switching from Arch" - ewarn "Linux configs to Fedora. Please keep a backup kernel just in case." - - kernel-install_pkg_pretend -} - -src_unpack() { - if use verify-sig; then - einfo "Unpacking linux-${PV}.tar.xz ..." - verify-sig_verify_detached - "${DISTDIR}"/linux-${PV}.tar.sign \ - < <(xz -cd "${DISTDIR}"/linux-${PV}.tar.xz | tee >(tar -x)) - assert "Unpack failed" - unpack "gentoo-kernel-config-${GENTOO_CONFIG_VER}.tar.gz" - else - default - fi -} - -src_prepare() { - default - - # prepare the default config - case ${ARCH} in - amd64) - cp "${DISTDIR}/kernel-x86_64.config.${CONFIG_VER}" .config || die - ;; - arm64) - cp "${DISTDIR}/kernel-aarch64.config.${CONFIG_VER}" .config || die - ;; - ppc64) - cp "${DISTDIR}/kernel-ppc64le.config.${CONFIG_VER}" .config || die - ;; - x86) - cp "${DISTDIR}/kernel-i686.config.${CONFIG_VER}" .config || die - ;; - *) - die "Unsupported arch ${ARCH}" - ;; - esac - - local merge_configs=( - "${WORKDIR}/gentoo-kernel-config-${GENTOO_CONFIG_VER}"/base.config - ) - use debug || merge_configs+=( - "${WORKDIR}/gentoo-kernel-config-${GENTOO_CONFIG_VER}"/no-debug.config - ) - [[ ${ARCH} == x86 ]] && merge_configs+=( - "${WORKDIR}/gentoo-kernel-config-${GENTOO_CONFIG_VER}"/32-bit.config - ) - - kernel-build_merge_configs "${merge_configs[@]}" -} diff --git a/sys-kernel/vanilla-kernel/vanilla-kernel-5.4.93.ebuild b/sys-kernel/vanilla-kernel/vanilla-kernel-5.4.99.ebuild index f8ec23f5913a..f8ec23f5913a 100644 --- a/sys-kernel/vanilla-kernel/vanilla-kernel-5.4.93.ebuild +++ b/sys-kernel/vanilla-kernel/vanilla-kernel-5.4.99.ebuild diff --git a/sys-kernel/vanilla-sources/Manifest b/sys-kernel/vanilla-sources/Manifest index 6e240ad6656d..b769221d80a2 100644 --- a/sys-kernel/vanilla-sources/Manifest +++ b/sys-kernel/vanilla-sources/Manifest @@ -3,10 +3,12 @@ DIST linux-4.19.tar.xz 103117552 BLAKE2B 1dbf16cf410867412d17568fe42bc1e90c03418 DIST linux-4.4.tar.xz 87295988 BLAKE2B f260f1858994f5d481fd078c86e51bddbc958f7c5d1586f60dced772e1b1107ecf3aae0558c3e6f39c36f7d3aa1e6cd1e5c64ec9d6f2218f47b98413da6466fb SHA512 13c8459933a8b80608e226a1398e3d1848352ace84bcfb7e6a4a33cb230bbe1ab719d4b58e067283df91ce5311be6d2d595fc8c19e2ae6ecc652499415614b3e DIST linux-4.9.tar.xz 93192404 BLAKE2B 83ae310b17d47f1f18d6d28537c31e10f3e60458c5954c4611158ca99e71cc0da2e051272eabf27d5887df4a7cb4a5dd66ff993077c11d2221e92d300a0b48d7 SHA512 bf67ff812cc3cb7e5059e82cc5db0d9a7c5637f7ed9a42e4730c715bf7047c81ed3a571225f92a33ef0b6d65f35595bc32d773356646df2627da55e9bc7f1f1a DIST linux-5.10.tar.xz 116606704 BLAKE2B b923d7b66309224f42f35f8a5fa219421b0a9362d2adacdadd8d96251f61f7230878ea297a269a7f3b3c56830f0b177e068691e1d7f88501a05653b0a13274d1 SHA512 95bc137d0cf9148da6a9d1f1a878698dc27b40f68e22c597544010a6c591ce1b256f083489d3ff45ff77753289b535135590194d88ef9f007d0ddab3d74de70e +DIST linux-5.11.tar.xz 117619104 BLAKE2B 81300c27bd5476387a83123aaeb4163c73eb61e9245806c23660cb5e6a4fa88ffc9def027031335fa0270fc4080506cd415990014364e3a98b9d2e8c58a29524 SHA512 a567ec133018bb5ec00c60281479b466c26e02137a93a9c690e83997947df02b6fd94e76e8df748f6d70ceb58a19bacc3b1467de10b7a1fad2763db32b3f1330 DIST linux-5.4.tar.xz 109441440 BLAKE2B 193bc4a3147e147d5529956164ec4912fad5d5c6fb07f909ff1056e57235834173194afc686993ccd785c1ff15804de0961b625f3008cca0e27493efc8f27b13 SHA512 9f60f77e8ab972b9438ac648bed17551c8491d6585a5e85f694b2eaa4c623fbc61eb18419b2656b6795eac5deec0edaa04547fc6723fbda52256bd7f3486898f -DIST patch-4.14.221.xz 4125144 BLAKE2B 474f8791e2b59f1524681e70300d5a9543a4b56fb7affbd02a22d67d4df2632c7aa37a73d032697b3b10291671efd96f5eaf13c4632c05801a4a7cac99a4c219 SHA512 fd332b076ac0231ea4b3806bd6cb58f0b66bd9317ae352fb6f90856e92df5cc96d2c89bc8c44001f2f34ea98b43fbbe8b8eae0abe2249fe561b8dd4a2c76bcb5 -DIST patch-4.19.175.xz 3773632 BLAKE2B c292411aba5dc44ec66b3d27c27740437d22e78c361a31b043bc943ea40853106057084e9723e82f5f7d1f07f4d1714ba4ff4d7508f5ea556ab93f2572c4a27f SHA512 cf0fd3d6d6bef17f4d03a9f0929e7038814ba2754a59f0bdb4ee9d91c559ee6a04bf5ddc46ed4c1c03a0d7d17b802a66426c01098db8a25d716ba39e6baaad20 -DIST patch-4.4.257.xz 3458668 BLAKE2B 3de9cb1b83b0a846b5c6ef1471d0e1dee1d355db2fc1383a0e9272c4b47675685f2c0dd46c08f8f4dc5d5e8e3c499f8c1e25aeb71d20af29f822a009e1cc0c2e SHA512 a27d8c8fc81026b18d8954efb1f54f6dd05244f384248711e845877bf3ba0b48c7d09946b8572f95fb6065b7d89f833b040544e41fae13ebfc7fb99622d54bb8 -DIST patch-4.9.257.xz 3854704 BLAKE2B acd4beafa60bb61de1f73d3a31f4143102d56e9918ef5ebfc1040d096e70a92353014e4978d58f2cd7b4c11d15d430700417e63f17bd7d3d5110ef1ac26d9c53 SHA512 ff50eb605da6367724999fc059627954bd79da7272ad46870a25e60876d1e6b805c79821059b4cbfb9d2251e16f65a58fc39ea2262a0caad913536049f42136a -DIST patch-5.10.15.xz 486748 BLAKE2B da5b708b6f3a1d4b20156e82d47c96d027d535464118ea20556d7bd09f3995ab02bb5d67eb1c858bae2343bb42c0fe0c45d6690b50b2b7d199f63e7b4515c9f7 SHA512 624123b4333783633d6fa417ab5fa8cbf85e56dda122487c8314b7ec37da74eb3dadded9a3d3dbda80d3c4cc734e516316f43222c85a820df1c549df8d70baad -DIST patch-5.4.97.xz 2601604 BLAKE2B a8308677364597f9e6b12ed14639fa0774cf2e28c985b6d634caec4572d9efb835fa5234f27c13aa4a74dda03934c9003f5cd8fb4c6cd86686c515548446b513 SHA512 d32b99572006ade1eeb377c99c7b1879af08a9c177870e7548bc45f10d5c1486a50f3b50fa53decad4e58d0321c30288259e8597f0baaf95ad1537f693b677f6 +DIST patch-4.14.222.xz 4135176 BLAKE2B cf01385fa64d7541262dab01d9e75d48bb233720e7fdb4d1c00d368d16e1d07641ae9f401845c69d2965bd1eb552e1c65aea013f383dbe448f1f1ca066776a5b SHA512 ed87d0c31ceda7dff71566c7692b8ae1ba8434708024432e89a6e7ade1c90d9580034ba8fa0033849a48d20c77452c827a93b82079425a442d132af58527c1f1 +DIST patch-4.19.177.xz 3786940 BLAKE2B 2bea68978459d98cca861e33de58103d3060be5f7641c4d2d5f35868c9d395d2fbe6b76a855b01dffd2e5a812a9db11762287a55478a5c55e7bb4e5564bfd43f SHA512 e3de5d3e9547b223212a6eb38d57f69ff815fd50002544783208fb8cec9b32d716e60c2cf010f2e90672aa9f9dfd2391bcd5364de7b7c5371b8520dc5c1b2b23 +DIST patch-4.4.258.xz 3466684 BLAKE2B 0416e17a0d9233808ea244132b3ebcfcaba2eafe60070791ee5baf770595c34fea3a1e586dcba878a99522782991e3c5c6dfc3d037722f38e26470fe9fd6ec95 SHA512 61f49862b5a906c4ca67d5aeaa3cc7e86cac8d10a4f984d5ebbb0b3514a230e74ce2fcb8a384acdff7909e1757ca2422c6546a259d366c15c6ca843d23721bc7 +DIST patch-4.9.258.xz 3866012 BLAKE2B 5a17dbfc120698feb2300d6cb06f487c1594a63c76d396e662119ca5f33fd0e6a02b2c9134d223831c19ea0dc5ee20f09c4e113e43c4918bbc31833e1f81f01d SHA512 46bb41de8cee0e037890a68e995500029b6c53f78294265bdaf56290551977af1cf85d673b19c068d1c9b04a3859e241a74ead808965bef2b7998da8d3e0a89b +DIST patch-5.10.19.xz 535612 BLAKE2B f64a1988f9daec87ad09aeb5df2ddd5ddfa0ab80b0be14e3f1085e54ac1183dc311fcfe202bce1aea9669121e2b4d92400c6ca5d684ce0e5da22b4170a2342ad SHA512 9637f8dac379ffa6d376afcce8da87250eb48a6a2ffac0e5732884cca2cc2f0a85811fc326f006d2d297680ff7dcf726665360d9c7d5d34307bc3e7169ce6a7a +DIST patch-5.11.2.xz 8160 BLAKE2B 15c4ccf0a72bc3cf274d88d0e3e1dce45181de55a8464a2d9611e81f85638316c3b4b47202f5344897ea7e1ebd0ac5688c372ca04b625b8500724082eef65307 SHA512 32a89fc1b755249c30a263193d638983c83808a7481380567ff08a0b84df01465501f4c664b8dd5b6f1cb2525a089a0a6f5cf2fb994ee5e250210aa9cda57ced +DIST patch-5.4.101.xz 2624564 BLAKE2B 840449f0d0e00b09b91c558f8fa384ad7fd6c3c1f0e7f57289586b98c6daa32fc9154469c7a2773e815fd2da6b3be93d8f4fffcecf08ebb0a728f0fd638dbfec SHA512 20b573c539c970c39eb63f3b97331e696436ceb19bf23649e84d6e936cb29bc459613aab0a4e7a78e29809764b34bbfd14869a19add0bfc5b0a1d6e47dec7f97 diff --git a/sys-kernel/vanilla-sources/metadata.xml b/sys-kernel/vanilla-sources/metadata.xml index 01c0b537dc0d..f14a76b87698 100644 --- a/sys-kernel/vanilla-sources/metadata.xml +++ b/sys-kernel/vanilla-sources/metadata.xml @@ -1,16 +1,17 @@ <?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE pkgmetadata SYSTEM "http://www.gentoo.org/dtd/metadata.dtd"> +<!DOCTYPE pkgmetadata SYSTEM "https://liguros.gitlab.io/dtd/metadata.dtd"> <pkgmetadata> - <maintainer type="project"> - <email>kernel@gentoo.org</email> - <name>Gentoo kernel team</name> - </maintainer> - <maintainer type="person"> - <email>ago@gentoo.org</email> - <name>Agostino Sarubbo</name> - <description>CC/Assign to me the version bump request</description> - </maintainer> - <upstream> - <remote-id type="cpe">cpe:/o:linux:linux_kernel</remote-id> - </upstream> -</pkgmetadata> + <maintainer type="project"> + <email>kernel@gentoo.org</email> + <name>Gentoo kernel team</name> + </maintainer> + <maintainer type="person"> + <email>ago@gentoo.org</email> + <name>Agostino Sarubbo</name> + <description>CC/Assign to me the version bump request</description> + </maintainer> + <upstream> + <remote-id type="cpe">cpe:/o:linux:linux_kernel</remote-id> + </upstream> + <origin>gentoo-staging</origin> +</pkgmetadata>
\ No newline at end of file diff --git a/sys-kernel/vanilla-sources/vanilla-sources-4.14.221.ebuild b/sys-kernel/vanilla-sources/vanilla-sources-4.14.222.ebuild index 7083facc514b..7083facc514b 100644 --- a/sys-kernel/vanilla-sources/vanilla-sources-4.14.221.ebuild +++ b/sys-kernel/vanilla-sources/vanilla-sources-4.14.222.ebuild diff --git a/sys-kernel/vanilla-sources/vanilla-sources-4.19.175.ebuild b/sys-kernel/vanilla-sources/vanilla-sources-4.19.177.ebuild index 7083facc514b..7083facc514b 100644 --- a/sys-kernel/vanilla-sources/vanilla-sources-4.19.175.ebuild +++ b/sys-kernel/vanilla-sources/vanilla-sources-4.19.177.ebuild diff --git a/sys-kernel/vanilla-sources/vanilla-sources-4.4.257.ebuild b/sys-kernel/vanilla-sources/vanilla-sources-4.4.258.ebuild index 7083facc514b..7083facc514b 100644 --- a/sys-kernel/vanilla-sources/vanilla-sources-4.4.257.ebuild +++ b/sys-kernel/vanilla-sources/vanilla-sources-4.4.258.ebuild diff --git a/sys-kernel/vanilla-sources/vanilla-sources-4.9.257.ebuild b/sys-kernel/vanilla-sources/vanilla-sources-4.9.258.ebuild index 7083facc514b..7083facc514b 100644 --- a/sys-kernel/vanilla-sources/vanilla-sources-4.9.257.ebuild +++ b/sys-kernel/vanilla-sources/vanilla-sources-4.9.258.ebuild diff --git a/sys-kernel/vanilla-sources/vanilla-sources-5.10.15.ebuild b/sys-kernel/vanilla-sources/vanilla-sources-5.10.19.ebuild index 7083facc514b..7083facc514b 100644 --- a/sys-kernel/vanilla-sources/vanilla-sources-5.10.15.ebuild +++ b/sys-kernel/vanilla-sources/vanilla-sources-5.10.19.ebuild diff --git a/sys-kernel/vanilla-sources/vanilla-sources-5.4.97.ebuild b/sys-kernel/vanilla-sources/vanilla-sources-5.11.2.ebuild index 7083facc514b..7083facc514b 100644 --- a/sys-kernel/vanilla-sources/vanilla-sources-5.4.97.ebuild +++ b/sys-kernel/vanilla-sources/vanilla-sources-5.11.2.ebuild diff --git a/sys-kernel/vanilla-sources/vanilla-sources-5.4.101.ebuild b/sys-kernel/vanilla-sources/vanilla-sources-5.4.101.ebuild new file mode 100644 index 000000000000..7083facc514b --- /dev/null +++ b/sys-kernel/vanilla-sources/vanilla-sources-5.4.101.ebuild @@ -0,0 +1,16 @@ +# Copyright 1999-2021 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +EAPI="6" +K_NOUSENAME="yes" +K_NOSETEXTRAVERSION="yes" +K_SECURITY_UNSUPPORTED="1" +ETYPE="sources" +inherit kernel-2 +detect_version + +DESCRIPTION="Full sources for the Linux kernel" +HOMEPAGE="https://www.kernel.org" +SRC_URI="${KERNEL_URI}" + +KEYWORDS="~alpha ~amd64 ~arm ~arm64 ~hppa ~ia64 ~mips ~ppc ~ppc64 ~s390 ~sparc ~x86" diff --git a/sys-kernel/zen-sources/Manifest b/sys-kernel/zen-sources/Manifest index a99496add2bf..89f8fd35cd62 100644 --- a/sys-kernel/zen-sources/Manifest +++ b/sys-kernel/zen-sources/Manifest @@ -1,5 +1,8 @@ DIST genpatches-5.10-1.base.tar.xz 3840 BLAKE2B 08ac1f83dc9a1cfc1d4cf0a3a5ab4c9d4686a80348247ec7cd1da6e49db92d6932a1864113f2631d5528a4ba732945b2afe73d03061bd3c532b3d1e4d9571999 SHA512 04356093c4df6a7ee0876b89be5b90f8bc90c920628e5fe69b5787ce82e003be05eaac142310f10f32d0549a6676af846734ae4ac188c2b96c2eca2cb0a6f4b0 DIST genpatches-5.10-1.extras.tar.xz 1768 BLAKE2B e99d5d2137d5752845ba8284a0dd57620851c3620603e871973af5841b54e9bfdde92ea2408ddedb55355f2c954c80641b06098060043916d2483e10cfb8293a SHA512 0034e5ab57cccb2e969a3b9e1f674614ca853779c552c37be9c5afb0a37112bf8f2c30e1b21832d56320c70c1d622081b60369c6a86fa737a23c3ed953267453 +DIST genpatches-5.11-1.base.tar.xz 3440 BLAKE2B eb1e9a9f2060023cb410bf3db8c4f4fe283eff47f545a434dfc1edb98aa513940f30a2a88566422192b79f7ab36c607b9bc63253c067070d9a479d6318fd34b3 SHA512 a862fe33272bb6b0e4095c862c74361f015fc57316b9dbbdf2782f2e57c131fbe7fe9b9ba81c3d5a7d71788f2d56abdbd28f1c7571973c3f378cd05199c0421f +DIST genpatches-5.11-1.extras.tar.xz 1772 BLAKE2B e6f8eae67db54099424f33e17bbfa66d36ae44c98d5f58969634a709a4b949a675a7ec1053eab4db4f745513d9730b68439ecf888e92f0fc9ef369822b39a388 SHA512 cf9d0ee27618b1b49322cefda8d85f66fd94820b9902948c8dd9a33d4e14acf511e7aabf611df5e070a4011e06d80164a512d124f5686b5b16fd81409098d8eb DIST linux-5.10.tar.xz 116606704 BLAKE2B b923d7b66309224f42f35f8a5fa219421b0a9362d2adacdadd8d96251f61f7230878ea297a269a7f3b3c56830f0b177e068691e1d7f88501a05653b0a13274d1 SHA512 95bc137d0cf9148da6a9d1f1a878698dc27b40f68e22c597544010a6c591ce1b256f083489d3ff45ff77753289b535135590194d88ef9f007d0ddab3d74de70e -DIST v5.10.10-zen1.patch.xz 538040 BLAKE2B 2c0ceaebd78107adf1f062a866a6ecb7cc7defcf7eb00ac9287974a6417da2431100c5bc3b23ee4ad47a2478c31c5843de32b73b64ab7928c8df019aec2fb77f SHA512 ee719511e43fa0c799a8b342254125f10cf88fd32999d63d8eb904e76b45d53af22722dd14fd3c36556713a39569266d69551278939b752580360c52ea6a3750 -DIST v5.10.6-zen1.patch.xz 387460 BLAKE2B 0e42109335d0c8d7344b8afc3addbe20c92952eea536df4db0152607dcc97d7de142124f9cb0c22c52af01bd6c117cdc69c51f36725c0f2ab2d51165a2390a28 SHA512 3ba03f703521083e629911ebf980545daa34d73aba30aed8e7355eb315d89728f322df0a3791663fa5fbe398bbd1d10951518d81126e077cf50c9fa1d34563dd +DIST linux-5.11.tar.xz 117619104 BLAKE2B 81300c27bd5476387a83123aaeb4163c73eb61e9245806c23660cb5e6a4fa88ffc9def027031335fa0270fc4080506cd415990014364e3a98b9d2e8c58a29524 SHA512 a567ec133018bb5ec00c60281479b466c26e02137a93a9c690e83997947df02b6fd94e76e8df748f6d70ceb58a19bacc3b1467de10b7a1fad2763db32b3f1330 +DIST v5.10.16-zen1.patch.xz 702476 BLAKE2B 3aff93587e1607cfe241f81ba9f2cd00f8bdbf1f42850040afe8ed3c7b95fd5d578256f9e41f1921d105399dc88b575472b66d6434b55bb44e7f987c09742417 SHA512 6dde0849fdb9181d62fe547eb1bfd48d2577c0c795ab22c7a298a441f7da8d8e948ca081ec9a080a19222e4ae6a0a461a19109632ea96a9c224481b776652e20 +DIST v5.11-zen2.patch.xz 88440 BLAKE2B efe9997086c9af9e752113873b91caa1a1fedc826b2e7c09ffc00e153a708ad6d3db0c2e4a3f407d43162f90d1773cc4a2d98373bd8506d2450603c8777e1bb5 SHA512 4671fec5857696caec8f7dd1f65b01db1a69b27cbf87e807ef57e6c5473497ca8327f35c3a53312d2443c43448755656664b6fe6af1324974135206899ec81ce diff --git a/sys-kernel/zen-sources/metadata.xml b/sys-kernel/zen-sources/metadata.xml index 3c75f3aa2ec0..e7df5e32c912 100644 --- a/sys-kernel/zen-sources/metadata.xml +++ b/sys-kernel/zen-sources/metadata.xml @@ -1,12 +1,13 @@ <?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE pkgmetadata SYSTEM "http://www.gentoo.org/dtd/metadata.dtd"> +<!DOCTYPE pkgmetadata SYSTEM "https://liguros.gitlab.io/dtd/metadata.dtd"> <pkgmetadata> - <maintainer type="person"> - <email>anarchy@gentoo.org</email> - <name>Jory A. Pratt</name> - </maintainer> -<upstream> - <remote-id type="cpe">cpe:/o:linux:linux_kernel</remote-id> - <remote-id type="github">zen-kernel/zen-kernel</remote-id> -</upstream> -</pkgmetadata> + <maintainer type="person"> + <email>anarchy@gentoo.org</email> + <name>Jory A. Pratt</name> + </maintainer> + <upstream> + <remote-id type="cpe">cpe:/o:linux:linux_kernel</remote-id> + <remote-id type="github">zen-kernel/zen-kernel</remote-id> + </upstream> + <origin>gentoo-staging</origin> +</pkgmetadata>
\ No newline at end of file diff --git a/sys-kernel/zen-sources/zen-sources-5.10.10.ebuild b/sys-kernel/zen-sources/zen-sources-5.10.16.ebuild index ef149d6a6a93..ef149d6a6a93 100644 --- a/sys-kernel/zen-sources/zen-sources-5.10.10.ebuild +++ b/sys-kernel/zen-sources/zen-sources-5.10.16.ebuild diff --git a/sys-kernel/zen-sources/zen-sources-5.10.6.ebuild b/sys-kernel/zen-sources/zen-sources-5.11.ebuild index ef149d6a6a93..d8686b02d3fa 100644 --- a/sys-kernel/zen-sources/zen-sources-5.10.6.ebuild +++ b/sys-kernel/zen-sources/zen-sources-5.11.ebuild @@ -18,10 +18,10 @@ IUSE="" DESCRIPTION="The Zen Kernel Live Sources" -ZEN_URI="https://github.com/zen-kernel/zen-kernel/releases/download/v${PV}-zen1/v${PV}-zen1.patch.xz" +ZEN_URI="https://github.com/zen-kernel/zen-kernel/releases/download/v${PV}-zen2/v${PV}-zen2.patch.xz" SRC_URI="${KERNEL_URI} ${GENPATCHES_URI} ${ARCH_URI} ${ZEN_URI}" -UNIPATCH_LIST="${DISTDIR}/v${PV}-zen1.patch.xz" +UNIPATCH_LIST="${DISTDIR}/v${PV}-zen2.patch.xz" UNIPATCH_STRICTORDER="yes" K_EXTRAEINFO="For more info on zen-sources, and for how to report problems, see: \ |
